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

#ifndef OCEANBASE_SQL_ENGINE_TABLE_TABLE_SCAN_
#define OCEANBASE_SQL_ENGINE_TABLE_TABLE_SCAN_

#include "common/ob_partition_key.h"
#include "share/schema/ob_schema_struct.h"
#include "sql/ob_phy_table_location.h"
#include "sql/optimizer/ob_join_order.h"
#include "sql/optimizer/ob_opt_est_cost.h"
#include "sql/rewrite/ob_query_range.h"
#include "sql/engine/ob_no_children_phy_operator.h"
#include "sql/engine/expr/ob_sql_expression.h"
#include "sql/engine/ob_physical_plan_ctx.h"
#include "sql/ob_sql_mock_schema_utils.h"
#include "storage/ob_i_partition_storage.h"
#include "share/ob_i_sql_expression.h"
#include "ob_table_partition_ranges.h"
#include "storage/ob_partition_service.h"

namespace oceanbase {
namespace common {
class ObIDataAccessService;
}
namespace storage {
class ObPartitionService;
}

namespace sql {
class ObTaskExecutorCtx;
class ObDomainIndex;
class ObTableScanWithIndexBack;
class ObTableScanWithChecksum;
class ObTableScanCreateDomainIndex;
class ObGranuleTaskInfo;

class ObTableScanInput : public ObIPhyOperatorInput {
  friend class ObTableScan;
  friend class ObMVTableScan;
  friend class ObMultiPartitionTableScan;
  OB_UNIS_VERSION_V(1);

public:
  ObTableScanInput();
  virtual ~ObTableScanInput();
  virtual void reset() override;
  virtual int init(ObExecContext& ctx, ObTaskInfo& task_info, const ObPhyOperator& op) override;
  int64_t get_location_idx() const;
  inline void set_location_idx(int64_t location_idx)
  {
    location_idx_ = location_idx;
  }
  virtual ObPhyOperatorType get_phy_op_type() const override;
  virtual void set_deserialize_allocator(common::ObIAllocator* allocator) override;
  int reassign_ranges(ObIArray<ObNewRange>& ranges);

  int translate_pid_to_ldx(ObExecContext& ctx, int64_t partition_id, int64_t table_location_key, int64_t ref_table_id,
      int64_t& location_idx);

private:
  int deep_copy_range(common::ObIAllocator* allocator, const common::ObNewRange& src, common::ObNewRange& dst);

protected:
  int64_t location_idx_;

protected:
  common::ObSEArray<common::ObNewRange, 16> key_ranges_;
  common::ObPosArray range_array_pos_;
  // This variable is reserved for compatibility. Because 2.0 will
  // serialize and deserialize this variable
  common::ObSEArray<ObPartitionScanRanges, 16> partition_ranges_;

protected:
  common::ObIAllocator* deserialize_allocator_;
  DISALLOW_COPY_AND_ASSIGN(ObTableScanInput);
};

class ObTableScan : public ObNoChildrenPhyOperator {
  OB_UNIS_VERSION_V(1);

public:
  class ObTableScanCtx : public ObPhyOperatorCtx {
    friend class ObTableScan;
    friend class ObDomainIndex;
    friend class ObTableScanWithIndexBack;
    friend class ObMVTableScan;
    friend class ObRowSampleScan;
    friend class ObBlockSampleScan;
    friend class ObTableScanWithChecksum;
    friend class ObTableScanCreateDomainIndex;
    friend class ObMultiPartTableScan;

