Skip to content

File cas_common_execute.c

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

/*
 * cas_common_execute.c - Shared execution functions used by both cas_execute.c and cas_cgw_execute.c
 */

#ident "$Id$"

#include "cas_common_execute.h"
#include "cas_net_buf.h"
#include "cas_util.h"
#include "perf_monitor.h"
#include "release_string.h"
#include "dbi.h"
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>


/* Shared cas_u_type array for CAS and CGW */
static char cas_u_type[] = { 0, /* 0 */
  CCI_U_TYPE_INT,       /* 1 */
  CCI_U_TYPE_FLOAT,     /* 2 */
  CCI_U_TYPE_DOUBLE,        /* 3 */
  CCI_U_TYPE_STRING,        /* 4 */
  CCI_U_TYPE_OBJECT,        /* 5 */
  CCI_U_TYPE_SET,       /* 6 */
  CCI_U_TYPE_MULTISET,      /* 7 */
  CCI_U_TYPE_SEQUENCE,      /* 8 */
  0,                /* 9 */
  CCI_U_TYPE_TIME,      /* 10 */
  CCI_U_TYPE_TIMESTAMP,     /* 11 */
  CCI_U_TYPE_DATE,      /* 12 */
  CCI_U_TYPE_MONETARY,      /* 13 */
  0, 0, 0, 0,           /* 14 - 17 */
  CCI_U_TYPE_SHORT,     /* 18 */
  0, 0, 0,          /* 19 - 21 */
  CCI_U_TYPE_NUMERIC,       /* 22 */
  CCI_U_TYPE_BIT,       /* 23 */
  CCI_U_TYPE_VARBIT,        /* 24 */
  CCI_U_TYPE_CHAR,      /* 25 */
  CCI_U_TYPE_NCHAR_DEPRECATED,  /* 26 */
  CCI_U_TYPE_VARNCHAR_DEPRECATED,   /* 27 */
  CCI_U_TYPE_RESULTSET,     /* 28 */
  0, 0,             /* 29 - 30 */
  CCI_U_TYPE_BIGINT,        /* 31 */
  CCI_U_TYPE_DATETIME,      /* 32 */
  CCI_U_TYPE_BLOB,      /* 33 */
  CCI_U_TYPE_CLOB,      /* 34 */
  CCI_U_TYPE_ENUM,      /* 35 */
  CCI_U_TYPE_TIMESTAMPTZ,   /* 36 */
  CCI_U_TYPE_TIMESTAMPLTZ,  /* 37 */
  CCI_U_TYPE_DATETIMETZ,    /* 38 */
  CCI_U_TYPE_DATETIMELTZ,   /* 39 */
  CCI_U_TYPE_JSON,      /* 40 */
};

static CAS_ERROR_LOG_HANDLE_CONTEXT *cas_EHCTX = NULL;

char
ux_db_type_to_cas_type (int db_type)
{
  /* todo: T_CCI_U_TYPE duplicates db types. */
  if (db_type < DB_TYPE_FIRST || db_type > DB_TYPE_LAST)
    {
      return CCI_U_TYPE_NULL;
    }

  return (cas_u_type[db_type]);
}

void
ux_set_utype_for_enum (char u_type)
{
  cas_u_type[DB_TYPE_ENUMERATION] = u_type;
}

void
ux_set_utype_for_timestamptz (char u_type)
{
  cas_u_type[DB_TYPE_TIMESTAMPTZ] = u_type;
}

void
ux_set_utype_for_datetimetz (char u_type)
{
  cas_u_type[DB_TYPE_DATETIMETZ] = u_type;
}

void
ux_set_utype_for_timestampltz (char u_type)
{
  cas_u_type[DB_TYPE_TIMESTAMPLTZ] = u_type;
}

void
ux_set_utype_for_datetimeltz (char u_type)
{
  cas_u_type[DB_TYPE_DATETIMELTZ] = u_type;
}

void
ux_set_utype_for_json (char u_type)
{
  cas_u_type[DB_TYPE_JSON] = u_type;
}

/* ========================================================================
 * SQL statement parsing functions
 * ======================================================================== */

