/**
 * Copyright (c) 2021 OceanBase
 * OceanBase CE is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#define USING_LOG_PREFIX SERVER

#include "ob_inner_sql_result.h"

#include "lib/mysqlclient/ob_mysql_result.h"
#include "lib/hash/ob_hashmap.h"
#include "lib/rc/context.h"

namespace oceanbase {
using namespace common;
using namespace common::sqlclient;
using namespace share;
using namespace share::schema;
using namespace sql;

namespace observer {
inline int ObInnerSQLResult::check_extend_value(const common::ObObj& obj)
{
  int ret = OB_SUCCESS;
  if (obj.is_null()) {
    ret = OB_ERR_NULL_VALUE;
  } else if (obj.is_min_value()) {
    ret = OB_ERR_MIN_VALUE;
  } else if (obj.is_max_value()) {
    ret = OB_ERR_MIN_VALUE;
  }
  return ret;
}

ObInnerSQLResult::ObInnerSQLResult(ObSQLSessionInfo& session)
    : column_map_created_(false),
      column_indexed_(false),
      column_map_(),
      mem_context_(nullptr),
      mem_context_destroy_guard_(mem_context_),
      sql_ctx_(),
      opened_(false),
      session_(session),
      result_set_(nullptr),
      row_(NULL),
      execute_start_ts_(0),
      execute_end_ts_(0),
      compat_mode_(
          ORACLE_MODE == session.get_compatibility_mode() ? ObWorker::CompatMode::ORACLE : ObWorker::CompatMode::MYSQL),
      is_inited_(false)
{
  sql_ctx_.exec_type_ = InnerSql;
}

int ObInnerSQLResult::init()
{
  int ret = OB_SUCCESS;
  lib::ContextParam param;
  param.set_mem_attr(session_.get_effective_tenant_id(), ObModIds::OB_RESULT_SET, ObCtxIds::DEFAULT_CTX_ID)
      .set_properties(lib::USE_TL_PAGE_OPTIONAL)
      .set_page_size(OB_MALLOC_MIDDLE_BLOCK_SIZE)
      .set_ablock_size(lib::INTACT_MIDDLE_AOBJECT_SIZE);
  if (OB_FAIL(CURRENT_CONTEXT->CREATE_CONTEXT(mem_context_, param))) {
    LOG_WARN("create memory entity failed", K(ret));
  } else {
    result_set_ = new (buf_) ObResultSet(session_, mem_context_->get_arena_allocator());
    result_set_->set_is_inner_result_set(true);
    is_inited_ = true;
  }
  return ret;
}

ObInnerSQLResult::~ObInnerSQLResult()
{
  close();
  if (result_set_ != nullptr) {
    result_set_->~ObResultSet();
  }
}

int ObInnerSQLResult::open()
{
  int ret = OB_SUCCESS;
  execute_start_ts_ = ObTimeUtility::current_time();
  if (OB_UNLIKELY(!is_inited_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not init", K(ret));
  } else {
    share::CompatModeGuard g(compat_mode_);
    WITH_CONTEXT(mem_context_)
    {
      if (opened_) {
        ret = OB_INIT_TWICE;
        LOG_WARN("result set already open", K(ret));
      } else if (OB_FAIL(result_set_->sync_open())) {
        ObResultSet::refresh_location_cache(result_set_->get_exec_context().get_task_exec_ctx(), true, ret);
        LOG_WARN("open result set failed", K(ret));
        // move after precess_retry().
        //        result_set_->close();
      } else {
        opened_ = true;
      }
    }
  }
  execute_end_ts_ = ObTimeUtility::current_time();
  return ret;
}

int ObInnerSQLResult::close()
{
  int ret = OB_SUCCESS;
  // close can be executed too if result set not open.
  if (opened_) {
    // opened=true imply is_inited=true
    if (OB_FAIL(inner_close(false))) {
      LOG_WARN("result set close failed", K(ret));
    }
  }
  column_map_.clear();
  column_indexed_ = false;
  return ret;
}

int ObInnerSQLResult::force_close(bool need_retry)
{
  UNUSED(need_retry);
  int ret = OB_SUCCESS;
  if (OB_FAIL(inner_close(false))) {
    LOG_WARN("result set close failed", K(ret));
  }
  column_map_.clear();
  column_indexed_ = false;
  return ret;
}

int ObInnerSQLResult::inner_close(bool need_retry)
{
  int ret = OB_SUCCESS;
  share::CompatModeGuard g(compat_mode_);
  LOG_DEBUG("compat_mode_", K(ret), K(compat_mode_), K(lbt()));
  WITH_CONTEXT(mem_context_)
  {
    if (OB_FAIL(result_set_->close(need_retry))) {
      ObResultSet::refresh_location_cache(result_set_->get_exec_context().get_task_exec_ctx(), true, ret);
      LOG_WARN("result set close failed", K(ret), K(need_retry));
    }
  }
  opened_ = false;
  return ret;
}

int ObInnerSQLResult::next()
{
  int ret = OB_SUCCESS;
  LOG_DEBUG("compat_mode_", K(ret), K(compat_mode_), K(lbt()));
  row_ = NULL;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else {
    share::CompatModeGuard g(compat_mode_);
    WITH_CONTEXT(mem_context_)
    {
      if (OB_FAIL(result_set_->get_next_row(row_))) {
        if (OB_ITER_END != ret) {
          ObResultSet::refresh_location_cache(result_set_->get_exec_context().get_task_exec_ctx(), true, ret);
          LOG_WARN("get next row failed", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObInnerSQLResult::build_column_map() const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (!column_map_created_) {
    if (OB_FAIL(column_map_.create(
            COLUMN_MAP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_SQL_COLUMN_MAP, ObModIds::OB_HASH_NODE_SQL_COLUMN_MAP))) {
      LOG_WARN("create hash table failed", K(ret), LITERAL_K(COLUMN_MAP_BUCKET_NUM));
    } else {
      column_map_created_ = true;
    }
  }
  if (OB_SUCC(ret)) {
    column_map_.clear();
    const ColumnsFieldIArray* fields = result_set_->get_field_columns();
    if (OB_ISNULL(fields)) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("invalid argument", K(ret), K(fields));
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < fields->count(); ++i) {
      if (nullptr == fields->at(i).cname_) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("null field name", K(ret), "field", fields->at(i));
      } else {
        if (OB_FAIL(column_map_.set_refactored(fields->at(i).cname_, i))) {
          // ignore duplicate column name
          if (OB_HASH_EXIST == ret) {
            ret = OB_SUCCESS;
          } else {
            LOG_WARN("add column name to column map failed", K(ret));
          }
        }
      }
    }
  }

  if (OB_SUCC(ret)) {
    column_indexed_ = true;
  }

  return ret;
}

int ObInnerSQLResult::find_idx(const char* col_name, int64_t& idx) const
{
  idx = OB_INVALID_INDEX;
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (nullptr == col_name) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(col_name));
  } else {
    if (OB_UNLIKELY(!column_indexed_)) {
      if (OB_FAIL(build_column_map())) {
        LOG_WARN("build column map failed", K(ret));
      }
    }
    if (OB_SUCC(ret)) {
      ret = column_map_.get_refactored(ObString::make_string(col_name), idx);
      if (OB_SUCCESS != ret && OB_HASH_NOT_EXIST != ret) {
        LOG_WARN("get index from hash failed", K(ret), K(col_name));
      } else if (OB_HASH_NOT_EXIST == ret) {
        ret = OB_ENTRY_NOT_EXIST;
      } else if (OB_INVALID_INDEX == idx) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("invalid index", K(ret), K(idx));
      }
    }
  }
  return ret;
}

#define DEF_GET_VALUE_BY_INDEX_IMPL(name, obj_name, type)                                       \
  int ObInnerSQLResult::name(const int64_t col_idx, type& val) const                            \
  {                                                                                             \
    int ret = OB_SUCCESS;                                                                       \
    if (!opened_) {                                                                             \
      ret = OB_NOT_INIT;                                                                        \
      LOG_WARN("not opened", K(ret));                                                           \
    } else if (NULL == row_) {                                                                  \
      ret = OB_ERR_UNEXPECTED;                                                                  \
      LOG_WARN("row is null", K(ret));                                                          \
    } else if (col_idx >= (NULL == row_->projector_ ? row_->count_ : row_->projector_size_)) {  \
      ret = OB_SIZE_OVERFLOW;                                                                   \
      LOG_WARN("column index overflow", K(ret), K(col_idx), "row", *row_);                      \
    } else {                                                                                    \
      const int64_t idx = (NULL != row_->projector_ ? row_->projector_[col_idx] : col_idx);     \
      if (idx < 0 || idx >= row_->count_) {                                                     \
        ret = OB_ERR_UNEXPECTED;                                                                \
        LOG_WARN("invalid index", K(ret), K(idx), "cell count", row_->count_);                  \
      } else {                                                                                  \
        const ObObj& obj = row_->cells_[idx];                                                   \
        if (OB_FAIL(check_extend_value(obj))) {                                                 \
          LOG_DEBUG("check extend value failed", K(ret));                                       \
        } else if (OB_FAIL(obj.obj_name(val))) {                                                \
          LOG_WARN("get " #type " value from obj failed", K(ret), K(obj), K(col_idx), K_(row)); \
        }                                                                                       \
      }                                                                                         \
    }                                                                                           \
    return ret;                                                                                 \
  }

#define DEF_GET_VALUE_BY_INDEX(name, type) DEF_GET_VALUE_BY_INDEX_IMPL(name, name, type)

// DEF_GET_VALUE_BY_INDEX(get_int, int64_t);
DEF_GET_VALUE_BY_INDEX_IMPL(get_uint, get_uint64, uint64_t);
DEF_GET_VALUE_BY_INDEX(get_datetime, int64_t);
DEF_GET_VALUE_BY_INDEX(get_date, int32_t);
DEF_GET_VALUE_BY_INDEX(get_time, int64_t);
DEF_GET_VALUE_BY_INDEX(get_year, uint8_t);

int ObInnerSQLResult::get_timestamp(const int64_t col_idx, const common::ObTimeZoneInfo* tz_info, int64_t& val) const
{
  UNUSED(tz_info);
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(!opened_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_UNLIKELY(NULL == row_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("row is null", K(ret));
  } else if (OB_UNLIKELY(col_idx >= (NULL == row_->projector_ ? row_->count_ : row_->projector_size_))) {
    ret = OB_SIZE_OVERFLOW;
    LOG_WARN("column index overflow", K(ret), K(col_idx), "row", *row_);
  } else {
    const int64_t idx = (NULL != row_->projector_ ? row_->projector_[col_idx] : col_idx);
    if (OB_UNLIKELY(idx < 0) || OB_UNLIKELY(idx >= row_->count_)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("invalid index", K(ret), K(idx), "cell count", row_->count_);
    } else {
      const ObObj& obj = row_->cells_[idx];
      if (OB_FAIL(check_extend_value(obj))) {
        LOG_DEBUG("check extend value failed", K(ret));
      } else {
        val = obj.get_timestamp();
      }
    }
  }
  return ret;
}

int ObInnerSQLResult::get_otimestamp_value(const int64_t col_idx, const common::ObTimeZoneInfo& tz_info,
    const common::ObObjType type, common::ObOTimestampData& otimestamp_val) const
{
  UNUSED(tz_info);
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(!opened_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_UNLIKELY(NULL == row_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("row is null", K(ret));
  } else if (OB_UNLIKELY(col_idx >= (NULL == row_->projector_ ? row_->count_ : row_->projector_size_))) {
    ret = OB_SIZE_OVERFLOW;
    LOG_WARN("column index overflow", K(ret), K(col_idx), "row", *row_);
  } else {
    const int64_t idx = (NULL != row_->projector_ ? row_->projector_[col_idx] : col_idx);
    if (OB_UNLIKELY(idx < 0) || OB_UNLIKELY(idx >= row_->count_)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("invalid index", K(ret), K(idx), "cell count", row_->count_);
    } else {
      const ObObj& obj = row_->cells_[idx];
      if (OB_UNLIKELY(type != obj.get_type())) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("type is mismatch", K(type), K(obj), K(ret));
      } else if (OB_FAIL(check_extend_value(obj))) {
        LOG_DEBUG("check extend value failed", K(ret));
      } else {
        otimestamp_val = obj.get_otimestamp_value();
      }
    }
  }
  return ret;
}

int ObInnerSQLResult::get_timestamp_tz(
    const int64_t col_idx, const common::ObTimeZoneInfo& tz_info, common::ObOTimestampData& otimestamp_val) const
{
  return get_otimestamp_value(col_idx, tz_info, ObTimestampTZType, otimestamp_val);
}

int ObInnerSQLResult::get_timestamp_ltz(
    const int64_t col_idx, const common::ObTimeZoneInfo& tz_info, common::ObOTimestampData& otimestamp_val) const
{
  return get_otimestamp_value(col_idx, tz_info, ObTimestampLTZType, otimestamp_val);
}

int ObInnerSQLResult::get_timestamp_nano(
    const int64_t col_idx, const common::ObTimeZoneInfo& tz_info, common::ObOTimestampData& otimestamp_val) const
{
  return get_otimestamp_value(col_idx, tz_info, ObTimestampNanoType, otimestamp_val);
}

DEF_GET_VALUE_BY_INDEX(get_interval_ym, ObIntervalYMValue);
DEF_GET_VALUE_BY_INDEX(get_interval_ds, ObIntervalDSValue);

int ObInnerSQLResult::get_bool(const int64_t col_idx, bool& bool_val) const
{
  int64_t v = 0;
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_INVALID_INDEX == col_idx) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(col_idx));
  } else if (OB_FAIL(get_int(col_idx, v))) {
    LOG_WARN("get int value failed", K(ret), K(col_idx));
  } else {
    bool_val = v;
  }
  return ret;
}

DEF_GET_VALUE_BY_INDEX(get_varchar, ObString);
DEF_GET_VALUE_BY_INDEX(get_raw, ObString);
DEF_GET_VALUE_BY_INDEX(get_nvarchar2, ObString);
DEF_GET_VALUE_BY_INDEX(get_nchar, ObString);
DEF_GET_VALUE_BY_INDEX(get_float, float);
DEF_GET_VALUE_BY_INDEX(get_double, double);

int ObInnerSQLResult::get_int(const int64_t col_idx, int64_t& int_val) const
{
  int ret = OB_SUCCESS;
  const ObObj* obj = NULL;
  if (OB_FAIL(get_obj(col_idx, obj))) {
    LOG_WARN("get obj error", K(ret));
  } else if (OB_ISNULL(obj)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get a invalud obj", K(col_idx), K(obj), K(ret));
  } else if (OB_UNLIKELY(ObIntTC != obj->get_type_class())) {
    ret = OB_OBJ_TYPE_ERROR;
    LOG_WARN("invalid input type", K(ret), K(*obj));
  } else {
    int_val = obj->get_int();
  }
  return ret;
}

DEF_GET_VALUE_BY_INDEX_IMPL(get_number_impl, get_number, number::ObNumber);
DEF_GET_VALUE_BY_INDEX_IMPL(get_urowid_impl, get_urowid, ObURowIDData);

#undef DEF_GET_VALUE_BY_INDEX
#undef DEF_GET_VALUE_BY_INDEX_IMPL

int ObInnerSQLResult::get_type(const int64_t col_idx, ObObjMeta& type) const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (NULL == row_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("row is null", K(ret));
  } else if (col_idx >= (NULL == row_->projector_ ? row_->count_ : row_->projector_size_)) {
    ret = OB_SIZE_OVERFLOW;
    LOG_WARN("column index overflow", K(ret), K(col_idx), "row", *row_);
  } else {
    const int64_t idx = (NULL != row_->projector_ ? row_->projector_[col_idx] : col_idx);
    if (idx < 0 || idx >= row_->count_) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("invalid index", K(ret), K(idx), "cell count", row_->count_);
    } else {
      const ObObj& obj = row_->cells_[idx];
      type = obj.get_meta();
    }
  }
  return ret;
}

int ObInnerSQLResult::get_obj(
    const int64_t col_idx, ObObj& obj, const ObTimeZoneInfo* tz_info, ObIAllocator* allocator) const
{
  UNUSED(tz_info);
  UNUSED(allocator);
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (NULL == row_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("row is null", K(ret));
  } else if (col_idx >= (NULL == row_->projector_ ? row_->count_ : row_->projector_size_)) {
    ret = OB_SIZE_OVERFLOW;
    LOG_WARN("column index overflow", K(ret), K(col_idx), "row", *row_);
  } else {
    const int64_t idx = (NULL != row_->projector_ ? row_->projector_[col_idx] : col_idx);
    if (idx < 0 || idx >= row_->count_) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("invalid index", K(ret), K(idx), "cell count", row_->count_);
    } else {
      obj = row_->cells_[idx];
    }
  }
  return ret;
}

#define DEF_GET_VALUE_BY_NAME(name, type)                           \
  int ObInnerSQLResult::name(const char* col_name, type& val) const \
  {                                                                 \
    int ret = OB_SUCCESS;                                           \
    int64_t idx = OB_INVALID_INDEX;                                 \
    if (!opened_) {                                                 \
      ret = OB_NOT_INIT;                                            \
      LOG_WARN("not opened", K(ret));                               \
    } else if (NULL == col_name) {                                  \
      ret = OB_INVALID_ARGUMENT;                                    \
      LOG_WARN("column name can not be NULL", K(ret));              \
    } else if (OB_FAIL(find_idx(col_name, idx))) {                  \
      if (OB_ENTRY_NOT_EXIST == ret) {                              \
        ret = OB_ERR_COLUMN_NOT_FOUND;                              \
      } else {                                                      \
        LOG_WARN("find column index failed", K(ret), K(col_name));  \
      }                                                             \
    } else if (OB_INVALID_INDEX == idx) {                           \
      ret = OB_ERR_UNEXPECTED;                                      \
      LOG_WARN("invalid index returned", K(ret), K(idx));           \
    } else if (OB_FAIL(name(idx, val))) {                           \
      if (OB_ERR_NULL_VALUE != ret) {                               \
        LOG_WARN(#name " failed", K(ret), K(idx));                  \
      }                                                             \
    }                                                               \
    return ret;                                                     \
  }

DEF_GET_VALUE_BY_NAME(get_int, int64_t);
DEF_GET_VALUE_BY_NAME(get_uint, uint64_t);
DEF_GET_VALUE_BY_NAME(get_datetime, int64_t);
DEF_GET_VALUE_BY_NAME(get_date, int32_t);
DEF_GET_VALUE_BY_NAME(get_time, int64_t);
DEF_GET_VALUE_BY_NAME(get_year, uint8_t);
DEF_GET_VALUE_BY_NAME(get_bool, bool);
DEF_GET_VALUE_BY_NAME(get_varchar, ObString);
DEF_GET_VALUE_BY_NAME(get_raw, ObString);
DEF_GET_VALUE_BY_NAME(get_float, float);
DEF_GET_VALUE_BY_NAME(get_double, double);
DEF_GET_VALUE_BY_NAME(get_number_impl, number::ObNumber);
DEF_GET_VALUE_BY_NAME(get_type, ObObjMeta);
DEF_GET_VALUE_BY_NAME(get_obj, ObObj);
DEF_GET_VALUE_BY_NAME(get_interval_ym, ObIntervalYMValue);
DEF_GET_VALUE_BY_NAME(get_interval_ds, ObIntervalDSValue);
DEF_GET_VALUE_BY_NAME(get_nvarchar2, ObString);
DEF_GET_VALUE_BY_NAME(get_nchar, ObString);
DEF_GET_VALUE_BY_NAME(get_urowid_impl, ObURowIDData);
#undef DEF_GET_VALUE_BY_NAME

int ObInnerSQLResult::get_timestamp(const char* col_name, const common::ObTimeZoneInfo* tz_info, int64_t& val) const
{
  UNUSED(tz_info);
  int ret = OB_SUCCESS;
  int64_t idx = OB_INVALID_INDEX;
  if (OB_UNLIKELY(!opened_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_UNLIKELY(NULL == col_name)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("column name can not be NULL", K(ret));
  } else if (OB_FAIL(find_idx(col_name, idx))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      ret = OB_ERR_COLUMN_NOT_FOUND;
    } else {
      LOG_WARN("find column index failed", K(ret), K(col_name));
    }
  } else if (OB_UNLIKELY(OB_INVALID_INDEX == idx)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid index returned", K(ret), K(idx));
  } else if (OB_FAIL(get_timestamp(idx, tz_info, val))) {
    if (OB_ERR_NULL_VALUE != ret) {
      LOG_WARN("get_timestamp failed", K(ret), K(idx));
    }
  }
  return ret;
}

int ObInnerSQLResult::get_otimestamp_value(const char* col_name, const common::ObTimeZoneInfo& tz_info,
    const common::ObObjType type, common::ObOTimestampData& otimestamp_val) const
{
  UNUSED(tz_info);
  int ret = OB_SUCCESS;
  int64_t idx = OB_INVALID_INDEX;
  if (OB_UNLIKELY(!opened_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_UNLIKELY(NULL == col_name)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("column name can not be NULL", K(ret));
  } else if (OB_FAIL(find_idx(col_name, idx))) {
    if (OB_ENTRY_NOT_EXIST == ret) {
      ret = OB_ERR_COLUMN_NOT_FOUND;
    } else {
      LOG_WARN("find column index failed", K(ret), K(col_name));
    }
  } else if (OB_UNLIKELY(OB_INVALID_INDEX == idx)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid index returned", K(ret), K(idx));
  } else if (OB_FAIL(get_otimestamp_value(idx, tz_info, type, otimestamp_val))) {
    if (OB_ERR_NULL_VALUE != ret) {
      LOG_WARN("get_otimestamp failed", K(ret), K(idx));
    }
  }
  return ret;
}

int ObInnerSQLResult::get_timestamp_tz(
    const char* col_name, const common::ObTimeZoneInfo& tz_info, common::ObOTimestampData& otimestamp_val) const
{
  return get_otimestamp_value(col_name, tz_info, ObTimestampTZType, otimestamp_val);
}

int ObInnerSQLResult::get_timestamp_ltz(
    const char* col_name, const common::ObTimeZoneInfo& tz_info, common::ObOTimestampData& otimestamp_val) const
{
  return get_otimestamp_value(col_name, tz_info, ObTimestampLTZType, otimestamp_val);
}

int ObInnerSQLResult::get_timestamp_nano(
    const char* col_name, const common::ObTimeZoneInfo& tz_info, common::ObOTimestampData& otimestamp_val) const
{
  return get_otimestamp_value(col_name, tz_info, ObTimestampNanoType, otimestamp_val);
}

int ObInnerSQLResult::get_number(const int64_t col_idx, common::number::ObNumber& nmb_val) const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_INVALID_INDEX == col_idx) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(col_idx));
  } else if (OB_FAIL(get_number_impl(col_idx, nmb_val))) {
    LOG_WARN("get number impl failed", K(ret), K(col_idx));
  }
  return ret;
}

int ObInnerSQLResult::get_number(const char* col_name, common::number::ObNumber& nmb_val) const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (NULL == col_name) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(col_name));
  } else if (OB_FAIL(get_number_impl(col_name, nmb_val))) {
    LOG_WARN("get number impl failed", K(ret), K(col_name));
  }
  return ret;
}

int ObInnerSQLResult::inner_get_number(const int64_t col_idx, number::ObNumber& nmb_val, IAllocator& allocator) const
{
  UNUSED(allocator);
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_INVALID_INDEX == col_idx) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(col_idx));
  } else if (OB_FAIL(get_number_impl(col_idx, nmb_val))) {
    LOG_WARN("get number impl failed", K(ret), K(col_idx));
  }
  return ret;
}

int ObInnerSQLResult::inner_get_number(const char* col_name, number::ObNumber& nmb_val, IAllocator& allocator) const
{
  UNUSED(allocator);
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (NULL == col_name) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), KP(col_name));
  } else if (OB_FAIL(get_number_impl(col_name, nmb_val))) {
    LOG_WARN("get number impl failed", K(ret), K(col_name));
  }
  return ret;
}

int ObInnerSQLResult::inner_get_urowid(
    const int64_t col_idx, ObURowIDData& urowid_data, ObIAllocator& /* not used */) const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_FAIL(get_urowid_impl(col_idx, urowid_data))) {
    LOG_WARN("failed to get urowid", K(ret));
  }
  return ret;
}

