370 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**
 | 
						|
 * 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_UNITTEST_SQL_ENGINE_TABLE_OB_FAKE_TABLE_H_
 | 
						|
#define OCEANBASE_UNITTEST_SQL_ENGINE_TABLE_OB_FAKE_TABLE_H_
 | 
						|
 | 
						|
#include "share/object/ob_obj_cast.h"
 | 
						|
#include "common/row/ob_row_store.h"
 | 
						|
#include "lib/time/ob_time_utility.h"
 | 
						|
#include "lib/timezone/ob_time_convert.h"
 | 
						|
#include "sql/engine/ob_no_children_phy_operator.h"
 | 
						|
#include "sql/engine/ob_exec_context.h"
 | 
						|
#include "lib/allocator/ob_allocator.h"
 | 
						|
using namespace oceanbase::common;
 | 
						|
using namespace oceanbase::sql;
 | 
						|
 | 
						|
#define null static_cast<const char*>(NULL)
 | 
						|
#define timestamp(val) convert_to_timestamp(val)
 | 
						|
 | 
						|
#define COL(val) \
 | 
						|
  ({\
 | 
						|
    ObObj *_obj = new ObObj(); \
 | 
						|
    int err = OB_SUCCESS; \
 | 
						|
    if (OB_SUCCESS != (err = set_value(*_obj, val))) { \
 | 
						|
      _OB_LOG(WARN, "fail to set value, err=%d", err); \
 | 
						|
    } \
 | 
						|
    _obj; \
 | 
						|
  })
 | 
						|
 | 
						|
#define COL_T(type, val) \
 | 
						|
  ({ \
 | 
						|
    ObObj *_obj = new ObObj(); \
 | 
						|
    _obj->set_##type(val); \
 | 
						|
    _obj; \
 | 
						|
  })
 | 
						|
 | 
						|