char
get_stmt_type (char *stmt)
{
  if (strncasecmp (stmt, "insert", 6) == 0)
    {
      return CUBRID_STMT_INSERT;
    }
  else if (strncasecmp (stmt, "update", 6) == 0)
    {
      return CUBRID_STMT_UPDATE;
    }
  else if (strncasecmp (stmt, "delete", 6) == 0)
    {
      return CUBRID_STMT_DELETE;
    }
  else if (strncasecmp (stmt, "call", 4) == 0)
    {
      return CUBRID_STMT_CALL;
    }
  else if (strncasecmp (stmt, "evaluate", 8) == 0)
    {
      return CUBRID_STMT_EVALUATE;
    }
  else if (strncasecmp (stmt, "select", 6) == 0)
    {
      return CUBRID_STMT_SELECT;
    }
  else if (strncasecmp (stmt, "merge", 5) == 0)
    {
      return CUBRID_STMT_MERGE;
    }
  else
    {
      return CUBRID_MAX_STMT_TYPE;
    }
}

/* ========================================================================
 * Common execution functions
 * ======================================================================== */

int
ux_get_db_version (T_NET_BUF * net_buf, T_REQ_INFO * req_info)
{
  char *p;

  p = (char *) rel_build_number ();

  net_buf_cp_int (net_buf, 0, NULL);    /* result code */
  if (p == NULL)
    {
      net_buf_cp_byte (net_buf, '\0');
    }
  else
    {
      net_buf_cp_str (net_buf, p, strlen (p) + 1);
    }

  return 0;
}

char *
consume_tokens (char *stmt, STATEMENT_STATUS stmt_status)
{
  char *p = stmt;

  if (stmt_status == SQL_STYLE_COMMENT || stmt_status == CPP_STYLE_COMMENT)
    {
      for (; *p; p++)
    {
      if (*p == '\n')
        {
          break;
        }
    }
    }
  else if (stmt_status == C_STYLE_COMMENT)
    {
      for (; *p; p++)
    {
      if (*p == '*' && *(p + 1) == '/')
        {
          p++;
          break;
        }
    }
    }
  else if (stmt_status == SINGLE_QUOTED_STRING)
    {
      for (; *p; p++)
    {
      if (*p == '\'' && *(p + 1) == '\'')
        {
          p++;
        }
      else if (cas_default_no_backslash_escapes == false && *p == '\\')
        {
          p++;
        }
      else if (*p == '\'')
        {
          break;
        }
    }
    }
  else if (stmt_status == DOUBLE_QUOTED_STRING)
    {
      for (; *p; p++)
    {
      if (*p == '\"' && *(p + 1) == '\"')
        {
          p++;
        }
      else if (cas_default_no_backslash_escapes == false && *p == '\\')
        {
          p++;
        }
      else if (*p == '\"')
        {
          break;
        }
    }
    }

  return p;
}

int
get_num_markers (char *stmt)
{
  char *p;
  int num_markers = 0;

  for (p = stmt; *p; p++)
    {
      if (*p == '?')
    {
      num_markers++;
    }
      else if (*p == '-' && *(p + 1) == '-')
    {
      p = consume_tokens (p + 2, SQL_STYLE_COMMENT);
    }
      else if (*p == '/' && *(p + 1) == '*')
    {
      p = consume_tokens (p + 2, C_STYLE_COMMENT);
    }
      else if (*p == '/' && *(p + 1) == '/')
    {
      p = consume_tokens (p + 2, CPP_STYLE_COMMENT);
    }
      else if (*p == '\'')
    {
      p = consume_tokens (p + 1, SINGLE_QUOTED_STRING);
    }
      else if (cas_default_ansi_quotes == false && *p == '\"')
    {
      p = consume_tokens (p + 1, DOUBLE_QUOTED_STRING);
    }

      if (*p == '\0')
    {
      break;
    }
    }

  return num_markers;
}

void
ux_end_tran_cleanup (int tran_type)
{
  if (!as_info->cur_statement_pooling)
    {
      if (tran_type == CCI_TRAN_COMMIT)
    {
      hm_srv_handle_free_all (false);
    }
      else
    {
      hm_srv_handle_free_all (true);
    }
    }
  else
    {
      if (tran_type == CCI_TRAN_COMMIT)
    {
      /* do not close holdable results on commit */
      hm_srv_handle_qresult_end_all (false);
    }
      else
    {
      /* clear all queries */
      hm_srv_handle_qresult_end_all (true);
    }
    }
}