int ObInnerSQLResult::inner_get_urowid(
    const char* col_name, ObURowIDData& urowid_data, ObIAllocator& /* no used */) const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_FAIL(get_urowid_impl(col_name, urowid_data))) {
    LOG_WARN("failed to get urowid data", K(ret));
  }
  return ret;
}

int ObInnerSQLResult::get_lob_locator(const int64_t col_idx, ObLobLocator*& lob_locator) const
{
  int ret = OB_SUCCESS;
  if (OB_FAIL(get_lob_locator_impl(col_idx, lob_locator))) {
    LOG_WARN("get lob locator impl failed", K(ret), K(col_idx));
  }
  return ret;
}

int ObInnerSQLResult::get_lob_locator(const char* col_name, ObLobLocator*& lob_locator) const
{
  int ret = OB_SUCCESS;
  if (OB_FAIL(get_lob_locator_impl(col_name, lob_locator))) {
    LOG_WARN("get lob locator impl failed", K(ret), K(col_name));
  }
  return ret;
}

int ObInnerSQLResult::inner_get_lob_locator(
    const int64_t col_idx, ObLobLocator*& lob_locator, ObIAllocator& allocator) const
{
  UNUSED(allocator);
  int ret = OB_SUCCESS;
  if (OB_FAIL(get_lob_locator_impl(col_idx, lob_locator))) {
    LOG_WARN("get lob locator impl failed", K(ret), K(col_idx));
  }
  return ret;
}

