/**
 * 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_table_api_row_iterator.h"
#include "ob_table_rpc_processor.h"
#include "observer/ob_service.h"
#include "sql/ob_sql_utils.h"
#include "sql/engine/expr/ob_expr_add.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "storage/ob_partition_service.h"

using namespace oceanbase::common;
using namespace oceanbase::table;
using namespace oceanbase::share;
using namespace oceanbase::share::schema;
using namespace oceanbase::sql;


namespace oceanbase {
namespace observer {

/**
 * -------------------------------------------------------ObTableApiRowIterator--------------------------------------------------------
 */
ObTableApiRowIterator::ObTableApiRowIterator()
  : part_service_(NULL),
    schema_service_(NULL),
    ctx_(NULL),
    schema_guard_(),
    table_schema_(NULL),
    table_id_(0),
    tenant_id_(0),
    schema_version_(0),
    rowkey_column_cnt_(0),
    properties_(),
    column_ids_(),
    columns_type_(),
    column_descs_(),
    row_objs_(),
    missing_default_objs_(),
    generate_column_exprs_(),
    generate_column_idxs_(),
    expr_ctx_(),
    row_(),
    stmt_allocator_(ObModIds::TABLE_BATCH_OPERATION),
    row_allocator_(ObModIds::TABLE_BATCH_OPERATION),
    entity_(NULL),
    has_generate_column_(false),
    is_inited_(false)
{
}

ObTableApiRowIterator::~ObTableApiRowIterator()
{
  if (has_generate_column_) {
    sql::ObSQLUtils::destruct_default_expr_context(expr_ctx_);
    has_generate_column_ = false;
  }
}

int ObTableApiRowIterator::init(
    storage::ObPartitionService &partition_service,
    share::schema::ObMultiVersionSchemaService &schema_service,
    ObTableServiceCtx &ctx)
{
  int ret = OB_SUCCESS;

  if (is_inited_) {
    ret = OB_INIT_TWICE;
    LOG_WARN("The table api row iterator has been inited, ", K(ret));
  } else if (OB_FAIL(schema_service.get_schema_guard(schema_guard_))) {
    LOG_WARN("failed to get schema guard", K(ret));
  } else if (OB_FAIL(schema_guard_.get_table_schema(ctx.param_.table_id_, table_schema_))) {
    LOG_WARN("get table schema failed", K(ctx.param_.table_id_), K(ret));
  } else if (OB_ISNULL(table_schema_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("NULL ptr", K(ret), K(table_schema_));
  } else if (OB_FAIL(check_table_supported(table_schema_))) {
    LOG_WARN("check table support failed", K(ret));
  } else {
    table_id_ = ctx.param_.table_id_;
    tenant_id_ = extract_tenant_id(table_id_);
    schema_version_ = table_schema_->get_schema_version();
    rowkey_column_cnt_ = table_schema_->get_rowkey_column_num();
    part_service_ = &partition_service;
    ctx_ = &ctx;
    stmt_allocator_.set_tenant_id(tenant_id_);
    row_allocator_.set_tenant_id(tenant_id_);
    is_inited_ = true;
  }
  return ret;
}

void ObTableApiRowIterator::reset()
{
  if (has_generate_column_) {
    sql::ObSQLUtils::destruct_default_expr_context(expr_ctx_);
  }
  part_service_ = NULL;
  schema_service_ = NULL;
  ctx_ = NULL;
  table_schema_ = NULL;
  table_id_ = 0;
  tenant_id_ = 0;
  schema_version_ = 0;
  rowkey_column_cnt_ = 0;
  properties_.reset();
  column_ids_.reset();
  columns_type_.reset();
  column_descs_.reset();
  row_objs_.reset();
  missing_default_objs_.reset();
  generate_column_exprs_.reset();
  generate_column_idxs_.reset();
  stmt_allocator_.reset();
  row_allocator_.reset();
  entity_ = NULL;
  has_generate_column_ = false;
  is_inited_ = false;
}

int ObTableApiRowIterator::check_row(ObNewRow &row)
{
  int ret = OB_SUCCESS;
  const int64_t N = columns_type_.count();
  for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) {
    if (OB_FAIL(check_column_type(columns_type_.at(i), row.get_cell(i)))) {
      LOG_WARN("Fail to check column type, ", K(ret), K(i), K(columns_type_.at(i)), K(row.get_cell(i)));
    }
  } // end for
  return ret;
}

int ObTableApiRowIterator::entity_to_row(const ObITableEntity &entity, ObIArray<ObObj> &row)
{
  int ret = OB_SUCCESS;
  ObObj obj;
  const int64_t N = entity.get_rowkey_size();
  row.reuse();
  for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) {
    if (OB_FAIL(entity.get_rowkey_value(i, obj))) {
      LOG_WARN("failed to get rowkey value", K(ret), K(i));
    } else if (OB_FAIL(row.push_back(obj))) {
      LOG_WARN("failed to push", K(ret), K(i), K(obj));
    }
  } // end for
  if (OB_SUCC(ret)) {
    if (OB_FAIL(entity.get_properties_values(row))) {
      LOG_WARN("failed to get properties values", K(ret));
    }
  }
  return ret;
}

int ObTableApiRowIterator::fill_get_param(
    ObTableServiceCtx &ctx,
    const ObTableOperationType::Type op_type,
    ObRowkey &rowkey,
    storage::ObTableScanParam &scan_param,
    share::schema::ObTableParam &table_param)
{
  int ret = OB_SUCCESS;
  scan_param.key_ranges_.reset();
  if (OB_FAIL(fill_range(rowkey, scan_param.key_ranges_))) {
    LOG_WARN("Fail to fill range, ", K(ret));
  } else if (OB_FAIL(fill_flag(ctx, scan_param))) {
    LOG_WARN("Fail to fill param flag, ", K(ret));
  } else if (OB_FAIL(table_param.convert(*table_schema_, *table_schema_, column_ids_, false /*index back*/))) {
    LOG_WARN("failed to convert table param", K(ret));
  } else {
    if (ObTableOperationType::DEL == op_type
        || ObTableOperationType::UPDATE == op_type
        || ObTableOperationType::INSERT_OR_UPDATE == op_type
        || ObTableOperationType::REPLACE == op_type
        || ObTableOperationType::INCREMENT == op_type
        || ObTableOperationType::APPEND == op_type) {
      scan_param.for_update_ = true;
    }
    scan_param.table_param_ = &table_param;
    LOG_DEBUG("Success to fill get param.");
  }
  return ret;
}