  public:
    explicit ObTableScanCtx(ObExecContext& ctx)
        : ObPhyOperatorCtx(ctx),
          result_(NULL),
          iter_result_(NULL),
          result_iters_(NULL),
          scan_param_(),
          partition_guard_(),
          table_allocator_(NULL),
          output_row_count_(-1),
          iter_end_(false),
          partition_id_(OB_INVALID_INDEX),
          iterated_rows_(0),
          is_partition_list_empty_(false),
          got_feedback_(false),
          vt_result_converter_(nullptr)
    {
      scan_param_.partition_guard_ = &partition_guard_;
    }
    virtual ~ObTableScanCtx()
    {
      result_ = NULL;
      result_iters_ = NULL;
      scan_param_.partition_guard_ = NULL;
      partition_guard_.reset();
    }
    virtual void destroy()
    {
      scan_param_.destroy_schema_guard();
      schema_guard_.~ObSchemaGetterGuard();
      ObPhyOperatorCtx::destroy_base();
      scan_param_.partition_guard_ = NULL;
      partition_guard_.reset();
      if (OB_NOT_NULL(vt_result_converter_)) {
        vt_result_converter_->destroy();
        vt_result_converter_->~ObVirtualTableResultConverter();
        vt_result_converter_ = nullptr;
      }
    }
    inline void set_partition_list_empty(const bool partition_list_empty)
    {
      is_partition_list_empty_ = partition_list_empty;
    }
    inline bool get_partition_list_empty() const
    {
      return is_partition_list_empty_;
    }
    inline void set_table_allocator(common::ObArenaAllocator* alloc)
    {
      table_allocator_ = alloc;
    }
    inline void set_scan_iterator_mementity(lib::MemoryContext mem)
    {
      scan_param_.iterator_mementity_ = mem;
      scan_param_.allocator_ = &mem->get_arena_allocator();
    }
    inline storage::ObTableScanParam& get_table_scan_param()
    {
      return scan_param_;
    }
    const storage::ObTableScanParam& get_table_scan_param() const
    {
      return scan_param_;
    }
    inline share::schema::ObSchemaGetterGuard& get_schema_guard()
    {
      return schema_guard_;
    }
    virtual int init_table_allocator(ObExecContext& ctx);

  public:
    common::ObNewRowIterator* result_;
    // used for array binding
    common::ObNewIterIterator* iter_result_;
    // used for batch nestloop join
    common::ObNewIterIterator* result_iters_;
    storage::ObTableScanParam scan_param_;
    storage::ObIPartitionGroupGuard partition_guard_;
    // This allocator is generated when the table scan context is created, until the table scan is closed and reset
    common::ObArenaAllocator* table_allocator_;
    int64_t output_row_count_;  // this is used for found rows, if rescan. output_row_count_ is not accurate
    bool iter_end_;
    int64_t partition_id_;
    share::schema::ObSchemaGetterGuard schema_guard_;
    int64_t iterated_rows_;
    bool is_partition_list_empty_;
    bool got_feedback_;
    sql::ObVirtualTableResultConverter* vt_result_converter_;
  };

public:
  explicit ObTableScan(common::ObIAllocator& allocator);
  virtual ~ObTableScan();
  virtual void reset() override;
  virtual void reuse() override;
  // renew the TSC by a new granule task info and do table scan
  int reassign_task_and_do_table_scan(ObExecContext& ctx, ObGranuleTaskInfo& info) const;
  // get task from exection ctx
  int get_gi_task_and_restart(ObExecContext& ctx) const;
  // virtual int get_next_row(ObExecContext &ctx, const common::ObNewRow *&row) const;
  virtual int rescan(ObExecContext& ctx) const override;
  virtual int create_operator_input(ObExecContext& ctx) const override;

  DECLARE_VIRTUAL_TO_STRING;

