Skip to content

File method_oid_handler.cpp

File List > cubrid > src > method > method_oid_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_oid_handler.hpp"

#include <cstring>
#include <string>

#include "dbi.h"
#include "dbtype.h"
#include "method_struct_oid_info.hpp"
#include "method_query_util.hpp"
#include "object_primitive.h"
#include "oid.h"

namespace cubmethod
{
  oid_handler::~oid_handler ()
  {
    //
  }

// OID

  int
  oid_handler::check_object (DB_OBJECT *obj)
  {
    int error = NO_ERROR;

    if (obj == NULL)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    er_clear ();
    error = db_is_instance (obj);
    if (error < 0)
      {
    m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }
    else if (error > 0)
      {
    return 0;
      }

    error = db_error_code ();
    if (error < 0)
      {
    m_error_ctx.set_error (db_error_code(), db_error_string (1), __FILE__, __LINE__);
    return ER_FAILED;
      }

    m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
    return ER_FAILED;
  }

  oid_get_info
  oid_handler::oid_get (OID &oid, std::vector<std::string> &attr_names)
  {
    int error = NO_ERROR;
    oid_get_info info;

    DB_OBJECT *obj = db_object (&oid);
    if (obj == NULL)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
    return info;
      }

    error = check_object (obj);
    if (error < 0)
      {
    return info;
      }

    // set attribute names
    if (attr_names.empty())
      {
    /* get attributes name */
    DB_ATTRIBUTE *attributes = db_get_attributes (obj);
    for (DB_ATTRIBUTE *att = attributes; att; att = db_attribute_next (att))
      {
        const char *name = db_attribute_name (att);
        attr_names.emplace_back (name);
      }
      }

    // set attribute column info
    for (std::string &attr_name : attr_names)
      {
    DB_ATTRIBUTE *attr = NULL;
    char *p = (char *) std::strrchr (attr_name.c_str (), '.');
    if (p == NULL)
      {
        attr = db_get_attribute (obj, attr_name.c_str ());
        if (attr == NULL)
          {
        m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
        return info;
          }
      }
    else
      {
        DB_VALUE path_val;
        *p = '\0';
        error = db_get (obj, attr_name.c_str (), &path_val);
        if (error < 0 || db_value_is_null (&path_val) == true)
          {
        attr = NULL;
          }
        else
          {
        DB_OBJECT *path_obj = db_get_object (&path_val);
        attr = db_get_attribute (path_obj, p + 1);
        if (attr == NULL)
          {
            m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
            return info;
          }
          }
        *p = '.';
        db_value_clear (&path_val);
      }

    int db_type = DB_TYPE_NULL, set_type = DB_TYPE_NULL, precision = 0;
    short scale = 0;
    char charset = 0;
    if (attr != NULL)
      {
        DB_DOMAIN *domain = db_attribute_domain (attr);
        db_type = TP_DOMAIN_TYPE (domain);
        if (TP_IS_SET_TYPE (db_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);
          }
      }

    info.column_infos.emplace_back (db_type, set_type, scale, precision, charset, attr_name);
      }

    // set class name
    const char *cname = db_get_class_name (obj);
    if (cname != NULL)
      {
    info.class_name.assign (cname);
      }

    // set attr names
    info.attr_names = std::move (attr_names);

    // set OID data
    DB_VALUE val;
    for (std::string &attr_name : info.attr_names)
      {
    if (db_get (obj, attr_name.c_str (), &val) < 0)
      {
        db_make_null (&val);
      }
    info.db_values.push_back (val);
      }

