Skip to content

File method_query_handler.cpp

File List > cubrid > src > method > method_query_handler.cpp

Go to the documentation of this file

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

#include "method_query_handler.hpp"

#include "parser.h"
#include "db_session.h"
#include "authenticate.h"
#include "db.h"
#include "dbi.h"
#include "dbtype.h"
#include "method_query_util.hpp"
#include "method_schema_info.hpp"
#include "object_primitive.h"
#include "optimizer.h" /* qo_get_optimization_param, qo_set_optimization_param */

/* from jsp_cl.c */
extern void jsp_set_prepare_call ();
extern void jsp_unset_prepare_call ();

namespace cubmethod
{
  query_handler::query_handler (error_context &ctx, int id)
    : m_id (id)
    , m_tid (NULL_TRANID)
    , m_user ("")
    , m_error_ctx (ctx)
    , m_sql_stmt ()
    , m_stmt_type (CUBRID_STMT_NONE)
    , m_prepare_flag (0x00)
    , m_session (nullptr)
    , m_is_prepared (false)
    , m_use_plan_cache (false)
    , m_num_markers (-1)
    , m_max_col_size (-1)
    , m_has_result_set (false)
    , m_is_occupied (false)
    , m_query_id (-1)
    , m_prepare_info ()
    , m_execute_info ()
    , m_prepare_call_info ()
    , m_query_result ()
  {
    //
  }

  query_handler::~query_handler ()
  {
    end_qresult ();
    close_and_free_session ();
  }

  /* called after 1 iteration on method scan */
  void query_handler::reset ()
  {
    end_qresult ();
    m_is_occupied = false;
  }

  query_result::query_result ()
  {
    column_info = nullptr;
    result = nullptr;

    stmt_id = 0;
    stmt_type = 0;
    num_column = 0;
    tuple_count = 0;
    copied = false;
    include_oid = false;
  }

  int
  query_handler::get_id () const
  {
    return m_id;
  }

  std::string
  query_handler::get_user_name () const
  {
    return m_user;
  }

  std::string
  query_handler::get_sql_stmt () const
  {
    return m_sql_stmt;
  }

  int
  query_handler::get_statement_type () const
  {
    return m_stmt_type;
  }

  uint64_t
  query_handler::get_query_id () const
  {
    return m_query_id;
  }

  int
  query_handler::get_num_markers ()
  {
    const std::string &sql = m_sql_stmt;
    if (m_num_markers == -1 && !sql.empty ())
      {
    m_num_markers = calculate_num_markers (sql);
      }
    return m_num_markers;
  }

  bool query_handler::is_prepared () const
  {
    return m_is_prepared;
  }

  bool query_handler::get_is_occupied ()
  {
    return m_is_occupied;
  }

  void query_handler::set_is_occupied (bool flag)
  {
    m_is_occupied = flag;
  }

  TRANID
  query_handler::get_tran_id ()
  {
    return m_tid;
  }

  void
  query_handler::set_tran_id (TRANID tid)
  {
    m_tid = tid;
  }

  prepare_info &
  query_handler::get_prepare_info ()
  {
    return m_prepare_info;
  }

  execute_info &
  query_handler::get_execute_info ()
  {
    return m_execute_info;
  }

  DB_SESSION *
  query_handler::get_db_session ()
  {
    return m_session;
  }

  DB_QUERY_TYPE *
  query_handler::get_column_info ()
  {
    if (m_session)
      {
    return db_get_query_type_list (m_session, m_query_result.stmt_id);
      }
    return nullptr;
  }

  const query_result &
  query_handler::get_result ()
  {
    return m_query_result;
  }

  int
  query_handler::prepare (std::string sql, int flag)
  {
    m_sql_stmt.assign (sql);
    m_prepare_flag = flag;

    int error = NO_ERROR;
    if (m_prepare_flag & PREPARE_CALL)
      {
    error = prepare_call ();
      }
    else
      {
    error = prepare_query ();
      }

    if (error == NO_ERROR)
      {
    m_user = au_get_current_user_name ();
    m_prepare_info.handle_id = get_id ();
    m_prepare_info.stmt_type = m_query_result.stmt_type;
    m_prepare_info.num_markers = get_num_markers ();
    set_prepare_column_list_info (m_prepare_info.column_infos);

    m_is_occupied = true;
      }
    else
      {
    // error handling
    close_and_free_session ();
      }

    return error;
  }