  // construct ObTableScanParam  using following interface
  inline int init_output_column(const int64_t size);
  inline int add_output_column(const uint64_t column_id);
  inline int set_filter_before_indexback_flags(const common::ObIArray<bool>& flags);
  inline int set_partition_range_pos(const common::ObIArray<int64_t>& partition_range_pos);
  const common::ObIArray<int64_t>& get_partition_range_pos()
  {
    return part_range_pos_;
  }
  inline int set_subpartition_range_pos(const common::ObIArray<int64_t>& subpartition_range_pos);
  const common::ObIArray<int64_t>& get_subpartition_range_pos()
  {
    return subpart_range_pos_;
  }
  inline void set_partition_level(const share::schema::ObPartitionLevel partition_level);
  inline void set_partition_type(const share::schema::ObPartitionFuncType part_type);
  share::schema::ObPartitionFuncType get_partition_type()
  {
    return part_type_;
  };
  inline void set_subpartition_type(const share::schema::ObPartitionFuncType subpart_type);
  share::schema::ObPartitionFuncType get_subpartition_type()
  {
    return subpart_type_;
  };
  inline void set_schema_version(const int64_t schema_version);
  int64_t get_schema_version() const
  {
    return schema_version_;
  };
  inline void set_ref_table_id(const uint64_t ref_table_id);
  inline uint64_t get_ref_table_id() const;
  inline void set_table_name(const common::ObString& table_name);
  inline const common::ObString& get_table_name() const;
  inline uint64_t get_location_table_id() const;
  inline void set_index_table_id(const uint64_t idx_table_id);
  inline uint64_t get_index_table_id() const;
  inline const common::ObString& get_index_name() const;
  inline void set_index_name(const common::ObString& index_name);
  inline void set_is_index_global(const bool is_index_global);
  inline bool get_is_index_global() const;
  inline void add_flag(const int64_t flag);
  inline void set_flags(const int64_t flags)
  {
    flags_ = flags;
  }
  inline int64_t get_flags() const
  {
    return flags_;
  }
  inline void set_table_location_key(uint64_t table_location_key)
  {
    table_location_key_ = table_location_key;
  }
  inline uint64_t get_table_location_key() const
  {
    return table_location_key_;
  }
  inline int set_query_range(const ObQueryRange& query_range)
  {
    return pre_query_range_.deep_copy(query_range);
  }
  inline const ObQueryRange& get_query_range() const
  {
    return pre_query_range_;
  }
  inline void set_is_get(bool v)
  {
    is_get_ = v;
  }
  inline const bool& is_get() const
  {
    return is_get_;
  }
  inline void set_table_row_count(int64_t table_row_count)
  {
    table_row_count_ = table_row_count;
  }
  inline int64_t get_table_row_count() const
  {
    return table_row_count_;
  }
  inline void set_output_row_count(int64_t output_row_count)
  {
    output_row_count_ = output_row_count;
  }
  inline int64_t get_output_row_count() const
  {
    return output_row_count_;
  }
  inline void set_phy_query_range_row_count(int64_t phy_query_range_row_count)
  {
    phy_query_range_row_count_ = phy_query_range_row_count;
  }
  inline int64_t get_phy_query_range_row_count() const
  {
    return phy_query_range_row_count_;
  }
  inline void set_query_range_row_count(int64_t query_range_row_count)
  {
    query_range_row_count_ = query_range_row_count;
  }
  inline int64_t get_query_range_row_count() const
  {
    return query_range_row_count_;
  }
  inline void set_index_back_row_count(int64_t index_back_row_count)
  {
    index_back_row_count_ = index_back_row_count;
  }
  inline int64_t get_index_back_row_count() const
  {
    return index_back_row_count_;
  }
  int explain_index_selection_info(char* buf, int64_t buf_len, int64_t& pos) const;
  inline void set_estimate_method(RowCountEstMethod method)
  {
    estimate_method_ = method;
  }
  inline RowCountEstMethod get_estimate_method() const
  {
    return estimate_method_;
  }
  int set_pruned_index_name(const common::ObIArray<common::ObString>& pruned_index_name, ObIAllocator& phy_alloc);
  int set_available_index_name(const common::ObIArray<common::ObString>& available_index_name, ObIAllocator& phy_alloc);
  int set_est_row_count_record(const common::ObIArray<common::ObEstRowCountRecord>& est_records);
  inline const common::ObIArray<common::ObEstRowCountRecord>& get_est_row_count_record() const
  {
    return est_records_;
  }
  void set_for_update(bool for_update, int64_t wait_us)
  {
    for_update_ = for_update;
    for_update_wait_us_ = wait_us;
  }
  int64_t get_for_update_wait_us() const
  {
    return for_update_wait_us_;
  };
  bool is_for_update() const
  {
    return for_update_;
  }
  void set_is_top_table_scan(bool is_top)
  {
    is_top_table_scan_ = is_top;
  }