int ObTableApiRowIterator::fill_multi_get_param(
    ObTableServiceCtx &ctx,
    const ObTableBatchOperation &batch_operation,
    storage::ObTableScanParam &scan_param,
    share::schema::ObTableParam &table_param)
{
  int ret = OB_SUCCESS;
  scan_param.key_ranges_.reset();
  const int64_t N = batch_operation.count();
  if (N <= 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("Invalid argument, ", K(ret), K(N));
  }

  for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) {
    ObRowkey rowkey = const_cast<ObITableEntity &>(batch_operation.at(i).entity()).get_rowkey();
    if (OB_FAIL(fill_range(rowkey, scan_param.key_ranges_))) {
      LOG_WARN("Fail to fill range, ", K(ret), K(i));
    }
  } // end for

  if (OB_SUCC(ret)) {
    if (OB_FAIL(fill_flag(ctx, scan_param))) {
      LOG_WARN("Fail to fill param flag, ", K(ret));
    } else if (OB_FAIL(table_param.convert(*table_schema_, *table_schema_, column_ids_, false /*index back*/))) {
      LOG_WARN("failed to convert table param", K(ret));
    } else {
      const ObTableOperation &table_operation = batch_operation.at(0);
      if (ObTableOperationType::DEL == table_operation.type()
          || ObTableOperationType::UPDATE == table_operation.type()
          || ObTableOperationType::INSERT_OR_UPDATE == table_operation.type()
          || ObTableOperationType::REPLACE == table_operation.type()
          || ObTableOperationType::INCREMENT == table_operation.type()
          || ObTableOperationType::APPEND == table_operation.type()) {
        scan_param.for_update_ = true;
      }
      scan_param.table_param_ = &table_param;
    }
  }
  return ret;
}

int ObTableApiRowIterator::fill_generate_columns(common::ObNewRow &row)
{
  int ret = OB_SUCCESS;
  ObISqlExpression *expr = NULL;
  const int64_t N = generate_column_exprs_.count();
  int64_t col_idx = 0;
  for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) {
    if (OB_FAIL(generate_column_exprs_.at(i, expr))) {
      LOG_WARN("Fail to get generate column expr, ", K(ret), K(i));
    } else if (OB_FAIL(generate_column_idxs_.at(i, col_idx))) {
      LOG_WARN("Fail to get generate column idx, ", K(ret), K(i));
    } else if (NULL != expr) {
      if (OB_FAIL(sql::ObSQLUtils::calc_sql_expression(
          expr,
          *table_schema_,
          column_descs_,
          row,
          row_allocator_,
          expr_ctx_,
          row.cells_[col_idx]))) {
        LOG_WARN("failed to calc expr from str", K(column_descs_), K(ret));
      } else {
        LOG_DEBUG("Success to calc expr, ", K(col_idx), K(row.cells_[col_idx]));
      }
    }
  }
  return ret;
}


int ObTableApiRowIterator::cons_all_columns(const ObITableEntity &entity, const bool ignore_missing_column)
{
  int ret = OB_SUCCESS;
  const ObRowkeyInfo &rowkey_info = table_schema_->get_rowkey_info();
  if (OB_FAIL(entity.get_properties_names(properties_))) {
    LOG_WARN("failed to get properties, ", K(ret));
  } else if (OB_FAIL(rowkey_info.get_column_ids(column_ids_))) {
    LOG_WARN("failed to get rowkey column ids", K(ret), K(rowkey_info));
  } else {
    const schema::ObColumnSchemaV2 *column_schema = NULL;
    uint64_t column_id = OB_INVALID_ID;

    //add rowkey column
    const int64_t rowkey_cnt = rowkey_info.get_size();
    for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_cnt; ++i) {
      if (OB_FAIL(rowkey_info.get_column_id(i, column_id))) {
        LOG_WARN("failed to get column id", K(ret), K(i));
      } else if (NULL == (column_schema = table_schema_->get_column_schema(column_id))) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("rowkey column not exists", K(ret), K(column_id));
      } else if (OB_FAIL(add_column_type(*column_schema))) {
        LOG_WARN("Fail to add column type, ", K(ret));
      }
    } // end for

    //add property column
    const int64_t property_cnt = properties_.count();
    for (int64_t i = 0; OB_SUCC(ret) && i < property_cnt; ++i) {
      const ObString &cname = properties_.at(i);
      if (NULL == (column_schema = table_schema_->get_column_schema(cname))) {
        ret = OB_ERR_COLUMN_NOT_FOUND;
        LOG_WARN("column not exists", K(ret), K(cname));
      } else if (!ignore_missing_column && column_schema->is_generated_column()) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("Should not have generate columns, ", K(ret), K(cname));
      } else if (OB_FAIL(column_ids_.push_back(column_schema->get_column_id()))) {
        LOG_WARN("failed to add column id", K(ret));
      } else if (OB_FAIL(add_column_type(*column_schema))) {
        LOG_WARN("Fail to add column type, ", K(ret));
      }
    } // end for

    //add missing column
    if (OB_SUCC(ret) && !ignore_missing_column) {
      if (OB_FAIL(cons_missing_columns(entity))) {
        LOG_WARN("Fail to cons missing column, ", K(ret));
      }
    }
  }
  return ret;
}

int ObTableApiRowIterator::cons_missing_columns(const ObITableEntity &entity)
{
  int ret = OB_SUCCESS;
  has_generate_column_ = false;
  if (table_schema_->get_column_count() - table_schema_->get_rowkey_column_num() <= entity.get_properties_count()) {
    // no missing columns, do nothing
  } else {
    // some columns are missing
    ObTableSchema::const_column_iterator iter = NULL;
    ObTableSchema::const_column_iterator begin = table_schema_->column_begin();
    ObTableSchema::const_column_iterator end = table_schema_->column_end();
    ObObj obj;
    ObExprResType column_type;
    const schema::ObColumnSchemaV2 *column = NULL;
    for (iter = begin; OB_SUCC(ret) && iter != end; ++iter) {
      column = *iter;
      // skip all rowkeys
      if (OB_ISNULL(column)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("invalid column schema", K(column));
      } else if (!column->is_rowkey_column()) {
        if (OB_FAIL(entity.get_property(column->get_column_name_str(), obj))) {
          ret = OB_SUCCESS;
          // missing column
          obj = column->get_cur_default_value();
          if (OB_FAIL(missing_default_objs_.push_back(obj))) {
            LOG_WARN("Failed to push default obj, ", K(ret));
          } else if (OB_FAIL(column_ids_.push_back(column->get_column_id()))) {
            LOG_WARN("failed to add column id", K(ret));
          } else if (OB_FAIL(add_column_type(*column))) {
            LOG_WARN("Fail to add column type, ", K(ret));
          } else {
            if (column->is_generated_column()) {
              if (OB_FAIL(generate_column_idxs_.push_back(column_ids_.count() - 1))) {
                LOG_WARN("Failed to push generate column idx, ", K(ret));
              }
              has_generate_column_ = true;
            }
            LOG_DEBUG("add missing column", K(obj), K(column_type));
          }
        }
      } else {}
    } //end for

    //fill generate expression
    if (has_generate_column_) {
      generate_column_exprs_.reuse();
      uint64_t tenant_id = extract_tenant_id(table_schema_->get_table_id());
      if (OB_FAIL(sql::ObSQLUtils::make_default_expr_context(tenant_id, stmt_allocator_, expr_ctx_))) {
        LOG_WARN("failed to make default expr context ", K(ret));
      }

      for (iter = begin; OB_SUCC(ret) && iter != end; ++iter) {
        column = *iter;
        if (column->is_generated_column()) {
          ObISqlExpression *expr = NULL;
          obj = column->get_orig_default_value();
          if (OB_FAIL(sql::ObSQLUtils::make_generated_expression_from_str(
              obj.get_string(),
              *table_schema_,
              *column,
              column_descs_,
              stmt_allocator_,
              expr))) {
            STORAGE_LOG(WARN,
                        "failed to make sql expression",
                        K(obj.get_string()),
                        K(*table_schema_),
                        K(*column),
                        K(column_descs_),
                        K(ret));
          } else if (OB_FAIL(generate_column_exprs_.push_back(expr))) {
            STORAGE_LOG(WARN, "push back error", K(ret));
          } else {
            /*do nothing*/
          }

        }
      }
    }
  }
  return ret;
}