    return info;
  }

  int
  oid_handler::oid_put (OID &oid, std::vector<std::string> &attr_names, std::vector<DB_VALUE> &attr_values)
  {
    int error = NO_ERROR;

    DB_OBJECT *obj = db_object (&oid);
    if (obj == NULL)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    error = check_object (obj);
    if (error < 0)
      {
    return ER_FAILED;
      }

    DB_OTMPL *otmpl = dbt_edit_object (obj);
    if (otmpl == NULL)
      {
    m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
    return ER_FAILED;
      }

    assert (attr_names.size() == attr_values.size());

    DB_VALUE *attr_val = NULL;
    int i = 0;

    for (int i = 0; i < (int) attr_names.size(); i++)
      {
    const char *attr_name = attr_names[i].c_str ();
    char attr_type = get_attr_type (obj, attr_name);
    attr_val = &attr_values[i];

    error = dbt_put (otmpl, attr_name, attr_val);
    if (error < 0)
      {
        m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
        db_value_clear (attr_val);
        dbt_abort_object (otmpl);
        return error;
      }

    db_value_clear (attr_val);
      }

    obj = dbt_finish_object (otmpl);
    if (obj == NULL)
      {
    m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
    return ER_FAILED;
      }

    return NO_ERROR;
  }

  int
  oid_handler::oid_cmd (OID &oid, int cmd, std::string &res)
  {
    int error = NO_ERROR;

    DB_OBJECT *obj = db_object (&oid);
    if (obj == NULL)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    if (cmd != OID_IS_INSTANCE)
      {
    error = check_object (obj);
    if (error < 0)
      {
        return ER_FAILED;
      }
      }

    if (cmd == OID_DROP)
      {
    error = db_drop (obj);
      }
    else if (cmd == OID_IS_INSTANCE)
      {
    if (obj == NULL)
      {
        error = 0;
      }
    else
      {
        er_clear();
        if (db_is_instance (obj) > 0)
          {
        error = 1;
          }
        else
          {
        error = db_error_code ();
        if (error == ER_HEAP_UNKNOWN_OBJECT)
          {
            error = 0;
          }
          }
      }
      }
    else if (cmd == OID_LOCK_READ)
      {
    if (obj == NULL)
      {
        m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
    error = db_lock_read (obj);
      }
    else if (cmd == OID_LOCK_WRITE)
      {
    if (obj == NULL)
      {
        m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
    error = db_lock_write (obj);
      }
    else if (cmd == OID_CLASS_NAME)
      {
    if (obj == NULL)
      {
        m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
    char *class_name = (char *) db_get_class_name (obj);
    if (class_name == NULL)
      {
        error = db_error_code ();
        class_name = (char *) "";
      }
    else
      {
        error = NO_ERROR;
      }
    res.assign (class_name);
      }
    else
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    return error;
  }

// Collection

  int
  oid_handler::collection_cmd (OID &oid, int cmd, int seq_index, std::string &attr_name, DB_VALUE &elem_value)
  {
    int error = NO_ERROR;

    DB_OBJECT *obj = db_object (&oid);
    if (obj == NULL)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_OBJECT, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    error = check_object (obj);
    if (error < 0)
      {
    return ER_FAILED;
      }

    error = NO_ERROR;

    const char *name = attr_name.c_str ();
    DB_ATTRIBUTE *attr = db_get_attribute (obj, name);
    if (attr == NULL)
      {
    m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__);
    return ER_FAILED;
      }

    DB_DOMAIN *domain = db_attribute_domain (attr);
    DB_TYPE type = TP_DOMAIN_TYPE (domain);
    if (type != DB_TYPE_SET && type != DB_TYPE_MULTISET && type != DB_TYPE_SEQUENCE)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_NOT_COLLECTION, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    int dummy1;
    short dummy2;
    char dummy3;
    DB_TYPE elem_type = (DB_TYPE) get_set_domain (domain, dummy1, dummy2, dummy3);
    DB_DOMAIN *elem_domain = db_domain_set (domain);
    if (elem_type <= 0)
      {
    m_error_ctx.set_error (METHOD_CALLBACK_ER_COLLECTION_DOMAIN, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    DB_VALUE val;
    error = db_get (obj, name, &val);
    if (error < 0)
      {
    m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
    return ER_FAILED;
      }

    DB_COLLECTION *collection = NULL;
    if (db_value_type (&val) != DB_TYPE_NULL)
      {
    collection = db_get_collection (&val);
      }

    error = NO_ERROR; // reset error

    switch (cmd)
      {
      case COL_GET:
    /* TODO: not implemented at Server-Side JDBC */
    m_error_ctx.set_error (METHOD_CALLBACK_ER_NOT_IMPLEMENTED, NULL, __FILE__, __LINE__);
    error = ER_FAILED;
    break;
      case COL_SIZE:
    error = col_size (collection); // error is col_size
    break;
      case COL_SET_DROP:
    error = col_set_drop (collection, &elem_value);
    break;
      case COL_SET_ADD:
    error = col_set_add (collection, &elem_value);
    break;
      case COL_SEQ_DROP:
    error = col_seq_drop (collection, seq_index);
    break;
      case COL_SEQ_INSERT:
    error = col_seq_insert (collection, seq_index, &elem_value);
    break;
      case COL_SEQ_PUT:
    error = col_seq_put (collection, seq_index, &elem_value);
    break;
      default:
    assert (false); // invalid command
    error = ER_FAILED;
    break;
      }

    /* db_put */
    switch (cmd)
      {
      case COL_SET_DROP:
      case COL_SET_ADD:
      case COL_SEQ_DROP:
      case COL_SEQ_INSERT:
      case COL_SEQ_PUT:
    if (error >= 0)
      {
        db_put (obj, name, &val);
      }
    break;
      default:
    /* do nothing */
    break;
      }

    db_col_free (collection);
    db_value_clear (&val);

    return error;
  }


  int
  oid_handler::col_set_drop (DB_COLLECTION *col, DB_VALUE *ele_val)
  {
    if (col != NULL)
      {
    int error = db_set_drop (col, ele_val);
    if (error < 0)
      {
        m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
      }
    return NO_ERROR;
  }

  int
  oid_handler::col_set_add (DB_COLLECTION *col, DB_VALUE *ele_val)
  {
    int error = NO_ERROR;

    if (col != NULL)
      {
    error = db_set_add (col, ele_val);
    if (error < 0)
      {
        m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
      }

    return NO_ERROR;
  }

  int
  oid_handler::col_seq_drop (DB_COLLECTION *col, int seq_index)
  {
    if (col != NULL)
      {
    int error = db_seq_drop (col, seq_index - 1);
    if (error < 0)
      {
        m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
      }
    return NO_ERROR;
  }

  int
  oid_handler::col_seq_insert (DB_COLLECTION *col, int seq_index, DB_VALUE *ele_val)
  {
    int error = NO_ERROR;

    if (col != NULL)
      {
    error = db_seq_insert (col, seq_index - 1, ele_val);
    if (error < 0)
      {
        m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
      }

    return NO_ERROR;
  }

  int
  oid_handler::col_seq_put (DB_COLLECTION *col, int seq_index, DB_VALUE *ele_val)
  {
    int error = NO_ERROR;

    if (col != NULL)
      {
    error = db_seq_put (col, seq_index - 1, ele_val);
    if (error < 0)
      {
        m_error_ctx.set_error (error, NULL, __FILE__, __LINE__);
        return ER_FAILED;
      }
      }

    return NO_ERROR;
  }

  int
  oid_handler::col_size (DB_COLLECTION *col)
  {
    int col_size;
    if (col == NULL)
      {
    col_size = -1;
      }
    else
      {
    col_size = db_col_size (col);
      }

    return col_size;
  }

// MISC

  char
  oid_handler::get_attr_type (DB_OBJECT *obj, const char *attr_name)
  {
    DB_ATTRIBUTE *attribute = db_get_attribute (obj, attr_name);
    if (attribute == NULL)
      {
    return DB_TYPE_NULL;
      }

    DB_DOMAIN *attr_domain = db_attribute_domain (attribute);
    if (attr_domain == NULL)
      {
    return DB_TYPE_NULL;
      }

    int db_type = TP_DOMAIN_TYPE (attr_domain);
    if (TP_IS_SET_TYPE (db_type))
      {
    int dummy1;
    short dummy2;
    char dummy3;
    db_type = get_set_domain (attr_domain, dummy1, dummy2, dummy3);
      }
    return db_type;
  }
}