  void set_hint(const common::ObTableScanHint& hint)
  {
    hint_ = hint;
  }
  const common::ObTableScanHint& get_const_hint() const
  {
    return hint_;
  }
  common::ObTableScanHint& get_hint()
  {
    return hint_;
  }

  void set_exist_hint(bool exist_hint)
  {
    exist_hint_ = exist_hint;
  }
  bool exist_hint()
  {
    return exist_hint_;
  }

  // for virtual table with real table
  inline void set_is_vt_mapping()
  {
    is_vt_mapping_ = true;
  }
  inline void set_has_real_tenant_id(bool has_real_tenant_id)
  {
    use_real_tenant_id_ = has_real_tenant_id;
  }
  inline void set_has_tenant_id_col(bool has_tenant_id_col)
  {
    has_tenant_id_col_ = has_tenant_id_col;
  }
  inline void set_vt_table_id(uint64_t vt_table_id)
  {
    vt_table_id_ = vt_table_id;
  }
  inline void set_real_schema_version(int64_t schema_version)
  {
    real_schema_version_ = schema_version;
  }

  inline uint64_t get_vt_table_id() const
  {
    return vt_table_id_;
  }

  inline int init_key_types(const int64_t size)
  {
    return init_array_size<>(key_types_, size);
  }
  inline int init_key_tenant_ids(const int64_t size)
  {
    return init_array_size<>(key_with_tenant_ids_, size);
  }
  inline int init_extra_tenant_ids(const int64_t size)
  {
    return init_array_size<>(has_extra_tenant_ids_, size);
  }
  inline int init_output_columns_type(const int64_t size)
  {
    return init_array_size<>(output_row_types_, size);
  }

  inline int add_key_type(const ObObjMeta& obj_type)
  {
    return key_types_.push_back(obj_type);
  }
  inline int add_key_with_tenant_ids(bool has_tenant_id)
  {
    return key_with_tenant_ids_.push_back(has_tenant_id);
  }
  inline int add_extra_column_ids(bool has_tenant_id)
  {
    return has_extra_tenant_ids_.push_back(has_tenant_id);
  }
  inline int add_output_column_type(const ObObjMeta& obj_meta)
  {
    return output_row_types_.push_back(obj_meta);
  }

  inline int assign_org_output_column_ids(const common::ObIArray<uint64_t>& column_ids)
  {
    org_output_column_ids_.reset();
    return org_output_column_ids_.assign(column_ids);
  }

  inline const common::ObIArray<bool>& get_extra_tenant_ids() const
  {
    return has_extra_tenant_ids_;
  }
  inline const common::ObIArray<uint64_t>& get_org_output_column_ids() const
  {
    return org_output_column_ids_;
  }
  inline const common::ObIArray<ObObjMeta>& get_key_types() const
  {
    return key_types_;
  }
  inline const common::ObIArray<bool>& get_key_with_tenant_ids() const
  {
    return key_with_tenant_ids_;
  }

  void set_gi_above(bool above)
  {
    gi_above_ = above;
  }

  inline bool should_scan_index() const
  {
    return index_id_ != ref_table_id_ && common::OB_INVALID_ID != index_id_ && common::OB_INVALID_ID != ref_table_id_ &&
           !sql::ObSQLMockSchemaUtils::is_mock_index(index_id_);
  }

  inline void set_batch_scan_flag(const bool opt)
  {
    batch_scan_flag_ = opt;
  }
  inline bool get_batch_scan_flag() const
  {
    return batch_scan_flag_;
  }

  int set_limit_offset(const ObSqlExpression* limit, const ObSqlExpression* offset);
  int set_part_expr(const ObSqlExpression* part_expr);
  const ObSqlExpression& get_part_expr()
  {
    return part_expr_;
  };
  int set_subpart_expr(const ObSqlExpression* subpart_expr);
  const ObSqlExpression& get_subpart_expr()
  {
    return subpart_expr_;
  }
  // batch_rescan for ObNestedLoopJoin(self join)
  int batch_rescan_init(ObExecContext& ctx) const;
  int batch_rescan_add_key(ObExecContext& ctx) const;
  int batch_rescan(ObExecContext& ctx) const;
  share::schema::ObTableParam& get_table_param()
  {
    return table_param_;
  }