int ObTableApiRowIterator::add_column_type(const share::schema::ObColumnSchemaV2 &column_schema)
{
  int ret = OB_SUCCESS;
  ObExprResType column_type;
  ObColDesc column_desc;
  if (OB_FAIL(cons_column_type(column_schema, column_type))) {
    LOG_WARN("failed to cons column type", K(ret));
  } else if (OB_FAIL(columns_type_.push_back(column_type))) {
    LOG_WARN("failed to push back column type, ", K(ret));
  } else {
    column_desc.col_id_ = column_schema.get_column_id();
    column_desc.col_type_ = column_schema.get_meta_type();
    if (OB_FAIL(column_descs_.push_back(column_desc))) {
      LOG_WARN("failed to push back column desc, ", K(ret));
    }
  }
  return ret;
}

int ObTableApiRowIterator::cons_column_type(const schema::ObColumnSchemaV2 &column_schema, ObExprResType &column_type)
{
  int ret = OB_SUCCESS;
  column_type.set_type(column_schema.get_data_type());
  column_type.set_result_flag(ObRawExprUtils::calc_column_result_flag(column_schema));
  if (ob_is_string_type(column_schema.get_data_type())) {
    column_type.set_collation_type(column_schema.get_collation_type());
    column_type.set_collation_level(CS_LEVEL_IMPLICIT);
  } else {
    column_type.set_collation_type(CS_TYPE_BINARY);
    column_type.set_collation_level(CS_LEVEL_NUMERIC);
  }
  const ObAccuracy &accuracy = column_schema.get_accuracy();
  column_type.set_accuracy(accuracy);
  const bool is_zerofill = column_type.has_result_flag(ZEROFILL_FLAG);
  if (is_zerofill) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("modifing column with ZEROFILL flag is not supported", K(ret), K(column_schema));
  }
  return ret;
}


int ObTableApiRowIterator::check_table_supported(const ObTableSchema *table_schema)
{
  int ret = OB_SUCCESS;
  if (!table_schema->is_user_table()) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("table type not supported", K(ret),
             "table_name", table_schema->get_table_name_str(),
             "type", table_schema->get_table_type());
  }
  return ret;
}

int ObTableApiRowIterator::check_column_type(const ObExprResType &column_type, ObObj &obj)
{
  int ret = OB_SUCCESS;
  const bool is_not_nullable = column_type.has_result_flag(NOT_NULL_FLAG);
  const ObCollationType cs_type = column_type.get_collation_type();
  // 1. check nullable
  if (is_not_nullable && obj.is_null()) {
    ret = OB_BAD_NULL_ERROR;
  } else if (obj.is_null()) {
    // continue
  } else if (column_type.get_type() != obj.get_type()
             && !(ob_is_string_type(column_type.get_type()) && ob_is_string_type(obj.get_type()))) {
    // 2. data type mismatch
    ret = OB_OBJ_TYPE_ERROR;
    LOG_WARN("object type mismatch with column type", K(ret), K(column_type), K(obj));
  } else {
    // 3. check collation
    if (!ob_is_string_type(obj.get_type())) {
      // not string type, continue
    } else {
      if (cs_type == obj.get_collation_type()) {
        // same collation type
      } else if (cs_type == CS_TYPE_BINARY) {
        // any collation type can be compatible with cs_type_binary
        obj.set_collation_type(cs_type);
      } else if (ObCharset::charset_type_by_coll(cs_type) == ObCharset::charset_type_by_coll(obj.get_collation_type())) {
        // same charset, convert it
        obj.set_collation_type(cs_type);
      } else {
        ret = OB_ERR_COLLATION_MISMATCH;
        LOG_WARN("collation type mismatch with column", K(ret), K(column_type), K(obj));
      }
      if (OB_SUCC(ret)) {
        // convert obj type to the column type (char, varchar or text)
        obj.set_type(column_type.get_type());
      }
    }
    // 4. check accuracy
    if (OB_SUCC(ret)) {
      if (OB_FAIL(ob_obj_accuracy_check_only(column_type.get_accuracy(), cs_type, obj))) {
        LOG_WARN("accuracy check failed", K(ret), K(obj), K(column_type));
      }
    }
  }
  return ret;
}


int ObTableApiRowIterator::fill_range(const ObRowkey &key, ObIArray<common::ObNewRange> &ranges)
{
  int ret = OB_SUCCESS;
  ObNewRange range;

  if (key.get_obj_cnt() > rowkey_column_cnt_) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("wrong rowkey size", K(ret), K(key), K(columns_type_));
  } else {
    const int64_t N = key.get_obj_cnt();
    for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) {
      if (OB_FAIL(check_column_type(columns_type_.at(i), const_cast<ObObj&> (key.get_obj_ptr()[i])))) {
        LOG_WARN("Invalid column type, ", K(ret), K(i), K(columns_type_.at(i)), K(key.get_obj_ptr()[i]));
      }
    }

    if (OB_SUCC(ret)) {
      if (OB_FAIL(range.build_range(table_id_, key))) {
        LOG_WARN("fail to build key range", K(ret), K_(table_id), K(key));
      } else if (OB_FAIL(ranges.push_back(range))) {
        LOG_WARN("fail to push back key range", K(ret), K(range));
      } else {
      }
    }
  }

  return ret;
}

