Skip to content

File pl_query_cursor.cpp

File List > cubrid > src > sp > pl_query_cursor.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 "pl_query_cursor.hpp"

#include "dbtype.h"
#include "dbtype_def.h"
#include "list_file.h"
#include "log_impl.h"
#include "object_representation.h"
#include "xserver_interface.h"

// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

namespace cubpl
{
  query_cursor::query_cursor (cubthread::entry *thread_p, QUERY_ID qid, bool oid_included)
    : m_thread (thread_p)
    , m_query_id (qid)
    , m_query_entry (nullptr)
    , m_current_row_index (0)
    , m_is_oid_included (oid_included)
    , m_is_opened (false)
    , m_fetch_count (1000) // FIXME: change the fixed value, 1000
    , m_query_entry_no (0)
  {
    //
  }

  query_cursor::~query_cursor ()
  {
    close ();
  }

  int
  query_cursor::reset ()
  {
    m_current_row_index = 0;
    int tran_index = LOG_FIND_THREAD_TRAN_INDEX (m_thread);
    m_query_entry = qmgr_get_query_entry (m_thread, m_query_id, tran_index);
    if (m_query_entry && m_query_entry->list_id)
      {
    m_query_entry_no = m_query_entry->alloc_no;
    assert (m_query_entry_no != 0);         // see qmgr_allocate_query_entry()
    m_current_tuple.resize (m_query_entry->list_id->type_list.type_cnt);
    for (DB_VALUE &val : m_current_tuple)
      {
        db_make_null (&val);
      }

    return NO_ERROR;
      }

    return ER_FAILED;
  }

  int
  query_cursor::open ()
  {
    if (m_is_opened == false)
      {
    if (reset () == NO_ERROR && qfile_open_list_scan (m_query_entry->list_id, &m_scan_id) == NO_ERROR)
      {
        m_is_opened = true;
      }
      }
    return m_is_opened ? NO_ERROR : ER_FAILED;
  }

  void
  query_cursor::close ()
  {
    if (m_is_opened)
      {
    qfile_close_scan (m_thread, &m_scan_id);

    if (m_query_entry && (m_query_entry->list_id == NULL || m_query_entry->alloc_no != m_query_entry_no))
      {
        int tran_index = LOG_FIND_THREAD_TRAN_INDEX (m_thread);
        m_query_entry = qmgr_get_query_entry (m_thread, m_query_id, tran_index);
      }

    if (m_query_entry)
      {
        // Since the list was not created in this thread,
        // incrementing the count of the list (m_qlist_count) is required
        // to make the assertion on m_qlist_count in qexec_execute_query() hold
        qfile_update_qlist_count (m_thread, m_query_entry->list_id, 1);
        qfile_close_list (m_thread, m_query_entry->list_id);
      }

    // clear query entry
    xqmgr_end_query (m_thread, m_query_id);
    clear ();
    m_is_opened = false;
      }
  }

  bool
  query_cursor::is_opened () const
  {
    return m_is_opened;
  }

  void
  query_cursor::clear ()
  {
    m_query_entry = nullptr;
    m_query_entry_no = 0;
    m_current_tuple.clear ();
    m_current_row_index = 0;
    m_fetch_count = 0;
  }

  SCAN_CODE
  query_cursor::next_row ()
  {
    if (m_is_opened == false)
      {
    return S_END;
      }

    QFILE_TUPLE_RECORD tuple_record = { NULL, 0 };
    SCAN_CODE scan_code = qfile_scan_list_next (m_thread, &m_scan_id, &tuple_record, PEEK);
    if (scan_code == S_SUCCESS)
      {
    m_current_row_index++;

    char *ptr;
    int length;
    OR_BUF buf;

    assert (m_query_entry != NULL);
    if (m_query_entry->list_id == NULL || m_query_entry->alloc_no != m_query_entry_no)
      {
        int tran_index = LOG_FIND_THREAD_TRAN_INDEX (m_thread);
        m_query_entry = qmgr_get_query_entry (m_thread, m_query_id, tran_index);
        if (m_query_entry && m_query_entry->list_id)
          {
        m_query_entry_no = m_query_entry->alloc_no;
          }
        else
          {
        qfile_close_scan (m_thread, &m_scan_id);
        return S_ERROR; // control reaches here when this method is called after ROLLBACK
          }
      }

    QFILE_LIST_ID *list_id = m_query_entry->list_id;
    for (int i = 0; i < list_id->type_list.type_cnt; i++)
      {
        DB_VALUE *value = &m_current_tuple[i];
        QFILE_TUPLE_VALUE_FLAG flag = (QFILE_TUPLE_VALUE_FLAG) qfile_locate_tuple_value (tuple_record.tpl, i, &ptr, &length);
        if (flag == V_BOUND)
          {
        TP_DOMAIN *domain = list_id->type_list.domp[i];
        if (domain == NULL || domain->type == NULL)
          {
            scan_code = S_ERROR;
            break;
          }

        const PR_TYPE *pr_type = domain->type;
        if (pr_type == NULL)
          {
            scan_code = S_ERROR;
            break;
          }

        or_init (&buf, ptr, length);

        if (pr_type->data_readval (&buf, value, domain, -1, true, NULL, 0) != NO_ERROR)
          {
            scan_code = S_ERROR;
            break;
          }
          }
        else
          {
        db_make_null (value);
          }
      }
      }

    if (scan_code == S_END || scan_code == S_ERROR)
      {
    close ();
      }

    return scan_code;
  }

  void
  query_cursor::change_owner (cubthread::entry *thread_p)
  {
    if (m_thread != nullptr && m_thread->get_id () == thread_p->get_id ())
      {
    return;
      }

    close ();

    // change owner thread
    m_thread = thread_p;
  }

  cubthread::entry *
  query_cursor::get_owner () const
  {
    return m_thread;
  }

  std::vector<DB_VALUE>
  query_cursor::get_current_tuple ()
  {
    return m_current_tuple;
  }

  int
  query_cursor::get_current_index ()
  {
    return m_current_row_index;
  }

  OID *
  query_cursor::get_current_oid ()
  {
    if (m_is_oid_included)
      {
    DB_VALUE *first_value = &m_current_tuple[0];
    DB_TYPE type = DB_VALUE_DOMAIN_TYPE (first_value);

    if (type == DB_TYPE_OID)
      {
        return db_get_oid (first_value);
      }
      }
    return NULL;
  }

  bool
  query_cursor::get_is_oid_included ()
  {
    return m_is_oid_included;
  }

  QUERY_ID
  query_cursor::get_query_id ()
  {
    return m_query_id;
  }

  bool
  query_cursor::get_is_opened ()
  {
    return m_is_opened;
  }

  int
  query_cursor::get_fetch_count ()
  {
    return m_fetch_count;
  }

  void
  query_cursor::set_fetch_count (int cnt)
  {
    if (cnt > 0 && cnt < INT32_MAX) // check invalid value
      {
    m_fetch_count = cnt;
      }
  }

}