  // group_rescan for ObNestedLoopJoin
  int group_rescan_init(ObExecContext& ctx, int64_t size) const;
  int group_add_query_range(ObExecContext& ctx) const;
  int group_rescan(ObExecContext& ctx) const;
  /*
   * the following three functions are used for blocked nested loop join
   * reset_qeury_range, add_query_range and rescan after setting query range
   */
  int reset_query_range(ObExecContext& ctx) const;
  virtual int add_query_range(ObExecContext& ctx) const;
  virtual int rescan_after_adding_query_range(ObExecContext& ctx) const;
  int set_part_filter(const ObTableLocation& table_loc);
  virtual bool is_table_scan() const override
  {
    return true;
  }
  void set_whole_range_scan(bool whole_range_scan)
  {
    is_whole_range_scan_ = whole_range_scan;
  }
  bool is_whole_range_scan() const
  {
    return is_whole_range_scan_;
  }
  void set_optimization_method(OptimizationMethod m)
  {
    optimization_method_ = m;
  }
  OptimizationMethod get_optimization_method() const
  {
    return optimization_method_;
  }
  void set_available_index_count(int64_t v)
  {
    available_index_count_ = v;
  }
  int64_t get_available_index_count() const
  {
    return available_index_count_;
  }
  void set_need_scn(bool need_scn)
  {
    need_scn_ = need_scn;
  }
  bool need_scn() const
  {
    return need_scn_;
  }
  /*
   * the range from opitimier must change id to storage scan key id.
   * If the optimizer deside to use index idx to access table A, the origin
   * ObNewRange use A's real table id, but the range is a A(idx) range.
   * We must change this id before send this range to storage layer.
   */
  inline uint64_t get_scan_key_id() const
  {
    return should_scan_index() ? get_index_table_id() : get_ref_table_id();
  }
  virtual int switch_iterator(ObExecContext& ctx) const override;
  const ObIArray<uint64_t>& get_output_column_ids() const
  {
    return output_column_ids_;
  }

  static int transform_rowid_ranges(common::ObIAllocator& allocator, const share::schema::ObTableParam& table_param,
      const uint64_t index_id, ObQueryRangeArray& key_ranges);
  static int transform_rowid_range(
      common::ObIAllocator& allocator, const ObIArray<share::schema::ObColDesc>& rowkey_descs, ObNewRange& key_range);

protected:
  /**
   * @brief init operator context, will create a physical operator context (and a current row space)
   * @param ctx[in], execute context
   * @return if success, return OB_SUCCESS, otherwise, return errno
   */
  virtual int init_op_ctx(ObExecContext& ctx) const override;
  virtual bool need_filter_row() const override;
  virtual int inner_get_next_row(ObExecContext& ctx, const common::ObNewRow*& row) const override;
  /**
   * @brief open operator, not including children operators.
   * called by open.
   * Every op should implement this method.
   */
  virtual int inner_open(ObExecContext& ctx) const override;
  /**
   * @brief close operator, not including children operators.
   * Every op should implement this method.
   */
  virtual int inner_close(ObExecContext& ctx) const override;
  // helper
  int calc_expr_int_value(
      common::ObExprCtx& expr_ctx, const ObSqlExpression& expr, int64_t& retval, bool& is_null_value) const;
  virtual int do_table_scan(ObExecContext& ctx, bool is_rescan, bool need_prepare = true) const;
  int sim_err(ObSQLSessionInfo* my_session) const;
  virtual int prepare_scan_param(ObExecContext& ctx) const;
  int update_scan_param_pkey(ObExecContext& ctx) const;
  int prepare(ObExecContext& ctx, bool is_rescan) const;
  int get_partition_service(ObTaskExecutorCtx& executor_ctx, common::ObIDataAccessService*& das) const;
  inline bool need_extract_range() const
  {
    return pre_query_range_.has_range();
  }
  bool partition_list_is_empty(const ObPhyTableLocationIArray& phy_table_locs) const;
  int rt_rescan(ObExecContext& ctx) const;
  int vt_rescan(ObExecContext& ctx) const;
  // used to optimize partition pruning
  int prune_query_range_by_partition_id(ObExecContext& ctx, common::ObIArray<common::ObNewRange>& scan_ranges) const;
  int can_prune_by_partition_id(share::schema::ObSchemaGetterGuard& schema_guard, common::ObExprCtx& expr_ctx,
      const int64_t partition_id, ObNewRange& scan_range, bool& can_prune) const;
  int construct_partition_range(ObArenaAllocator& allocator, common::ObExprCtx& expr_ctx,
      const share::schema::ObPartitionFuncType part_type, const common::ObIArray<int64_t>& part_range_pos,
      const ObNewRange& scan_range, const ObSqlExpression& part_expr, bool& can_prune, ObNewRange& part_range) const;
  int revise_hash_part_object(common::ObObj& obj) const;
  int check_cache_table_version(int64_t schema_version) const;
  int fill_storage_feedback_info(ObExecContext& ctx) const;
  int extract_scan_ranges(ObTableScanInput& scan_input, ObTableScanCtx& scan_ctx) const;
  void fill_table_scan_stat(const ObTableScanStatistic& statistic, ObTableScanStat& scan_stat) const;
  void set_cache_stat(const ObPlanStat& plan_stat, storage::ObTableScanParam& param) const;