int ObTableApiRowIterator::fill_flag(ObTableServiceCtx &ctx, storage::ObTableScanParam &scan_param)
{
  int ret = OB_SUCCESS;
  const uint64_t table_id = ctx.param_.table_id_;
  ObPartitionKey part_key(table_id, ctx.param_.partition_id_, 0);
  scan_param.timeout_ = ctx.param_.timeout_ts_;
  ObQueryFlag query_flag(ObQueryFlag::KeepOrder, // scan_order KeepOrder!
                         false, // daily_merge
                         false, // optimize
                         false, // whole_macro_scan
                         false, // full_row
                         false, // index_back
                         false, // query_stat
                         ObQueryFlag::MysqlMode, // sql_mode
                         true // read_latest
                         );
  scan_param.scan_flag_.flag_ = query_flag.flag_;
  scan_param.reserved_cell_count_ = column_ids_.count() + 10;
  scan_param.for_update_ = false;
  scan_param.column_ids_.reset();
  scan_param.pkey_ = part_key;
  scan_param.schema_version_ = schema_version_;
  if (OB_FAIL(scan_param.column_ids_.assign(column_ids_))) {
    LOG_WARN("fail to assign column id", K(ret));
  } else {
    scan_param.expr_ctx_.calc_buf_ = NULL;
    scan_param.expr_ctx_.my_session_ = NULL;
    scan_param.expr_ctx_.phy_plan_ctx_ = NULL;
    scan_param.limit_param_.limit_ = -1;
    scan_param.limit_param_.offset_ = 0;
    scan_param.trans_desc_ = &(ctx.param_.processor_->get_trans_desc());
    scan_param.index_id_ = table_id_;
    scan_param.sql_mode_ = SMO_DEFAULT;
    scan_param.allocator_->set_tenant_id(scan_param.pkey_.get_tenant_id());
  }
  return ret;
}



/**
 * ------------------------------------------------------------------ObTableApiInsertRowIterator---------------------------------------------------------
 */
ObTableApiInsertRowIterator::ObTableApiInsertRowIterator()
{
}

ObTableApiInsertRowIterator::~ObTableApiInsertRowIterator()
{
}

int ObTableApiInsertRowIterator::open(const ObTableOperation &table_operation)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api insert row iterator has not been inited, ", K(ret));
  } else if (OB_FAIL(cons_all_columns(table_operation.entity()))) {
    LOG_WARN("Fail to construct all columns, ", K(ret));
  } else {
    entity_ = &(table_operation.entity());
  }
  return ret;
}

int ObTableApiInsertRowIterator::get_next_row(ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  row_allocator_.reuse();
  if (OB_ISNULL(entity_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("The entity is null, ", K(ret));
  } else if (OB_FAIL(cons_row(*entity_, row))) {
    LOG_WARN("Fail to construct insert row, ", K(ret));
  } else {
    //success
    LOG_DEBUG("Api insert row iter, ", K(*row));
  }
  return ret;
}

int ObTableApiInsertRowIterator::cons_row(const table::ObITableEntity &entity, common::ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  if (OB_FAIL(entity_to_row(entity, row_objs_))) {
    LOG_WARN("Fail to generate row from entity, ", K(ret));
  } else {
    const int64_t N = missing_default_objs_.count();
    for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) {
      if (OB_FAIL(row_objs_.push_back(missing_default_objs_.at(i)))) {
        LOG_WARN("Fail to push default value to row, ", K(ret));
      }
    }

    if (OB_SUCC(ret)) {
      row_.assign(&row_objs_.at(0), row_objs_.count());
      if (has_generate_column_ && OB_FAIL(fill_generate_columns(row_))) {
        LOG_WARN("Fail to fill generate columns, ", K(ret));
      }
    }

    if (OB_SUCC(ret)) {
      if (OB_FAIL(check_row(row_))) {
        LOG_WARN("Fail to check row, ", K(ret), K_(row));
      } else {
        row = &row_;
      }
    }
  }
  return ret;
}


/**
 * ------------------------------------------------------------------ObTableApiMultiInsertRowIterator---------------------------------------------------------
 */
ObTableApiMultiInsertRowIterator::ObTableApiMultiInsertRowIterator()
  : batch_operation_(NULL),
    row_idx_(0),
    batch_cnt_(0),
    is_iter_pause_(false)
{
}

ObTableApiMultiInsertRowIterator::~ObTableApiMultiInsertRowIterator()
{
}

void ObTableApiMultiInsertRowIterator::reset()
{
  batch_operation_ = NULL;
  row_idx_ = 0;
  batch_cnt_ = 0;
  is_iter_pause_ = false;
  ObTableApiInsertRowIterator::reset();
}

int ObTableApiMultiInsertRowIterator::open(const ObTableBatchOperation &batch_operation)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api multi insert iterator has not been inited, ", K(ret));
  } else if (OB_UNLIKELY(batch_operation.count() <= 0)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("Invalid argument, ", K(ret), K(batch_operation.count()));
  } else if (OB_FAIL(cons_all_columns(batch_operation.at(0).entity()))) {
    LOG_WARN("Fail to construct all columns, ", K(ret));
  } else {
    batch_operation_ = &batch_operation;
    row_idx_ = 0;
    batch_cnt_ = batch_operation.count();
  }
  return ret;
}