#define ADD_ROW(table_op, args...) \
 | 
						|
  if (OB_SUCC(ret)) { \
 | 
						|
    ObObj _cells[OB_MAX_COLUMN_NUMBER]; \
 | 
						|
    ObNewRow _row; \
 | 
						|
    _row.cells_ = _cells; \
 | 
						|
    _row.count_ = table_op.get_column_count(); \
 | 
						|
    if (OB_SUCCESS != (ret = fill_row(_row, ##args))) { \
 | 
						|
      _OB_LOG(WARN, "fail to fill row, ret=%d", ret); \
 | 
						|
    } else if (OB_SUCCESS != (ret = table_op.add_row(_row))) { \
 | 
						|
      _OB_LOG(WARN, "fail to add row, ret=%d", ret); \
 | 
						|
    } \
 | 
						|
  }
 | 
						|
 | 
						|
#define EXCEPT_RESULT(_ctx, _result_table, op, collation) \
 | 
						|
    EXCEPT_RESULT_WITH_IDX(_ctx, _result_table, op, 0, 0, collation)
 | 
						|
 | 
						|
#define EXCEPT_RESULT_SET(_ctx, _result_table, op, start_idx, end_idx, collation) \
 | 
						|
    EXCEPT_RESULT_WITH_IDX(_ctx, _result_table, op, start_idx, end_idx, collation)
 | 
						|
 | 
						|
#define EXCEPT_RESULT_WITH_IDX(_ctx, _result_table, op, start_idx, end_idx, collation) \
 | 
						|
  if (OB_SUCC(ret)) { \
 | 
						|
    int _ret = OB_SUCCESS; \
 | 
						|
    const ObNewRow *result_row = NULL; \
 | 
						|
    while(OB_SUCCESS == (_ret = op.get_next_row(_ctx, result_row))) { \
 | 
						|
      const ObNewRow *except_row = NULL; \
 | 
						|
      printf("row=%s\n", to_cstring(*result_row)); \
 | 
						|
      ASSERT_EQ(OB_SUCCESS, _result_table.get_next_row(_ctx, except_row)); \
 | 
						|
      printf("except_row=%s\n", to_cstring(*except_row)); \
 | 
						|
      ASSERT_TRUE(except_row->count_ == result_row->count_); \
 | 
						|
      for (int64_t i = start_idx; i < end_idx; ++i) { \
 | 
						|
        printf("index=%ld, cell=%s, respect_cell=%s\n", i, to_cstring(result_row->cells_[i]), to_cstring(except_row->cells_[i])); \
 | 
						|
        ASSERT_TRUE(0 == except_row->cells_[i].compare(result_row->cells_[i], collation)); \
 | 
						|
      } \
 | 
						|
      result_row = NULL; \
 | 
						|
    } \
 | 
						|
    ASSERT_EQ(OB_ITER_END, _ret); \
 | 
						|
  }
 | 
						|
 | 
						|
namespace oceanbase
 | 
						|
{
 | 
						|
namespace common
 | 
						|
{
 | 
						|
extern void init_global_memory_pool();
 | 
						|
}  // namespace common
 | 
						|
}  // namespace oceanbase
 | 
						|
 | 
						|
typedef struct TimeStampWrap
 | 
						|
{
 | 
						|
  int64_t usec_;
 | 
						|
} TimeStampWrap;
 | 
						|
 | 
						|
TimeStampWrap convert_to_timestamp(int64_t usec)
 | 
						|
{
 | 
						|
  TimeStampWrap time_stamp;
 | 
						|
  time_stamp.usec_ = usec;
 | 
						|
  return time_stamp;
 | 
						|
}
 | 
						|
 | 
						|
TimeStampWrap convert_to_timestamp(const char *str)
 | 
						|
{
 | 
						|
  TimeStampWrap time_stamp;
 | 
						|
  ObString date = ObString::make_string(str);
 | 
						|
 | 
						|
  //ObTimeUtility::str_to_usec(date, time_stamp.usec_);
 | 
						|
  ObTimeConvertCtx cvrt_ctx(NULL, false);
 | 
						|
  (void)ObTimeConverter::str_to_datetime(date, cvrt_ctx, time_stamp.usec_, NULL);
 | 
						|
 | 
						|
  return time_stamp;
 | 
						|
}
 | 
						|
 | 
						|
int set_value(ObObj &obj, int val)
 | 
						|
{
 | 
						|
  obj.set_int(static_cast<int64_t>(val));
 | 
						|
  return OB_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int set_value(ObObj &obj, int64_t val)
 | 
						|
{
 | 
						|
  obj.set_int(val);
 | 
						|
  return OB_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int set_value(ObObj &obj, float val)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObObj obj1;
 | 
						|
  obj1.set_float(val);
 | 
						|
  ObCastCtx cast_ctx(global_default_allocator,
 | 
						|
                     NULL,
 | 
						|
                     0,
 | 
						|
                     CM_NONE,
 | 
						|
                     CS_TYPE_INVALID,
 | 
						|
                     NULL);
 | 
						|
  if (OB_FAIL(ObObjCaster::to_type(ObNumberType, cast_ctx, obj1, obj))) {
 | 
						|
    _OB_LOG(WARN, "fail to cast obj, ret=%d", ret);
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int set_value(ObObj &obj, double val)
 | 
						|
{
 | 
						|
  ObObj obj1;
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  obj1.set_double(val);
 | 
						|
  ObCastCtx cast_ctx(global_default_allocator,
 | 
						|
                     NULL,
 | 
						|
                     0,
 | 
						|
                     CM_NONE,
 | 
						|
                     CS_TYPE_INVALID,
 | 
						|
                     NULL);
 | 
						|
  if (OB_FAIL(ObObjCaster::to_type(ObNumberType, cast_ctx, obj1, obj))) {
 | 
						|
    _OB_LOG(WARN, "fail to cast obj, ret=%d", ret);
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int set_value(ObObj &obj, const char *val)
 | 
						|
{
 | 
						|
  if (NULL == val) {
 | 
						|
    obj.set_null();
 | 
						|
  } else {
 | 
						|
    obj.set_varchar(val, static_cast<ObString::obstr_size_t>(strlen(val)));
 | 
						|
  }
 | 
						|
  return OB_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int set_value(ObObj &obj, const ObObj &val)
 | 
						|
{
 | 
						|
  obj = val;
 | 
						|
  return OB_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int set_value(ObObj &obj, TimeStampWrap val)
 | 
						|
{
 | 
						|
  obj.set_timestamp(val.usec_);
 | 
						|
  return OB_SUCCESS;
 | 
						|
}
 | 
						|
int fill_row(ObNewRow &row, ...)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObObj *ptr = NULL;
 | 
						|
  va_list ap;
 | 
						|
 | 
						|
#pragma GCC diagnostic push
 | 
						|
#pragma GCC diagnostic ignored "-Wvarargs"
 | 
						|
 | 
						|
  va_start(ap, row);
 | 
						|
  for (int64_t i = 0; OB_SUCC(ret) && i < row.count_; ++i) {
 | 
						|
    if (NULL == (ptr = va_arg(ap, ObObj*))) {
 | 
						|
      ret = OB_INVALID_ARGUMENT;
 | 
						|
      _OB_LOG(WARN, "argument is null");
 | 
						|
    } else {
 | 
						|
      row.cells_[i] = *ptr;
 | 
						|
      row.cells_[i].set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset()));
 | 
						|
      delete ptr;
 | 
						|
      ptr = NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  va_end(ap);
 | 
						|
 | 
						|
#pragma GCC diagnostic pop
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
static ObArenaAllocator alloc_;
 | 
						|
class ObFakeTable : public ObNoChildrenPhyOperator
 | 
						|
{
 | 
						|
private:
 | 
						|
  class ObFakeTableCtx : public ObPhyOperatorCtx
 | 
						|
  {
 | 
						|
  public:
 | 
						|
    ObFakeTableCtx(ObExecContext &ctx)
 | 
						|
        : ObPhyOperatorCtx(ctx)
 | 
						|
    {
 | 
						|
    }
 | 
						|
    int init(int64_t projector_size)
 | 
						|
    {
 | 
						|
      int ret = OB_SUCCESS;
 | 
						|
      projector_size_ = projector_size;
 | 
						|
      projector_ = static_cast<int32_t*>(exec_ctx_.get_allocator().alloc(sizeof(int32_t) * projector_size_));
 | 
						|
      if (NULL == projector_) {
 | 
						|
        ret = OB_ALLOCATE_MEMORY_FAILED;
 | 
						|
      }
 | 
						|
      if (OB_SUCC(ret)) {
 | 
						|
        for (int64_t i = 0; i < projector_size_; i++) {
 | 
						|
          projector_[i] = static_cast<int32_t>(i);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      return ret;
 | 
						|
    }
 | 
						|
    virtual void destroy() { return ObPhyOperatorCtx::destroy_base(); }
 | 
						|
    int64_t projector_size_;
 | 
						|
    int32_t *projector_;
 | 
						|
 | 
						|
  private:
 | 
						|
    ObRowStore::Iterator row_store_it_;
 | 
						|
    friend class ObFakeTable;
 | 
						|
  };
 | 
						|
 | 
						|
public:
 | 
						|
  ObFakeTable(ObIAllocator &alloc) : ObNoChildrenPhyOperator(alloc), no_rescan_(false)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  ObFakeTable() : ObNoChildrenPhyOperator(alloc_), no_rescan_(false)
 | 
						|
  {
 | 
						|
  }
 | 
						|
  ~ObFakeTable()
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  void set_no_rescan() { no_rescan_ = true; }
 | 
						|
  void reset()
 | 
						|
  {
 | 
						|
    row_store_.reset();
 | 
						|
    ObNoChildrenPhyOperator::reset();
 | 
						|
  }
 | 
						|
 | 
						|
  int add_row(const ObNewRow &row)
 | 
						|
  {
 | 
						|
    return row_store_.add_row(row);
 | 
						|
  }
 | 
						|
 | 
						|
  ObPhyOperatorType get_type() const { return PHY_FAKE_TABLE; }
 | 
						|
 | 
						|
  int inner_open(ObExecContext &ctx) const
 | 
						|
  {
 | 
						|
    int ret = OB_SUCCESS;
 | 
						|
    ObFakeTableCtx *table_ctx = NULL;
 | 
						|
 | 
						|
    if (OB_SUCCESS != (ret = init_op_ctx(ctx))) {
 | 
						|
      _OB_LOG(WARN, "fail to init operator context, ret=%d", ret);
 | 
						|
    } else if (NULL == (table_ctx = GET_PHY_OPERATOR_CTX(ObFakeTableCtx, ctx, get_id()))) {
 | 
						|
      ret = OB_ERR_UNEXPECTED;
 | 
						|
      _OB_LOG(WARN, "fail to get physical operator context");
 | 
						|
    } else if (OB_FAIL(table_ctx->init(column_count_))) {
 | 
						|
      _OB_LOG(WARN, "fail to init project size, ret=%d", ret);
 | 
						|
    } else {
 | 
						|
      table_ctx->row_store_it_ = row_store_.begin();
 | 
						|
    }
 | 
						|
    return ret;
 | 
						|
  }
 | 
						|
 | 
						|
  int rescan(ObExecContext &ctx) const
 | 
						|
  {
 | 
						|
  	if (no_rescan_) {
 | 
						|
  		return OB_SUCCESS;
 | 
						|
  	} else {
 | 
						|
			ObFakeTableCtx *fake_table_ctx = NULL;
 | 
						|
			fake_table_ctx = GET_PHY_OPERATOR_CTX(ObFakeTableCtx, ctx, get_id());
 | 
						|
			OB_ASSERT(fake_table_ctx);
 | 
						|
			fake_table_ctx->row_store_it_ = row_store_.begin();
 | 
						|
			return ObNoChildrenPhyOperator::rescan(ctx);
 | 
						|
  	}
 | 
						|
  }
 | 
						|
 | 
						|
  int inner_close(ObExecContext &ctx) const
 | 
						|
  {
 | 
						|
    UNUSED(ctx);
 | 
						|
    return OB_SUCCESS;
 | 
						|
  }
 | 
						|
private:
 | 
						|
  /**
 | 
						|
   * @brief create operator context, only child operator can know it's specific operator type,
 | 
						|
   * so must be overwrited by child operator,
 | 
						|
   * @param ctx[in], execute context
 | 
						|
   * @param op_ctx[out], the pointer of operator context
 | 
						|
   * @return if success, return OB_SUCCESS, otherwise, return errno
 | 
						|
   */
 | 
						|
  virtual int init_op_ctx(ObExecContext &ctx) const
 | 
						|
  {
 | 
						|
    int ret = OB_SUCCESS;
 | 
						|
    ObPhyOperatorCtx *op_ctx = NULL;
 | 
						|
    if (OB_SUCCESS != (ret = CREATE_PHY_OPERATOR_CTX(ObFakeTableCtx,
 | 
						|
                                                     ctx,
 | 
						|
                                                     get_id(),
 | 
						|
                                                     get_type(),
 | 
						|
                                                     op_ctx))) {
 | 
						|
      SQL_EXE_LOG(WARN, "create physical operator context failed", K(ret));
 | 
						|
    } else if (OB_SUCCESS != (ret = op_ctx->create_cur_row(get_column_count(), projector_, projector_size_))) {
 | 
						|
      SQL_EXE_LOG(WARN, "create current row failed", K(ret));
 | 
						|
    }
 | 
						|
    return ret;
 | 
						|
  }
 | 
						|
  /**
 | 
						|
   * @brief called by get_next_row(), get a row from the child operator or row_store
 | 
						|
   * @param ctx[in], execute context
 | 
						|
   * @param row[out], ObSqlRow an obj array and row_size
 | 
						|
   */
 | 
						|
  virtual int inner_get_next_row(ObExecContext &ctx, const ObNewRow *&row) const
 | 
						|
  {
 | 
						|
    int ret = OB_SUCCESS;
 | 
						|
    ObFakeTableCtx *table_ctx = NULL;
 | 
						|
 | 
						|
    if (NULL == (table_ctx = GET_PHY_OPERATOR_CTX(ObFakeTableCtx, ctx, get_id()))) {
 | 
						|
      ret = OB_ERR_UNEXPECTED;
 | 
						|
      _OB_LOG(WARN, "fail to get physical operator context");
 | 
						|
    } else if (OB_SUCCESS != (ret = table_ctx->row_store_it_.get_next_row(
 | 
						|
        table_ctx->get_cur_row()))) {
 | 
						|
      if (OB_ITER_END != ret) {
 | 
						|
        _OB_LOG(WARN, "fail to get next row, ret=%d", ret);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      row = &table_ctx->get_cur_row();
 | 
						|
      const_cast<ObNewRow *>(row)->projector_ = table_ctx->projector_;
 | 
						|
      const_cast<ObNewRow *>(row)->projector_size_ = table_ctx->projector_size_;
 | 
						|
    }
 | 
						|
    return ret;
 | 
						|
  }
 | 
						|
 | 
						|
  virtual int64_t to_string_kv(char *buf, const int64_t buf_len) const
 | 
						|
  {
 | 
						|
    int64_t pos = 0;
 | 
						|
    J_KV(N_ROW_STORE, row_store_);
 | 
						|
    return pos;
 | 
						|
  }
 | 
						|
 | 
						|
  DISALLOW_COPY_AND_ASSIGN(ObFakeTable);
 | 
						|
private:
 | 
						|
  ObRowStore row_store_;
 | 
						|
  bool no_rescan_;
 | 
						|
};
 | 
						|
 | 
						|
#endif /* OCEANBASE_UNITTEST_SQL_ENGINE_TABLE_OB_FAKE_TABLE_H_ */
 |