int ObInnerSQLResult::inner_get_lob_locator(
    const char* col_name, ObLobLocator*& lob_locator, ObIAllocator& allocator) const
{
  UNUSED(allocator);
  int ret = OB_SUCCESS;
  if (OB_FAIL(get_lob_locator_impl(col_name, lob_locator))) {
    LOG_WARN("get lob locator impl failed", K(ret), K(col_name));
  }
  return ret;
}

int ObInnerSQLResult::get_lob_locator_impl(const int64_t col_idx, ObLobLocator*& lob_locator) const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (OB_ISNULL(row_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("row is null", K(ret));
  } else if (OB_INVALID_INDEX == col_idx) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(ret), K(col_idx));
  } else if (col_idx >= (NULL == row_->projector_ ? row_->count_ : row_->projector_size_)) {
    ret = OB_SIZE_OVERFLOW;
    LOG_WARN("column index overflow", K(ret), K(col_idx), "row", *row_);
  } else {
    const int64_t idx = (NULL != row_->projector_ ? row_->projector_[col_idx] : col_idx);
    if (idx < 0 || idx >= row_->count_) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("invalid index", K(ret), K(idx), "cell count", row_->count_);
    } else {
      const ObObj& obj = row_->cells_[idx];
      if (OB_FAIL(check_extend_value(obj))) {
        LOG_DEBUG("check extend value failed", K(ret));
      } else if (OB_FAIL(obj.get_lob_locator(lob_locator))) {
        LOG_WARN("get lob locator value from obj failed", K(ret), K(obj), K(col_idx), K_(row));
      }
    }
  }
  return ret;
}