int ObTableApiMultiInsertRowIterator::get_next_row(common::ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  row_allocator_.reuse();
  if (OB_ISNULL(batch_operation_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api multi insert row iterator has not been inited, ", K(ret));
  } else if (row_idx_ >= batch_cnt_ || is_iter_pause_) {
    ret = OB_ITER_END;
  } else if (OB_FAIL(cons_row(batch_operation_->at(row_idx_).entity(), row))) {
    LOG_WARN("Fail to construct row, ", K(ret), K(row_idx_));
  } else {
    row_idx_++;
    is_iter_pause_ = true;
    LOG_DEBUG("Api insert row iter, ", K(*row), K_(row_idx));
  }
  return ret;
}


/**
 * ------------------------------------------------------------------ObTableApiUpdateRowIterator---------------------------------------------------------
 */
ObTableApiUpdateRowIterator::ObTableApiUpdateRowIterator()
  : scan_param_(),
    table_param_(stmt_allocator_),
    update_column_ids_(),
    scan_iter_(NULL),
    old_row_(NULL),
    new_row_(NULL),
    row_idx_(0),
    need_update_rowkey_(false),
    table_operation_(NULL)
{
}

ObTableApiUpdateRowIterator::~ObTableApiUpdateRowIterator()
{
  if (NULL != scan_iter_) {
    if (NULL != part_service_) {
      part_service_->revert_scan_iter(scan_iter_);
      scan_iter_ = NULL;
    } else {
      LOG_ERROR("The part service is NULL, but the scan iter is NOT NULL!");
    }
  }
}

void ObTableApiUpdateRowIterator::reset()
{
  if (NULL != scan_iter_) {
    if (NULL != part_service_) {
      part_service_->revert_scan_iter(scan_iter_);
      scan_iter_ = NULL;
    } else {
      LOG_ERROR("The part service is NULL, but the scan iter is NOT NULL!");
    }
  }
  scan_param_.destroy();
  table_param_.reset();
  update_column_ids_.reset();
  old_row_ = NULL;
  new_row_ = NULL;
  row_idx_ = 0;
  ObTableApiRowIterator::reset();
}

int ObTableApiUpdateRowIterator::open(const ObTableOperation &table_operation,
    const ObRowkey &rowkey, bool need_update_rowkey/* = false */)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api update row iterator has not been inited, ", K(ret));
  } else if (OB_FAIL(cons_all_columns(table_operation.entity()))) {
    LOG_WARN("Fail to construct all columns, ", K(ret));
  } else if (OB_FAIL(cons_update_columns(need_update_rowkey))) {
    LOG_WARN("Fail to construct update columns, ", K(ret));
  } else if (OB_FAIL(fill_get_param(*ctx_,
      table_operation.type(), const_cast<ObRowkey &>(rowkey), scan_param_, table_param_))) {
    LOG_WARN("Fail to fill get param, ", K(ret));
  } else if (OB_FAIL(part_service_->table_scan(scan_param_, scan_iter_))) {
    if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
      LOG_WARN("fail to scan table", K(ret));
    }
  } else {
    table_operation_ = &table_operation;
    old_row_ = NULL;
    new_row_ = NULL;
    row_idx_ = 0;
    need_update_rowkey_ = need_update_rowkey;
  }
  return ret;
}

int ObTableApiUpdateRowIterator::get_next_row(ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api update row iterator has not been inited, ", K(ret));
  } else if (OB_ISNULL(scan_iter_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api update row iterator has not been opened, ", K(ret));
  } else {
    if (0 == row_idx_ % 2) {
      if (OB_FAIL(scan_iter_->get_next_row(row))) {
        if (OB_ITER_END != ret) {
          LOG_WARN("Fail to get next row, ", K(ret));
        } else {
          LOG_DEBUG("Update row iter end, ", K_(row_idx), K(scan_param_));
        }
      } else {
        old_row_ = row;
        LOG_DEBUG("Update old row, ", K_(row_idx), K(*old_row_));
      }
    } else if (OB_FAIL(cons_new_row(*table_operation_, row))) {
      LOG_WARN("Fail to construct new row, ", K(ret));
    } else {
      new_row_ = row;
      LOG_DEBUG("Update iter cons new row, ", K_(row_idx), K(*new_row_));
    }

    if (OB_SUCC(ret)) {
      row_idx_++;
    }
  }
  return ret;
}

int ObTableApiUpdateRowIterator::cons_update_columns(bool need_update_rowkey)
{
  int ret = OB_SUCCESS;
  update_column_ids_.reuse();
  if (OB_UNLIKELY(column_ids_.count() <= 0)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("The column id array is empty, ", K(ret), K(column_ids_.count()));
  } else {
    const int64_t N = column_ids_.count() - missing_default_objs_.count();
    int64_t begin_column_idx = need_update_rowkey ? 0 : rowkey_column_cnt_;
    for (int64_t i = begin_column_idx; OB_SUCC(ret) && i < N; i++) {
      if (OB_FAIL(update_column_ids_.push_back(column_ids_.at(i)))) {
        LOG_WARN("Fail to push column id to update column ids array, ", K(ret));
      }
    }

    if (OB_SUCC(ret) && has_generate_column_) {
      const int64_t gen_col_cnt = generate_column_idxs_.count();
      uint64_t column_id = 0;
      for (int64_t i = 0; OB_SUCC(ret) && i < gen_col_cnt; ++i) {
        if (OB_FAIL(column_ids_.at(generate_column_idxs_.at(i), column_id))) {
          LOG_WARN("Fail to get ith col id, ", K(ret), K(i));
        } else if (OB_FAIL(update_column_ids_.push_back(column_id))) {
          LOG_WARN("Fail to push generate column id to update column ids array, ", K(ret), K(i), K(column_id));
        }
      }
    }
  }
  return ret;
}

int ObTableApiUpdateRowIterator::cons_new_row(const ObTableOperation &table_operation, common::ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  row_objs_.reuse();
  if (OB_FAIL(entity_to_row(table_operation.entity(), row_objs_))) {
    LOG_WARN("Fail to generate row from entity, ", K(ret));
  } else {
    const int64_t rowkey_col_cnt = table_operation.entity().get_rowkey_size();
    const int64_t base_col_cnt = row_objs_.count();
    ObTableOperationType::Type type = table_operation.type();

    switch(type) {
    case ObTableOperationType::GET:
    case ObTableOperationType::INSERT:
    case ObTableOperationType::DEL:
      ret = OB_ERR_UNEXPECTED;
      LOG_ERROR("invalid operation type", K(ret), K(type));
      break;
    case ObTableOperationType::UPDATE:
    case ObTableOperationType::INSERT_OR_UPDATE:
    case ObTableOperationType::REPLACE:
      //nothing to do
      break;
    case ObTableOperationType::INCREMENT: {
      for (int64_t i = rowkey_col_cnt; OB_SUCC(ret) && i < base_col_cnt; ++i) {
        if (OB_FAIL(obj_increment(row_objs_.at(i), old_row_->cells_[i], columns_type_.at(i), row_objs_.at(i)))) {
          LOG_WARN("failed to increment", K(ret), K(i), K(row_objs_.at(i)), K(old_row_->cells_[i]));
        }
      }
      break;
    }
    case ObTableOperationType::APPEND: {
      for (int64_t i = rowkey_col_cnt; OB_SUCC(ret) && i < base_col_cnt; ++i) {
        if (OB_FAIL(obj_append(row_objs_.at(i), old_row_->cells_[i], columns_type_.at(i), row_objs_.at(i)))) {
          LOG_WARN("failed to append", K(ret), K(i), K(row_objs_.at(i)), K(old_row_->cells_[i]));
        }
      }
      break;
    }
    default:
      ret = OB_ERR_UNEXPECTED;
      LOG_ERROR("invalid operation type", K(ret), K(type));
      break;
    }

    if (OB_SUCC(ret) && !need_update_rowkey_) {
      const int64_t N = rowkey_col_cnt;
      for (int64_t i = 0; i < N; ++i) {
        row_objs_[i] = old_row_->cells_[i];
      }
    }

    if (OB_SUCC(ret)) {
      //fill default columns
      const int64_t N = missing_default_objs_.count();
      for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) {
        if (OB_FAIL(row_objs_.push_back(old_row_->cells_[base_col_cnt + i]))) {
          LOG_WARN("Fail to push back old row obj to new row, ", K(ret));
        }
      }
    }

    if (OB_SUCC(ret)) {
      //fill generate columns
      row_.assign(&row_objs_.at(0), row_objs_.count());
      if (has_generate_column_ && OB_FAIL(fill_generate_columns(row_))) {
        LOG_WARN("Fail to fill generate columns, ", K(ret));
      }
    }

    if (OB_SUCC(ret)) {
      if (OB_FAIL(check_row(row_))) {
        LOG_WARN("Fail to check new row, ", K(ret));
      }
    }
  }

  if (OB_SUCC(ret)) {
    row = &row_;
  }
  return ret;
}