void
update_query_execution_count (T_APPL_SERVER_INFO * as_info_p, char stmt_type)
{
  assert (as_info_p != NULL);

  as_info_p->num_queries_processed %= MAX_DIAG_DATA_VALUE;
  as_info_p->num_queries_processed++;

  switch (stmt_type)
    {
    case CUBRID_STMT_SELECT:
      as_info_p->num_select_queries %= MAX_DIAG_DATA_VALUE;
      as_info_p->num_select_queries++;
      break;
    case CUBRID_STMT_INSERT:
      as_info_p->num_insert_queries %= MAX_DIAG_DATA_VALUE;
      as_info_p->num_insert_queries++;
      break;
    case CUBRID_STMT_UPDATE:
      as_info_p->num_update_queries %= MAX_DIAG_DATA_VALUE;
      as_info_p->num_update_queries++;
      break;
    case CUBRID_STMT_DELETE:
      as_info_p->num_delete_queries %= MAX_DIAG_DATA_VALUE;
      as_info_p->num_delete_queries++;
      break;
    default:
      break;
    }
}

void
update_error_query_count (T_APPL_SERVER_INFO * as_info_p, const T_ERROR_INFO * err_info_p)
{
  assert (as_info_p != NULL);
  assert (err_info_p != NULL);

  if (err_info_p->err_number != ER_QPROC_INVALID_XASLNODE)
    {
      as_info_p->num_error_queries %= MAX_DIAG_DATA_VALUE;
      as_info_p->num_error_queries++;
    }

  if (err_info_p->err_indicator == DBMS_ERROR_INDICATOR)
    {
      if (err_info_p->err_number == ER_BTREE_UNIQUE_FAILED || err_info_p->err_number == ER_UNIQUE_VIOLATION_WITHKEY)
    {
      as_info_p->num_unique_error_queries %= MAX_DIAG_DATA_VALUE;
      as_info_p->num_unique_error_queries++;
    }
    }
}

bool
check_auto_commit_after_getting_result (T_SRV_HANDLE * srv_handle)
{
  // To close an updatable cursor is dangerous since it lose locks and updating cursor is allowed before closing it.

  if (srv_handle->auto_commit_mode == TRUE && srv_handle->cur_result_index == srv_handle->num_q_result
      && srv_handle->forward_only_cursor == TRUE && srv_handle->is_updatable == FALSE)
    {
      return true;
    }

  return false;
}

void
prepare_column_info_set (T_NET_BUF * net_buf, char ut, short scale, int prec, char charset, const char *col_name,
             const char *default_value, char auto_increment, char unique_key, char primary_key,
             char reverse_index, char reverse_unique, char foreign_key, char shared, const char *attr_name,
             const char *class_name, char is_non_null, T_BROKER_VERSION client_version)
{
  const char *attr_name_p, *class_name_p;
  int attr_name_len, class_name_len;

  net_buf_column_info_set (net_buf, ut, scale, prec, charset, col_name);

  attr_name_p = (attr_name != NULL) ? attr_name : "";
  attr_name_len = strlen (attr_name_p);

  class_name_p = (class_name != NULL) ? class_name : "";
  class_name_len = strlen (class_name_p);

  net_buf_cp_int (net_buf, attr_name_len + 1, NULL);
  net_buf_cp_str (net_buf, attr_name_p, attr_name_len + 1);

  net_buf_cp_int (net_buf, class_name_len + 1, NULL);
  net_buf_cp_str (net_buf, class_name_p, class_name_len + 1);

  if (is_non_null >= 1)
    {
      is_non_null = 1;
    }
  else if (is_non_null < 0)
    {
      is_non_null = 0;
    }

  net_buf_cp_byte (net_buf, is_non_null);

  if (client_version < CAS_MAKE_VER (8, 3, 0))
    {
      return;
    }

  if (default_value == NULL)
    {
      net_buf_cp_int (net_buf, 1, NULL);
      net_buf_cp_byte (net_buf, '\0');
    }
  else
    {
      int len = strlen (default_value) + 1;

      net_buf_cp_int (net_buf, len, NULL);
      net_buf_cp_str (net_buf, default_value, len);
    }

  net_buf_cp_byte (net_buf, auto_increment);
  net_buf_cp_byte (net_buf, unique_key);
  net_buf_cp_byte (net_buf, primary_key);
  net_buf_cp_byte (net_buf, reverse_index);
  net_buf_cp_byte (net_buf, reverse_unique);
  net_buf_cp_byte (net_buf, foreign_key);
  net_buf_cp_byte (net_buf, shared);
}