  int init_converter(ObExecContext& ctx) const;
  int get_next_row_with_mode(ObTableScanCtx* scan_ctx, ObNewRow*& row) const;
  static int transform_rowid_rowkey(
      common::ObIAllocator& allocator, const ObIArray<share::schema::ObColDesc>& rowkey_descs, ObRowkey& row_key);

protected:
  // params
  uint64_t ref_table_id_;  // real table id for table to scan
  // @param: table_name_ & index_name_
  // Currently, those fields will only be used in (g)v$plan_cache_plan so as to find
  // table name of the operator, which means those fields will be used by local plan
  // and remote plan will not use those fields. Therefore, those fields NEED NOT TO BE SERIALIZED.
  common::ObString table_name_;  // table name of the table to scan;
  common::ObString index_name_;  // name of the index to be used
  uint64_t index_id_;            // index to be used
  bool is_index_global_;         // whether index is global
  // columns to output
  common::ObFixedArray<uint64_t, common::ObIAllocator> output_column_ids_;
  common::ObFixedArray<bool, common::ObIAllocator> filter_before_index_back_;
  int64_t flags_;  // read consistency, cache policy, result order
  ObSqlExpression limit_;
  ObSqlExpression offset_;
  // is for update
  bool for_update_;               // FOR UPDATE clause
  int64_t for_update_wait_us_;    // 0 means nowait, -1 means infinite
  common::ObTableScanHint hint_;  // hints for table scan
  bool exist_hint_;
  bool is_get_;
  ObQueryRange pre_query_range_;
  uint64_t table_location_key_;  // used to map table_location_key_ in ObPhyTableLocation
  bool is_top_table_scan_;       // need serialize
  share::schema::ObTableParam table_param_;
  int64_t schema_version_;
  share::schema::ObPartitionLevel part_level_;
  share::schema::ObPartitionFuncType part_type_;
  share::schema::ObPartitionFuncType subpart_type_;
  ObSqlExpression part_expr_;
  ObSqlExpression subpart_expr_;
  common::ObFixedArray<int64_t, common::ObIAllocator> part_range_pos_;
  common::ObFixedArray<int64_t, common::ObIAllocator> subpart_range_pos_;

  //***** used for acs *******
  OptimizationMethod optimization_method_;
  int64_t available_index_count_;

  //***** used for plan explain *******
  int64_t table_row_count_;
  int64_t output_row_count_;
  int64_t phy_query_range_row_count_;
  int64_t query_range_row_count_;
  int64_t index_back_row_count_;
  RowCountEstMethod estimate_method_;
  common::ObFixedArray<common::ObEstRowCountRecord, common::ObIAllocator> est_records_;
  common::ObFixedArray<common::ObString, common::ObIAllocator> available_index_name_;
  common::ObFixedArray<common::ObString, common::ObIAllocator> pruned_index_name_;
  //***********************************
  bool gi_above_;