int ObTableApiUpdateRowIterator::obj_increment(
    const common::ObObj &delta,
    const common::ObObj &src,
    const sql::ObExprResType target_type,
    common::ObObj &target)
{
  int ret = OB_SUCCESS;
  if (OB_LIKELY(ob_is_int_tc(delta.get_type()))) {
    int64_t delta_int = delta.get_int();
    ObObjType src_type = src.get_type();
    switch (src_type) {
      case ObNullType: {
        // the result is set to delta when src is NULL
        ObObjType result_type = target_type.get_type();
        if (ob_is_int_tc(result_type)) {
          ret = int_add_int_with_check(0, delta_int, result_type, target);
        } else if (ob_is_uint_tc(result_type)) {
          ret = uint_add_int_with_check(0, delta_int, result_type, target);
        } else {
          ret = OB_OBJ_TYPE_ERROR;
        }
        break;
      }
      case ObTinyIntType:
      case ObSmallIntType:
      case ObMediumIntType:
      case ObInt32Type:
      case ObIntType: {
        // signed := signed + signed
        ret = int_add_int_with_check(src.get_int(), delta_int, src_type, target);
        break;
      }
      case ObUTinyIntType:
      case ObUSmallIntType:
      case ObUMediumIntType:
      case ObUInt32Type:
      case ObUInt64Type: {
        // unsigned := usigned + signed
        ret = uint_add_int_with_check(src.get_uint64(), delta_int, src_type, target);
        break;
      }
      default:
        ret = OB_OBJ_TYPE_ERROR;
        break;
    }  // end switch
  } else {
    ret = OB_OBJ_TYPE_ERROR;
    LOG_WARN("delta should only be signed integer type", K(ret), K(delta));
  }
  return ret;
}

int ObTableApiUpdateRowIterator::obj_append(
    const common::ObObj &delta,
    const common::ObObj &src,
    const sql::ObExprResType target_type,
    common::ObObj &target)
{
  int ret = OB_SUCCESS;
  if (delta.is_null()) {
    ret = OB_OBJ_TYPE_ERROR;
    LOG_WARN("append NULL is illegal", K(ret), K(delta));
  } else if (OB_UNLIKELY(ObVarcharType != delta.get_type())) {
    ret = OB_OBJ_TYPE_ERROR;
    LOG_WARN("can only append varchar/varbinary type", K(ret), K(delta));
  } else {
    const char *result_ptr = NULL;
    int32_t result_len = 0;

    if (src.is_null()) {
      // the result is set the delta when src is NULL
      if (OB_UNLIKELY(ObVarcharType != target_type.get_type())
          && OB_UNLIKELY(ObTextTC != ob_obj_type_class(target_type.get_type()))) {
        ret = OB_OBJ_TYPE_ERROR;
        LOG_WARN("can only appended to string type", K(ret), K(target_type));
      } else {
        result_ptr = delta.get_string_ptr();
        result_len = delta.get_string_len();
      }
    } else if (OB_UNLIKELY(ObVarcharType != src.get_type())
        && OB_UNLIKELY(ObTextTC != ob_obj_type_class(src.get_type()))) {
      ret = OB_OBJ_TYPE_ERROR;
      LOG_WARN("can only appended to string type", K(ret), K(src));
    } else {
      const int32_t len1 = src.get_string_len();
      const int32_t len2 = delta.get_string_len();
      const int32_t total_len = len1 + len2;
      // the actual length will be checked in ObTableOperationTypeChecker
      if (len1 <= 0) {
        result_ptr = delta.get_string_ptr();
        result_len = delta.get_string_len();
      } else if (len2 <= 0) {
        target = src;
        result_len = -1;  // no need to set the target
      } else {
        char *buf = NULL;
        if (OB_ISNULL(buf = static_cast<char*>(row_allocator_.alloc(total_len)))) {
          ret = OB_ALLOCATE_MEMORY_FAILED;
          LOG_ERROR("alloc memory failed", K(ret), K(total_len));
        } else {
          MEMCPY(buf, src.get_string_ptr(), len1);
          MEMCPY(buf + len1, delta.get_string_ptr(), len2);
          result_ptr = buf;
          result_len = total_len;
        }
      }
    }

    if (OB_SUCC(ret) && result_len >= 0) {
      if (ob_is_text_tc(target_type.get_type())) {  // LOB
        target.set_lob_value(target_type.get_type(), result_ptr, result_len);
        target.set_meta_type(target_type);
      } else {  // Varchar/Varbinary
        target.set_varchar_value(result_ptr, result_len);
        target.set_meta_type(target_type);
      }
    }
  }
  return ret;
}

int ObTableApiUpdateRowIterator::int_add_int_with_check(
    int64_t old_int,
    int64_t delta_int,
    common::ObObjType result_type,
    common::ObObj &result)
{
  int ret = OB_SUCCESS;
  int64_t result_int = old_int + delta_int;
  if (sql::ObExprAdd::is_int_int_out_of_range(old_int, delta_int, result_int)) {
    ret = OB_DATA_OUT_OF_RANGE;
    LOG_WARN("result of increment out of range", K(ret),
             K(delta_int), K(old_int), K(result_int));
  } else if (result_int < INT_MIN_VAL[result_type]
             || result_int > INT_MAX_VAL[result_type]) {
    ret = OB_DATA_OUT_OF_RANGE;
    LOG_WARN("result of increment out of range", K(ret),
             K(delta_int), K(old_int), K(result_int),
             "min", INT_MIN_VAL[result_type],
             "max", INT_MAX_VAL[result_type]);
  } else {
    result.set_type(result_type);
    result.set_int_value(result_int);
  }
  return ret;
}