bool
has_stmt_result_set (char stmt_type)
{
  switch (stmt_type)
    {
    case CUBRID_STMT_SELECT:
    case CUBRID_STMT_CALL:
    case CUBRID_STMT_GET_STATS:
    case CUBRID_STMT_EVALUATE:
      return true;

    default:
      break;
    }

  return false;
}

/* ========================================================================
 * Error log handler functions for execution
 * ======================================================================== */

char *
cas_log_error_handler_asprint (char *buf, size_t bufsz, bool clear)
{
  char *buf_p;
  unsigned int from, to;

  if (buf == NULL || bufsz <= 0)
    {
      return NULL;
    }

  if (cas_EHCTX == NULL || cas_EHCTX->from == 0)
    {
      buf[0] = '\0';
      return buf;
    }

  from = cas_EHCTX->from;
  to = cas_EHCTX->to;

  if (clear)
    {
      cas_EHCTX->from = 0;
      cas_EHCTX->to = 0;
    }

  /* ", EID = <int> ~ <int>" : 32 bytes suffice */
  if (bufsz < 32)
    {
      buf_p = (char *) malloc (32);

      if (buf_p == NULL)
    {
      return NULL;
    }
    }
  else
    {
      buf_p = buf;
    }

  /* actual print */
  if (to != 0)
    {
      snprintf (buf_p, 32, ", EID = %u ~ %u", from, to);
    }
  else
    {
      snprintf (buf_p, 32, ", EID = %u", from);
    }

  return buf_p;
}

/*****************************
  move from cas_log.c
 *****************************/
void
cas_log_error_handler (unsigned int eid)
{
  if (cas_EHCTX == NULL)
    {
      return;
    }

  if (cas_EHCTX->from == 0)
    {
      cas_EHCTX->from = eid;
    }
  else
    {
      cas_EHCTX->to = eid;
    }
}

/*
 * get_error_log_eids - get error identifier string
 *    return: pointer to internal buffer
 * NOTE:
 * this function is not MT safe. Returned address is guaranteed to be valid
 * until next get_error_log_eids() call.
 */
char *
get_error_log_eids (int err)
{
  static char *pending_alloc = NULL;
  static char buffer[512];
  char *buf;

  if (err >= 0)
    {
      return (char *) "";
    }

  if (pending_alloc != NULL)
    {
      free (pending_alloc);
      pending_alloc = NULL;
    }

  buf = cas_log_error_handler_asprint (buffer, sizeof (buffer), true);
  if (buf != buffer)
    {
      pending_alloc = buf;
    }

  return buf;
}

void
cas_log_error_handler_begin (void)
{
  CAS_ERROR_LOG_HANDLE_CONTEXT *ectx;

  ectx = (CAS_ERROR_LOG_HANDLE_CONTEXT *) malloc (sizeof (*ectx));
  if (ectx == NULL)
    {
      return;
    }

  ectx->from = 0;
  ectx->to = 0;

  if (cas_EHCTX != NULL)
    {
      free (cas_EHCTX);
    }

  cas_EHCTX = ectx;
  (void) db_register_error_log_handler (cas_log_error_handler);
}

void
cas_log_error_handler_end (void)
{
  if (cas_EHCTX != NULL)
    {
      free (cas_EHCTX);
      cas_EHCTX = NULL;
      (void) db_register_error_log_handler (NULL);
    }
}

void
cas_log_error_handler_clear (void)
{
  if (cas_EHCTX == NULL)
    {
      return;
    }

  cas_EHCTX->from = 0;
  cas_EHCTX->to = 0;
}