  // for virtual table with real table
  bool is_vt_mapping_;
  bool use_real_tenant_id_;
  bool has_tenant_id_col_;
  uint64_t vt_table_id_;
  // for check real table schema version
  // only used in select virtual table that is mapping real table
  int64_t real_schema_version_;
  common::ObFixedArray<common::ObObjMeta, common::ObIAllocator> output_row_types_;
  common::ObFixedArray<common::ObObjMeta, common::ObIAllocator> key_types_;
  common::ObFixedArray<bool, common::ObIAllocator> key_with_tenant_ids_;
  common::ObFixedArray<bool, common::ObIAllocator> has_extra_tenant_ids_;
  common::ObFixedArray<uint64_t, common::ObIAllocator> org_output_column_ids_;

  // used for partition cutting
  ObTableLocation part_filter_;

private:
  bool is_whole_range_scan_;
  // used for batch nested loop join
  bool batch_scan_flag_;
  bool need_scn_;

private:
  DISALLOW_COPY_AND_ASSIGN(ObTableScan);
};

inline int ObTableScan::init_output_column(const int64_t size)
{
  output_column_ids_.reset();
  return init_array_size<>(output_column_ids_, size);
}

inline int ObTableScan::add_output_column(const uint64_t column_id)
{
  return output_column_ids_.push_back(column_id);
}

inline int ObTableScan::set_filter_before_indexback_flags(const common::ObIArray<bool>& flags)
{
  return filter_before_index_back_.assign(flags);
}

inline int ObTableScan::set_partition_range_pos(const common::ObIArray<int64_t>& partition_range_pos)
{
  return part_range_pos_.assign(partition_range_pos);
}

inline int ObTableScan::set_subpartition_range_pos(const common::ObIArray<int64_t>& subpartition_range_pos)
{
  return subpart_range_pos_.assign(subpartition_range_pos);
}

inline void ObTableScan::set_partition_level(const share::schema::ObPartitionLevel partition_level)
{
  part_level_ = partition_level;
}

inline void ObTableScan::set_partition_type(const share::schema::ObPartitionFuncType part_type)
{
  part_type_ = part_type;
}

inline void ObTableScan::set_subpartition_type(const share::schema::ObPartitionFuncType subpart_type)
{
  subpart_type_ = subpart_type;
}

inline void ObTableScan::set_schema_version(const int64_t schema_version)
{
  schema_version_ = schema_version;
}

inline void ObTableScan::set_ref_table_id(const uint64_t ref_table_id)
{
  ref_table_id_ = ref_table_id;
}

inline uint64_t ObTableScan::get_ref_table_id() const
{
  return ref_table_id_;
}

inline void ObTableScan::set_table_name(const common::ObString& table_name)
{
  table_name_ = table_name;
}

inline const common::ObString& ObTableScan::get_table_name() const
{
  return table_name_;
}

inline uint64_t ObTableScan::get_location_table_id() const
{
  return is_vt_mapping_ ? vt_table_id_ : (is_index_global_ ? index_id_ : ref_table_id_);
}

inline void ObTableScan::set_index_table_id(const uint64_t idx_table_id)
{
  index_id_ = idx_table_id;
}

inline uint64_t ObTableScan::get_index_table_id() const
{
  return index_id_;
}

inline void ObTableScan::set_index_name(const common::ObString& index_name)
{
  index_name_ = index_name;
}

inline const common::ObString& ObTableScan::get_index_name() const
{
  return index_name_;
}

inline void ObTableScan::set_is_index_global(const bool is_index_global)
{
  is_index_global_ = is_index_global;
}

inline bool ObTableScan::get_is_index_global() const
{
  return is_index_global_;
}

inline void ObTableScan::add_flag(const int64_t flag)
{
  flags_ |= flag;
}

}  // end namespace sql
}  // end namespace oceanbase

#endif /* OCEANBASE_SQL_ENGINE_TABLE_TABLE_SCAN_ */