int ObTableApiUpdateRowIterator::uint_add_int_with_check(
    uint64_t old_uint,
    int64_t delta_int,
    common::ObObjType result_type,
    common::ObObj &result)
{
  int ret = OB_SUCCESS;
  uint64_t result_uint = old_uint + delta_int;
  if (sql::ObExprAdd::is_int_uint_out_of_range(delta_int, old_uint, result_uint)) {
    ret = OB_DATA_OUT_OF_RANGE;
    LOG_WARN("result of increment out of range", K(ret),
             K(delta_int), K(old_uint), K(result_uint));
  } else if (result_uint > UINT_MAX_VAL[result_type]) {
    ret = OB_DATA_OUT_OF_RANGE;
    LOG_WARN("result of increment out of range", K(ret),
             K(delta_int), K(old_uint), K(result_uint),
             "max", UINT_MAX_VAL[result_type]);
  } else {
    result.set_type(result_type);
    result.set_uint64_value(result_uint);
  }
  return ret;
}



/**
 * ------------------------------------------------------------------ObTableApiMultiUpdateRowIterator---------------------------------------------------------
 */
ObTableApiMultiUpdateRowIterator::ObTableApiMultiUpdateRowIterator()
  : batch_operation_(NULL),
    batch_cnt_(0),
    batch_idx_(0),
    cur_update_idx_(-1),
    is_iter_pause_(false)
{
}

ObTableApiMultiUpdateRowIterator::~ObTableApiMultiUpdateRowIterator()
{
}

void ObTableApiMultiUpdateRowIterator::reset()
{
  batch_operation_ = NULL;
  batch_cnt_ = 0;
  batch_idx_ = 0;
  cur_update_idx_ = -1;
  is_iter_pause_ = false;
  ObTableApiUpdateRowIterator::reset();
}

int ObTableApiMultiUpdateRowIterator::open(const ObTableBatchOperation &batch_operation)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api update row iterator has not been inited, ", K(ret));
  } else if (OB_FAIL(cons_all_columns(batch_operation.at(0).entity()))) {
    LOG_WARN("Fail to construct all columns, ", K(ret));
  } else if (OB_FAIL(cons_update_columns(false/*need_update_rowkey*/))) {
    LOG_WARN("Fail to construct update columns, ", K(ret));
  } else if (OB_FAIL(fill_multi_get_param(*ctx_, batch_operation, scan_param_, table_param_))) {
    LOG_WARN("Fail to fill get param, ", K(ret));
  } else if (OB_FAIL(part_service_->table_scan(scan_param_, scan_iter_))) {
    if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
      LOG_WARN("fail to scan table", K(ret));
    }
  } else {
    batch_operation_ = &batch_operation;
    batch_cnt_ = batch_operation.count();
    batch_idx_ = 0;
    cur_update_idx_ = -1;
    is_iter_pause_ = false;
  }
  return ret;
}

int ObTableApiMultiUpdateRowIterator::get_next_row(ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api update row iterator has not been inited, ", K(ret));
  } else if (OB_ISNULL(batch_operation_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api update row iterator has not been opened, ", K(ret));
  } else if (batch_idx_ >= batch_cnt_ || is_iter_pause_) {
    ret = OB_ITER_END;
  } else {
    row_allocator_.reuse();
    if (0 == row_idx_ % 2) {
      if (OB_FAIL(scan_iter_->get_next_row(row))) {
        if (OB_ITER_END != ret) {
          LOG_WARN("Fail to scan next row, ", K(ret), K_(row_idx));
        } else {
          batch_idx_ = batch_cnt_;
        }
        old_row_ = NULL;
      } else {
        old_row_ = row;
      }
    } else {
      ObRowkey old_row_key(old_row_->cells_, rowkey_column_cnt_);
      row = NULL;
      while(batch_idx_ < batch_cnt_) {
        entity_ = &(batch_operation_->at(batch_idx_).entity());
        if (old_row_key.simple_equal((const_cast<ObITableEntity*>(entity_))->get_rowkey())) {
          break;
        } else {
          batch_idx_++;
        }
      }

      if (batch_idx_ < batch_cnt_) {
        if (OB_FAIL(cons_new_row(batch_operation_->at(batch_idx_), row))) {
          LOG_WARN("Fail to construct new row, ", K(ret));
        } else {
          cur_update_idx_ = batch_idx_;
          batch_idx_++;
          is_iter_pause_ = true;
        }
      } else {
        ret = OB_ITER_END;
      }
    }

    if (OB_SUCC(ret)) {
      row_idx_++;
    }
  }
  return ret;
}


/**
 * ------------------------------------------------------------------ObTableApiDeleteRowIterator---------------------------------------------------------
 */
ObTableApiDeleteRowIterator::ObTableApiDeleteRowIterator()
  : scan_param_(),
    table_param_(stmt_allocator_),
    scan_iter_(NULL)
{
}

ObTableApiDeleteRowIterator::~ObTableApiDeleteRowIterator()
{
  if (NULL != scan_iter_) {
    if (NULL != part_service_) {
      part_service_->revert_scan_iter(scan_iter_);
      scan_iter_ = NULL;
    } else {
      LOG_ERROR("The part service is NULL, but the scan iter is NOT NULL!");
    }
  }
}

void ObTableApiDeleteRowIterator::reset()
{
  if (NULL != scan_iter_) {
    if (NULL != part_service_) {
      part_service_->revert_scan_iter(scan_iter_);
      scan_iter_ = NULL;
    } else {
      LOG_ERROR("The part service is NULL, but the scan iter is NOT NULL!");
    }
  }
  scan_param_.destroy();
  table_param_.reset();

  ObTableApiRowIterator::reset();
}

int ObTableApiDeleteRowIterator::open(const ObTableOperation &table_operation)
{
  int ret = OB_SUCCESS;
  ObRowkey rowkey = const_cast<ObITableEntity &>(table_operation.entity()).get_rowkey();
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api update row iterator has not been inited, ", K(ret));
  } else if (OB_FAIL(cons_all_columns(table_operation.entity()))) {
    LOG_WARN("Fail to construct all columns, ", K(ret));
  } else if (OB_FAIL(fill_get_param(*ctx_, table_operation.type(), rowkey,
      scan_param_, table_param_))) {
    LOG_WARN("Fail to fill get param, ", K(ret));
  } else if (OB_FAIL(part_service_->table_scan(scan_param_, scan_iter_))) {
    if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
      LOG_WARN("fail to scan table", K(ret));
    }
  } else {
    entity_ = &(table_operation.entity());
  }
  return ret;
}

int ObTableApiDeleteRowIterator::get_next_row(common::ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  if (NULL == scan_iter_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The delete row iterator has not been inited, ", K(ret));
  } else {
    if (OB_FAIL(scan_iter_->get_next_row(row))) {
      if (OB_ITER_END != ret) {
        LOG_WARN("Fail to get next delete row, ", K(ret));
      }
    }
  }
  return ret;
}