int ObInnerSQLResult::get_lob_locator_impl(const char* col_name, ObLobLocator*& lob_locator) const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else {
    int64_t idx = OB_INVALID_INDEX;
    if (OB_ISNULL(col_name)) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("column name can not be NULL", K(ret));
    } else if (OB_FAIL(find_idx(col_name, idx))) {
      if (OB_ENTRY_NOT_EXIST == ret) {
        ret = OB_ERR_COLUMN_NOT_FOUND;
      } else {
        LOG_WARN("find column index failed", K(ret), K(col_name));
      }
    } else if (OB_INVALID_INDEX == idx) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("invalid index returned", K(ret), K(idx));
    } else if (OB_FAIL(get_lob_locator_impl(idx, lob_locator))) {
      if (OB_ERR_NULL_VALUE != ret) {
        LOG_WARN("inner get lob locator failed", K(ret), K(idx));
      }
    }
  }
  return ret;
}

int ObInnerSQLResult::get_obj(const int64_t col_idx, const common::ObObj*& result) const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else if (NULL == row_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("row is null", K(ret));
  } else if (col_idx >= (NULL == row_->projector_ ? row_->count_ : row_->projector_size_)) {
    ret = OB_SIZE_OVERFLOW;
    LOG_WARN("column index overflow", K(ret), K(col_idx), "row", *row_);
  } else {
    const int64_t idx = (NULL != row_->projector_ ? row_->projector_[col_idx] : col_idx);
    if (idx < 0 || idx >= row_->count_) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("invalid index", K(ret), K(idx), "cell count", row_->count_);
    } else {
      const ObObj& obj = row_->cells_[idx];
      if (OB_FAIL(check_extend_value(obj))) {
        LOG_DEBUG("check extend value failed", K(ret));
      } else {
        result = &obj;
      }
    }
  }
  return ret;
}

int ObInnerSQLResult::print_info() const
{
  int ret = OB_SUCCESS;
  if (!opened_) {
    ret = OB_NOT_INIT;
    LOG_WARN("not opened", K(ret));
  } else {
    LOG_INFO("result", K_(result_set));
  }
  return ret;
}
}  // end of namespace observer
}  // end of namespace oceanbase