  int
  query_handler::prepare_retry ()
  {
    if (is_prepared ())
      {
    return prepare (m_sql_stmt, m_prepare_flag);
      }
    return ER_FAILED;
  }

  int
  query_handler::prepare_compile (const std::string &sql)
  {
    int level;
    qo_get_optimization_param (&level, QO_PARAM_LEVEL);
    qo_set_optimization_param (NULL, QO_PARAM_LEVEL, 2);

    int error = prepare (sql, PREPARE_STATIC_SQL);

    // restore
    qo_set_optimization_param (NULL, QO_PARAM_LEVEL, level);

    return error;
  }

  int
  query_handler::execute (const execute_request &request)
  {
    int error = NO_ERROR;

    int flag = request.execute_flag;
    int max_col_size = request.max_field;
    const std::vector<DB_VALUE> &bind_values = request.param_values;
    int max_row = -1; // TODO

    // 0) clear qresult
    end_qresult ();

    if (m_prepare_flag & PREPARE_CALL)
      {
    error = execute_internal_call (flag, max_col_size, max_row, bind_values, request.param_modes);
      }
    else
      {
    error = execute_internal (flag, max_col_size, max_row, bind_values);
      }

    if (error == NO_ERROR)
      {
    /* set max_col_size */
    m_max_col_size = max_col_size;
    m_execute_info.handle_id = get_id ();
    m_query_id = m_execute_info.qresult_info.query_id;

    /* include column info? */
    if (db_check_single_query (m_session) != NO_ERROR) /* ER_IT_MULTIPLE_STATEMENT */
      {
        er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_MULTIPLE_STATEMENT, 0);
        m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
        return ER_FAILED;
      }
      }
    else
      {
    if (m_prepare_flag & PREPARE_XASL_CACHE_PINNED)
      {
        db_session_set_xasl_cache_pinned (m_session, false, false);
        m_prepare_flag &= ~PREPARE_XASL_CACHE_PINNED;
      }
      }