/**
 * ------------------------------------------------------------------ObTableApiMultiDeleteRowIterator---------------------------------------------------------
 */
ObTableApiMultiDeleteRowIterator::ObTableApiMultiDeleteRowIterator()
  : batch_operation_(NULL),
    batch_cnt_(0),
    batch_idx_(0),
    cur_delete_idx_(-1),
    is_iter_pause_(false)
{
}

ObTableApiMultiDeleteRowIterator::~ObTableApiMultiDeleteRowIterator()
{
}

void ObTableApiMultiDeleteRowIterator::reset()
{
  batch_operation_ = NULL;
  batch_cnt_ = 0;
  batch_idx_ = 0;
  cur_delete_idx_ = -1;
  is_iter_pause_ = false;
  ObTableApiDeleteRowIterator::reset();
}

int ObTableApiMultiDeleteRowIterator::open(const ObTableBatchOperation &batch_operation)
{
  int ret = OB_SUCCESS;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The multi delte row iterator has not been inited, ", K(ret));
  } else if (OB_FAIL(cons_all_columns(batch_operation.at(0).entity()))) {
    LOG_WARN("Fail to construct all columns, ", K(ret));
  } else if (OB_FAIL(fill_multi_get_param(*ctx_, batch_operation, scan_param_, table_param_))) {
    LOG_WARN("Fail to fill multi get param, ", K(ret));
  } else if (OB_FAIL(part_service_->table_scan(scan_param_, scan_iter_))) {
    if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
      LOG_WARN("fail to scan table", K(ret));
    }
  } else {
    batch_operation_ = &batch_operation;
    batch_cnt_ = batch_operation.count();
    batch_idx_ = 0;
    cur_delete_idx_ = -1;
    is_iter_pause_ = false;
  }
  return ret;
}

int ObTableApiMultiDeleteRowIterator::get_next_row(ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  row = NULL;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api multi delete row iterator has not been inited, ", K(ret));
  } else if (OB_ISNULL(batch_operation_)) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api multi delete row iterator has not been opened, ", K(ret));
  } else if (batch_idx_ >= batch_cnt_ || is_iter_pause_) {
    ret = OB_ITER_END;
  } else {
    if (OB_FAIL(scan_iter_->get_next_row(row))) {
      if (OB_ITER_END != ret) {
        LOG_WARN("Fail to get next delete row, ", K(ret));
      } else {
        batch_idx_ = batch_cnt_;
      }
    } else {
      ObRowkey row_key(row->cells_, rowkey_column_cnt_);
      while(batch_idx_ < batch_cnt_) {
        entity_ = &(batch_operation_->at(batch_idx_).entity());
        if (row_key.simple_equal((const_cast<ObITableEntity*>(entity_))->get_rowkey())) {
          cur_delete_idx_ = batch_idx_;
          break;
        } else {
          batch_idx_++;
        }
      }
      batch_idx_++;
      is_iter_pause_ = true;
    }
  }

  return ret;
}


/**
 * ------------------------------------------------------------------ObTableApiGetRowIterator---------------------------------------------------------
 */
ObTableApiGetRowIterator::ObTableApiGetRowIterator()
  : scan_param_(),
    table_param_(stmt_allocator_),
    scan_iter_(NULL)
{
}

ObTableApiGetRowIterator::~ObTableApiGetRowIterator()
{
  if (NULL != scan_iter_) {
    if (NULL != part_service_) {
      part_service_->revert_scan_iter(scan_iter_);
      scan_iter_ = NULL;
    } else {
      LOG_ERROR("The part service is NULL, but the scan iter is NOT NULL!");
    }
  }
}

void ObTableApiGetRowIterator::reset()
{
  scan_param_.destroy();
  table_param_.reset();
  if (NULL != scan_iter_) {
    if (NULL != part_service_) {
      part_service_->revert_scan_iter(scan_iter_);
      scan_iter_ = NULL;
    } else {
      LOG_ERROR("The part service is NULL, but the scan iter is NOT NULL!");
    }
  }
  ObTableApiRowIterator::reset();
}

int ObTableApiGetRowIterator::open(const ObTableOperation &table_operation)
{
  int ret = OB_SUCCESS;
  const bool ignore_missing_column = true;
  ObRowkey rowkey = const_cast<ObITableEntity &>(table_operation.entity()).get_rowkey();
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api update row iterator has not been inited, ", K(ret));
  } else if (OB_FAIL(cons_all_columns(table_operation.entity(), ignore_missing_column))) {
    LOG_WARN("Fail to construct all columns, ", K(ret));
  } else if (OB_FAIL(fill_get_param(*ctx_, table_operation.type(), rowkey,
      scan_param_, table_param_))) {
    LOG_WARN("Fail to fill get param, ", K(ret));
  } else if (OB_FAIL(part_service_->table_scan(scan_param_, scan_iter_))) {
    if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
      LOG_WARN("fail to scan table", K(ret));
    }
  } else {
  }
  return ret;
}

int ObTableApiGetRowIterator::get_next_row(common::ObNewRow *&row)
{
  int ret = OB_SUCCESS;
  if (NULL == scan_iter_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api get row iterator has not been inited, ", K(ret));
  } else if (OB_FAIL(scan_iter_->get_next_row(row))) {
    if (OB_ITER_END != ret) {
      LOG_WARN("Fail to get next row, ", K(ret));
    }
  }
  return ret;
}

/**
 * ------------------------------------------------------------------ObTableApiMultiGetRowIterator---------------------------------------------------------
 */
ObTableApiMultiGetRowIterator::ObTableApiMultiGetRowIterator()
{
}

ObTableApiMultiGetRowIterator::~ObTableApiMultiGetRowIterator()
{
}

int ObTableApiMultiGetRowIterator::open(const ObTableBatchOperation &batch_operation)
{
  int ret = OB_SUCCESS;
  const bool ignore_missing_column = true;
  if (!is_inited_) {
    ret = OB_NOT_INIT;
    LOG_WARN("The table api multi get row iterator has not been inited, ", K(ret));
  } else if (OB_FAIL(cons_all_columns(batch_operation.at(0).entity(), ignore_missing_column))) {
    LOG_WARN("Fail to construct all columns, ", K(ret));
  } else if (OB_FAIL(fill_multi_get_param(*ctx_, batch_operation, scan_param_, table_param_))) {
    LOG_WARN("Fail to fill get param, ", K(ret));
  } else if (OB_FAIL(part_service_->table_scan(scan_param_, scan_iter_))) {
    if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
      LOG_WARN("fail to scan table", K(ret));
    }
  } else {
  }
  return ret;
}

}
}