    return error;
  }

  get_generated_keys_info
  query_handler::generated_keys ()
  {
    int error = NO_ERROR;

    get_generated_keys_info info;

    int stmt_type;
    DB_QUERY_RESULT *qres = (DB_QUERY_RESULT *) m_query_result.result;
    if (qres == NULL)
      {
    // TODO: proper error code
    m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
    error = ER_FAILED;
      }
    else
      {
    if (qres->type == T_SELECT)
      {
        stmt_type = qres->res.s.stmt_type;
        error = get_generated_keys_server_insert (info, *qres);
      }
    else if (qres->type == T_CALL)
      {
        stmt_type = m_query_result.stmt_type;
        error = get_generated_keys_client_insert (info, *qres);
      }
    else
      {
        // TODO: proper error code
        m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
        error = ER_FAILED;
      }
      }

    if (error == NO_ERROR)
      {
    /* set qresult_info */
    query_result_info &result_info = info.qresult_info;
    result_info.stmt_type = stmt_type;
    result_info.tuple_count = info.generated_keys.tuples.size ();
    result_info.query_id = -1; /* initialized value, intead of garbage */
      }

    return info;
  }

  int
  query_handler::get_generated_keys_client_insert (get_generated_keys_info &info, DB_QUERY_RESULT &qres)
  {
    int error = NO_ERROR;
    int tuple_count = 0;
    DB_SEQ *seq = NULL;
    DB_VALUE oid_val;

    assert (qres.type == T_CALL);

    DB_VALUE *val_ptr = qres.res.c.val_ptr;
    DB_TYPE db_type = DB_VALUE_DOMAIN_TYPE (val_ptr);
    if (db_type == DB_TYPE_SEQUENCE)
      {
    seq = db_get_set (val_ptr);
    if (seq == NULL)
      {
        // TODO: proper error code
        m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
    tuple_count = db_col_size (seq);
      }
    else if (db_type == DB_TYPE_OBJECT)
      {
    tuple_count = 1;
    db_make_object (&oid_val, db_get_object (val_ptr));
      }
    else
      {
    // TODO: proper error code
    m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    for (int i = 0; i < tuple_count; i++)
      {
    if (seq != NULL)
      {
        error = db_col_get (seq, i, &oid_val);
        if (error < 0)
          {
        // TODO: proper error code
        m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
        return ER_FAILED;
          }
      }

    error = make_attributes_by_oid_value (info, oid_val, i + 1);
    if (error < 0)
      {
        // TODO: proper error code
        m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
      }
    return NO_ERROR;
  }

  int
  query_handler::get_generated_keys_server_insert (get_generated_keys_info &info, DB_QUERY_RESULT &qres)
  {
    int error = NO_ERROR;

    assert (qres.type == T_SELECT);

    error = db_query_next_tuple (&qres);
    if (error < 0)
      {
    // TODO: proper error code
    m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    int tuple_count = 0;
    DB_VALUE oid_val;
    while (qres.res.s.cursor_id.position == C_ON)
      {
    tuple_count++;

    error = db_query_get_tuple_value (&qres, 0, &oid_val);
    if (error < 0)
      {
        // TODO: proper error code
        m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }

    error = make_attributes_by_oid_value (info, oid_val, tuple_count);
    if (error < 0)
      {
        // TODO: proper error code
        m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }

    error = db_query_next_tuple (&qres);
    if (error < 0)
      {
        // TODO: proper error code
        m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
      }

    return NO_ERROR;
  }

  int
  query_handler::make_attributes_by_oid_value (get_generated_keys_info &info, const DB_VALUE &oid_val, int tuple_offset)
  {
    int error = NO_ERROR;

    DB_OBJECT *obj = db_get_object (&oid_val);
    DB_OBJECT *class_obj = db_get_class (obj);
    DB_ATTRIBUTE *attributes = db_get_attributes (class_obj);

    OID ins_oid = OID_INITIALIZER;
    set_dbobj_to_oid (obj, &ins_oid);

    std::vector<DB_VALUE> attribute_values;
    for (DB_ATTRIBUTE *attr = attributes; attr; attr = db_attribute_next (attr))
      {
    DB_VALUE value;
    if (db_attribute_is_auto_increment (attr))
      {
        const char *attr_name = db_attribute_name (attr);
        error = db_get (obj, attr_name, &value);
        if (error < 0)
          {
        error = ER_FAILED;
        break;
          }

        if (tuple_offset == 1)
          {
        const char *class_name = db_get_class_name (class_obj);
        DB_DOMAIN *domain = db_attribute_domain (attr);
        int precision = db_domain_precision (domain);
        short scale = db_domain_scale (domain);
        char charset = db_domain_codeset (domain);
        int db_type = TP_DOMAIN_TYPE (domain);
        int set_type = DB_TYPE_NULL;

        if (TP_IS_SET_TYPE (db_type))
          {
            set_type = get_set_domain (domain, precision, scale, charset);
          }

        /* first tuple, store attribute info */
        column_info c_info = set_column_info (db_type, set_type, scale, precision, charset, attr_name, attr_name, class_name,
                              false);

        info.column_infos.push_back (c_info);
          }

        attribute_values.push_back (value);
      }
      }

    info.generated_keys.tuples.emplace_back (tuple_offset, attribute_values, ins_oid);
    return error;
  }

  int
  query_handler::set_qresult_info (query_result_info &qinfo)
  {
    int error = NO_ERROR;
    OID ins_oid = OID_INITIALIZER;
    DB_OBJECT *ins_obj_p;

    query_result &qresult = m_query_result;
    DB_QUERY_RESULT *qres = (DB_QUERY_RESULT *) qresult.result;

    /* set result of a GET_GENERATED_KEYS request */
    if (qresult.stmt_type == CUBRID_STMT_INSERT && qres != NULL)
      {
    if (qres->type == T_SELECT)
      {
        /* result of a GET_GENERATED_KEYS request, server insert */
        /* do nothing */
      }
    else // qres->type == T_CALL
      {
        DB_VALUE val;
        error = db_query_get_tuple_value ((DB_QUERY_RESULT *) qresult.result, 0, &val);
        if (error >= 0)
          {
        if (DB_VALUE_DOMAIN_TYPE (&val) == DB_TYPE_OBJECT)
          {
            ins_obj_p = db_get_object (&val);
            set_dbobj_to_oid (ins_obj_p, &ins_oid);
            db_value_clear (&val);
          }
        else if (DB_VALUE_DOMAIN_TYPE (&val) == DB_TYPE_SEQUENCE)
          {
            /* result of a GET_GENERATED_KEYS request, client insert */
            DB_VALUE value;
            DB_SEQ *seq = db_get_set (&val);
            if (seq != NULL && db_col_size (seq) == 1)
              {
            db_col_get (seq, 0, &value);
            ins_obj_p = db_get_object (&value);
            set_dbobj_to_oid (ins_obj_p, &ins_oid);
            db_value_clear (&value);
              }
            db_value_clear (&val);
          }
          }
      }
      }

    query_result_info &result_info = qinfo;
    result_info.ins_oid = ins_oid;
    result_info.stmt_type = qresult.stmt_type;
    result_info.tuple_count = qresult.tuple_count;
    result_info.include_oid = qresult.include_oid;

    if (qres && qres->type == T_SELECT)
      {
    result_info.query_id = qres->res.s.query_id;
    if (result_info.query_id >= SHRT_MAX) // handle invalid value
      {
        result_info.query_id = NULL_QUERY_ID; // initialized value
      }
      }
    return error;
  }

  int
  query_handler::execute_internal_call (int flag, int max_col_size, int max_row,
                    const std::vector<DB_VALUE> &bind_values, const std::vector<int> &param_modes)
  {
    int error = NO_ERROR;

    int num_bind = get_num_markers ();
    assert (num_bind == (int) bind_values.size ());

    prepare_call_info &call_info = m_prepare_call_info;
    // set host variables
    if (num_bind > 0)
      {
    if (call_info.is_first_out)
      {
        error = set_host_variables (num_bind - 1, (DB_VALUE *) &bind_values[1]);
      }
    else
      {
        error = set_host_variables (num_bind, (DB_VALUE *) &bind_values[0]);
      }

    if (error != NO_ERROR)
      {
        m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
      }

    DB_QUERY_RESULT *result = NULL;
    int stmt_id = m_query_result.stmt_id;
    jsp_set_prepare_call ();
    int n = db_execute_and_keep_statement (m_session, stmt_id, &result);
    jsp_unset_prepare_call ();
    if (n < 0)
      {
    m_error_ctx.set_error (n, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    if (result != NULL)
      {
    /* success; copy the values in tuples */
    (void) db_query_set_copy_tplvalue (result, 1 /* copy */ );
      }

    int i = 0;
    if (call_info.is_first_out)
      {
    if (result != NULL)
      {
        db_query_get_tuple_value (result, 0, &call_info.dbval_args[0]);
      }
    i++;
      }

    DB_VALUE *out_vals = db_get_hostvars (m_session);
    for (int j = 0; i < call_info.num_args; i++, j++)
      {
    call_info.dbval_args[i] = out_vals[j];
      }

    m_execute_info.num_affected = n;

    m_has_result_set = true;

    /* set query result */
    m_query_result.result = result;
    m_query_result.tuple_count = n;

    error = set_qresult_info (m_execute_info.qresult_info);

    // set prepare call info
    if (error == NO_ERROR)
      {
    assert (call_info.param_modes.size() == param_modes.size());
    for (int i = 0; i < (int) call_info.param_modes.size(); i++)
      {
        call_info.param_modes[i] = param_modes[i];
      }
    m_execute_info.call_info = &call_info;
      }

    return error;
  }

  void
  query_handler::end_qresult ()
  {
    query_result &q_result = m_query_result;
    if (q_result.copied == false && q_result.result)
      {
    DB_QUERY_RESULT *result = q_result.result;
    db_query_end_internal (result, false);
      }
    q_result.result = NULL;

    if (q_result.column_info)
      {
    db_query_format_free (q_result.column_info);
    q_result.column_info = NULL;
      }

    m_has_result_set = false;
    m_query_id = (uint64_t) (-1);
  }

  int
  query_handler::execute_internal (int flag, int max_col_size, int max_row,
                   const std::vector<DB_VALUE> &bind_values)
  {
    int error = NO_ERROR;

    assert (is_prepared ());

    // bind host variables
    int num_bind = get_num_markers ();
    assert (num_bind == (int) bind_values.size ());
    if (num_bind > 0)
      {
    error = set_host_variables (num_bind, (DB_VALUE *) bind_values.data());
    if (error != NO_ERROR)
      {
        return error;
      }
      }

    if (flag & EXEC_RETURN_GENERATED_KEYS)
      {
    db_session_set_return_generated_keys ((DB_SESSION *) m_session, true);
      }
    else
      {
    db_session_set_return_generated_keys ((DB_SESSION *) m_session, false);
      }

    int stmt_id = -1;

    // check unexpected behavior trying to execute query handler un-prepared
    if (m_is_prepared == false)
      {
    assert (false); // something wrong
    m_error_ctx.set_error (METHOD_CALLBACK_ER_STMT_POOLING, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }
    else
      {
    stmt_id = m_query_result.stmt_id;
      }

    DB_QUERY_RESULT *result = NULL;
    int n = db_execute_and_keep_statement (m_session, stmt_id, &result);
    if (n < 0)
      {
    return ER_FAILED;
      }
    else if (result != NULL)
      {
    /* success; peek the values in tuples */
    (void) db_query_set_copy_tplvalue (result, 0 /* peek */ );
      }

    if (max_row > 0 && db_get_statement_type (m_session, stmt_id) == CUBRID_STMT_SELECT)
      {
    // TODO: max_row?
      }

    m_execute_info.num_affected = n;

    if (m_prepare_flag & PREPARE_XASL_CACHE_PINNED)
      {
    db_session_set_xasl_cache_pinned (m_session, false, false);
    m_prepare_flag &= ~PREPARE_XASL_CACHE_PINNED;
      }

    db_get_cacheinfo (m_session, stmt_id, &m_use_plan_cache, NULL);

    /* set to query result */
    m_query_result.result = result;
    m_query_result.tuple_count = n;

    if (has_stmt_result_set (m_query_result.stmt_type))
      {
    m_has_result_set = true;
      }

    error = set_qresult_info (m_execute_info.qresult_info);

    return error;
  }

  bool
  query_handler::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;
  }

  int
  query_handler::prepare_query ()
  {
    int &flag = m_prepare_flag;

    if (flag & PREPARE_STATIC_SQL)
      {
    g_open_buffer_control_flags |= PARSER_FOR_PLCSQL_STATIC_SQL;
      }

    db_init_lexer_lineno();
    m_session = db_open_buffer (m_sql_stmt.c_str());
    g_open_buffer_control_flags = 0;

    if (!m_session)
      {
    m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
    return ER_FAILED;
      }

    if (db_check_single_query (m_session) == ER_IT_MULTIPLE_STATEMENT)
      {
    er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_MULTIPLE_STATEMENT, 0);
    m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
    return ER_FAILED;
      }

    flag |= (flag & PREPARE_UPDATABLE) ? PREPARE_INCLUDE_OID : 0;
    if (flag & PREPARE_INCLUDE_OID)
      {
    db_include_oid (m_session, DB_ROW_OIDS);
      }

    if (flag & PREPARE_XASL_CACHE_PINNED)
      {
    db_session_set_xasl_cache_pinned (m_session, true, false);
      }

    m_stmt_type = CUBRID_STMT_NONE;
    int stmt_id = db_compile_statement (m_session);
    if (stmt_id < 0)
      {
    m_stmt_type = get_stmt_type (m_sql_stmt);
    if (stmt_id == ER_PT_SEMANTIC && m_stmt_type != CUBRID_STMT_SELECT && m_stmt_type != CUBRID_MAX_STMT_TYPE)
      {
        close_and_free_session ();
      }
    m_error_ctx.set_error (stmt_id, db_error_string (1), __FILE__, __LINE__);
    m_is_prepared = false;
    return ER_FAILED;
      }
    else
      {
    m_stmt_type = db_get_statement_type (m_session, stmt_id);
    m_is_prepared = true;
      }

    db_get_cacheinfo (m_session, stmt_id, &m_use_plan_cache, NULL);
    db_session_set_holdable (m_session, true);

    /* prepare result set */
    m_num_markers = get_num_markers ();

    query_result &q_result = m_query_result;
    q_result.stmt_type = m_stmt_type;
    q_result.stmt_id = stmt_id;

    return NO_ERROR;
  }

  int
  query_handler::prepare_call ()
  {
    std::string sql_stmt_copy = m_sql_stmt;
    int error = m_prepare_call_info.set_is_first_out (sql_stmt_copy);
    if (error != NO_ERROR)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_INVALID_CALL_STMT, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    str_trim (sql_stmt_copy);
    int stmt_type = get_stmt_type (sql_stmt_copy);
    if (stmt_type != CUBRID_STMT_CALL)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_INVALID_CALL_STMT, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    db_init_lexer_lineno ();
    m_session = db_open_buffer (sql_stmt_copy.c_str());
    if (!m_session)
      {
    m_error_ctx.set_error (db_error_code(), db_error_string (1), __FILE__, __LINE__);
    return ER_FAILED;
      }

    if (db_check_single_query (m_session) == ER_IT_MULTIPLE_STATEMENT)
      {
    er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_MULTIPLE_STATEMENT, 0);
    m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
    er_clear ();
    return ER_FAILED;
      }

    int stmt_id = db_compile_statement (m_session);
    if (stmt_id < 0)
      {
    m_error_ctx.set_error (stmt_id, db_error_string (1), __FILE__, __LINE__);
    return ER_FAILED;
      }

    m_is_prepared = true;

    db_get_cacheinfo (m_session, stmt_id, &m_use_plan_cache, NULL);

    /* prepare result set */
    m_stmt_type = CUBRID_STMT_CALL_SP;
    m_num_markers = get_num_markers ();
    m_prepare_call_info.set_prepare_call_info (m_num_markers);

    query_result &q_result = m_query_result;
    q_result.stmt_type = m_stmt_type;
    q_result.stmt_id = stmt_id;

    return NO_ERROR;
  }

  void
  query_handler::close_and_free_session ()
  {
    if (m_session)
      {
    db_close_session ((DB_SESSION *) (m_session));
      }
    m_session = NULL;
  }

  void
  query_handler::set_prepare_column_list_info (std::vector<column_info> &infos)
  {
    m_query_result.include_oid = false;

    if (!m_query_result.null_type_column.empty())
      {
    m_query_result.null_type_column.clear();
      }

    int stmt_id = m_query_result.stmt_id;
    char stmt_type = m_query_result.stmt_type;
    if (stmt_type == CUBRID_STMT_SELECT)
      {
    // TODO: updatable
    if (m_prepare_flag)
      {
        if (db_query_produce_updatable_result (m_session, stmt_id) <= 0)
          {
        // TODO: updatable
          }
        else
          {
        m_query_result.include_oid = true;
          }
      }

    DB_QUERY_TYPE *db_column_info = db_get_query_type_list (m_session, stmt_id);
    if (db_column_info == NULL)
      {
        m_error_ctx.set_error (db_error_code(), db_error_string (1), __FILE__, __LINE__);
      }

    int num_cols = 0;
    char *col_name = NULL, *class_name = NULL, *attr_name = NULL;

    char set_type;
    int precision = 0;
    short scale = 0;
    char charset;

    DB_QUERY_TYPE *col;
    for (col = db_column_info; col != NULL; col = db_query_format_next (col))
      {
#if 0
        // TODO: stripped_column_name
        if (stripped_column_name)
          {
        col_name = (char *) db_query_format_name (col);
          }
        else
#endif
          {
        col_name = (char *) db_query_format_original_name (col);
        if (strchr (col_name, '*') != NULL)
          {
            col_name = (char *) db_query_format_name (col);
          }
          }
        class_name = (char *) db_query_format_class_name (col);
        attr_name = (char *) db_query_format_attr_name (col);

        // TODO: related to updatable flag

        DB_DOMAIN *domain = db_query_format_domain (col);
        DB_TYPE db_type = TP_DOMAIN_TYPE (domain);

        if (TP_IS_SET_TYPE (db_type))
          {
        // TODO: set type
        set_type = get_set_domain (domain, precision, scale, charset);
          }
        else
          {
        set_type = DB_TYPE_NULL;
        precision = db_domain_precision (domain);
        scale = (short) db_domain_scale (domain);
        charset = db_domain_codeset (domain);
          }

        if (db_type == DB_TYPE_NULL)
          {
        m_query_result.null_type_column.push_back (1);
          }
        else
          {
        m_query_result.null_type_column.push_back (0);
          }

        column_info info = set_column_info ((int) db_type, set_type, scale, precision, charset, col_name, attr_name, class_name,
                        (char) db_query_format_is_non_null (col));
        infos.push_back (info);
        num_cols++;
      }

    m_query_result.num_column = num_cols;

    // TODO: updatable
    //q_result->col_updatable = updatable_flag;
    //q_result->col_update_info = col_update_info;
    if (db_column_info)
      {
        db_query_format_free (db_column_info);
      }
      }
    else if (stmt_type == CUBRID_STMT_CALL || stmt_type == CUBRID_STMT_GET_STATS || stmt_type == CUBRID_STMT_EVALUATE)
      {
    m_query_result.null_type_column.push_back (1);
    column_info info; // default constructor
    infos.push_back (info);
      }
    else
      {
    //
      }
  }

  column_info
  query_handler::set_column_info (int dbType, int setType, short scale, int prec, char charset, const char *col_name,
                  const char *attr_name,
                  const char *class_name, char is_non_null)
  {
    DB_OBJECT *class_obj = db_find_class (class_name);
    DB_ATTRIBUTE *attr = db_get_attribute (class_obj, col_name);

    char auto_increment = db_attribute_is_auto_increment (attr);
    char unique_key = db_attribute_is_unique (attr);
    char primary_key = db_attribute_is_primary_key (attr);
    char reverse_index = db_attribute_is_reverse_indexed (attr);
    char reverse_unique = db_attribute_is_reverse_unique (attr);
    char foreign_key = db_attribute_is_foreign_key (attr);
    char shared = db_attribute_is_shared (attr);

    std::string col_name_string (col_name ? col_name : "");
    std::string attr_name_string (attr_name? attr_name : "");
    std::string class_name_string (class_name? class_name : "");

    std::string default_value_string = get_column_default_as_string (attr);

    column_info info (dbType, setType, scale, prec, charset,
              col_name_string, default_value_string,
              auto_increment, unique_key, primary_key, reverse_index, reverse_unique, foreign_key, shared,
              attr_name_string, class_name_string, is_non_null);

    if (er_errid () == ER_OBJ_INVALID_ATTRIBUTE || er_errid () == ER_OBJ_INVALID_ARGUMENTS)
      {
    // do not check
    er_clear ();
      }

    return info;
  }

  /*
  * set_host_variables ()
  *
  *   return: error code or NO_ERROR
  *   db_session(in):
  *   num_bind(in):
  *   in_values(in):
  */
  int
  query_handler::set_host_variables (int num_bind, DB_VALUE *in_values)
  {
    int err_code;
    DB_CLASS_MODIFICATION_STATUS cls_status;
    int stmt_id;

    err_code = db_push_values (m_session, num_bind, in_values);
    if (err_code != NO_ERROR)
      {
    int stmt_count = db_statement_count (m_session);
    for (stmt_id = 0; stmt_id < stmt_count; stmt_id++)
      {
        cls_status = db_has_modified_class (m_session, stmt_id);
        if (cls_status == DB_CLASS_MODIFIED)
          {
        m_error_ctx.set_error (METHOD_CALLBACK_ER_STMT_POOLING, NULL, __FILE__, __LINE__);
        return err_code;
          }
        else if (cls_status == DB_CLASS_ERROR)
          {
        assert (er_errid () != NO_ERROR);
        err_code = er_errid ();
        if (err_code == NO_ERROR)
          {
            err_code = ER_FAILED;
          }
        m_error_ctx.set_error (err_code, NULL, __FILE__, __LINE__);
        return err_code;
          }
      }
    m_error_ctx.set_error (err_code, NULL, __FILE__, __LINE__);
      }

    return err_code;
  }

  void
  query_result::clear ()
  {
    column_info = NULL;
    result = NULL;
    stmt_id = 0;
    stmt_type = 0;
    num_column = 0;
    tuple_count = 0;

    include_oid = false;
    copied = false;
  }

  void query_handler::set_dbobj_to_oid (DB_OBJECT *obj, OID *oid)
  {
    OID *objs_oid = db_identifier (obj);

    assert (oid != NULL);

    if (objs_oid == NULL)
      {
    oid->pageid = 0;
    oid->volid = 0;
    oid->slotid = 0;
      }
    else
      {
    oid->pageid = objs_oid->pageid;
    oid->volid = objs_oid->volid;
    oid->slotid = objs_oid->slotid;
      }
  }
}