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

#include "share/ob_unique_index_row_transformer.h"
#include "sql/engine/expr/ob_postfix_expression.h"
#include "sql/ob_result_set.h"
#include "sql/engine/expr/ob_expr_regexp.h"
#include "sql/engine/expr/ob_expr_like.h"
#include "lib/utility/ob_hang_fatal_error.h"

namespace oceanbase {
using namespace common;
using namespace share;
namespace sql {

template <typename AllocatorT>
int ob_write_expr_item(AllocatorT& alloc, const ObPostExprItem& src, ObPostExprItem& dst, ObWriteExprItemFlag flag)
{
  int ret = OB_SUCCESS;
  ObItemType item_type = src.get_item_type();
  dst.set_item_type(item_type);
  ObExprOperatorFactory factory(alloc);
  if (T_REF_COLUMN == item_type) {
    dst.set_accuracy(src.get_accuracy());
    ret = dst.set_column(src.get_column());
  } else if (IS_DATATYPE_OR_QUESTIONMARK_OP(item_type)) {
    ObObj tmp_obj;
    if (OB_SUCC(ob_write_obj(alloc, src.get_obj(), tmp_obj))) {
      dst.set_accuracy(src.get_accuracy());
      ret = dst.assign(tmp_obj);
    }
  } else if (IS_EXPR_OP(item_type)) {
    if (NEW_OP_WHEN_COPY == flag) {
      ObExprOperator* op = NULL;
      if (OB_FAIL(factory.alloc(item_type, op))) {
        LOG_WARN("fail to alloc expr_op", K(ret));
      } else if (OB_ISNULL(op)) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("no memory to alloc op", K(ret), K(item_type));
      } else if (OB_ISNULL(src.get_expr_operator())) {
        ret = OB_BAD_NULL_ERROR;
        LOG_WARN("src expr op is null", K(ret));
      } else if (OB_FAIL(op->assign(*src.get_expr_operator()))) {
        LOG_WARN("deep copy op failed", K(ret));
      } else if (OB_FAIL(dst.assign(op))) {
        LOG_WARN("failed to assign dst expr item", K(ret));
      }
    } else {
      if (OB_ISNULL(src.get_expr_operator())) {
        ret = OB_BAD_NULL_ERROR;
        LOG_WARN("src expr op is null", K(ret));
      } else if (OB_FAIL(dst.assign(const_cast<ObPostExprItem&>(src).get_expr_operator()))) {
        LOG_WARN("failed to assign dst expr item", K(ret));
      }
    }
  } else {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("unknown expr item to serialize", K(item_type));
  }
  return ret;
}

int ObPostExprItem::assign(const common::ObObj& obj)
{
  int ret = OB_SUCCESS;
  ObItemType item_type = static_cast<ObItemType>((obj.get_type()));
  if (OB_UNLIKELY(!IS_DATATYPE_OR_QUESTIONMARK_OP(item_type))) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid obj type", K(ret), K(obj));
  } else {
    new (&v2_.v1_) ObObj(obj);
    item_type_ = item_type;
  }
  return ret;
}

int ObPostExprItem::set_column(int64_t index)
{
  int ret = OB_SUCCESS;
  if (index < 0) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid index", K(ret), K(index));
  } else {
    item_type_ = T_REF_COLUMN;
    v2_.cell_index_ = index;
  }
  return ret;
}

int ObPostExprItem::assign(ObExprOperator* op)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(op)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("op is NULL", K(ret));
  } else {
    item_type_ = op->get_type();
    v2_.op_ = op;
  }
  return ret;
}

int ObPostExprItem::assign(ObItemType item_type)
{
  int ret = OB_SUCCESS;
  if (T_INVALID == item_type) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("item type is invalid", K(ret));
  } else {
    item_type_ = item_type;
  }
  return ret;
}

/* for unittest only */
int ObPostExprItem::set_op(ObIAllocator& alloc, const char* op_name, ObExprOperator*& op)
{
  int ret = OB_SUCCESS;
  ObExprOperatorType type = ObExprOperatorFactory::get_type_by_name(ObString::make_string(op_name));
  ObExprOperatorFactory factory(alloc);
  if (T_INVALID == type) {
    ret = OB_ERR_FUNCTION_UNKNOWN;
    LOG_WARN("unknown operator/function name", K(ret), K(op_name));
  } else if (OB_FAIL(factory.alloc(type, op))) {
    LOG_WARN("fail to alloc expr_op", K(ret));
  } else if (OB_ISNULL(op)) {
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_ERROR("failed to alloc expr operator", K(ret));
  } else {
    ret = assign(op);
  }
  return ret;
}

/* for unittest only */
/* so need NOT normalize */
void ObPostExprItem::set_op(ObIAllocator& alloc, const char* op_name, int32_t real_param_num)
{
  ObExprOperatorType type = ObExprOperatorFactory::get_type_by_name(ObString::make_string(op_name));
  if (T_INVALID == type) {
    LOG_ERROR("invaid op type", K(type));
    right_to_die_or_duty_to_live();
  } else {
    ObExprOperator* op = NULL;
    ObExprOperatorFactory factory(alloc);
    factory.alloc(type, op);
    if (OB_ISNULL(op)) {
    } else {
      op->set_real_param_num(real_param_num);
      assign(op);
    }
  }
}

int64_t ObPostExprItem::to_string(char* buf, const int64_t buf_len) const
{
  int64_t pos = 0;
  if (IS_DATATYPE_OP(item_type_)) {
    J_OW(J_KV(N_CONST, get_obj(), N_ACCURACY, accuracy_));
  } else {
    switch (item_type_) {
      case T_REF_COLUMN: {
        J_OW(J_KV(N_COLUMN_INDEX, get_column(), N_ACCURACY, accuracy_));
        break;
      }
      case T_QUESTIONMARK: {
        J_OW(J_KV(N_PARAM, get_obj().get_int(), N_ACCURACY, accuracy_));
        break;
      }
      default: {
        if (IS_EXPR_OP(item_type_)) {
          J_OW(J_KV(N_OP, *get_expr_operator()));
        } else {
          LOG_WARN("unknown item", K_(item_type));
        }
        break;
      }
    }  // end switch
  }

  return pos;
}

DEFINE_SERIALIZE(ObPostExprItem)
{
  int ret = OB_SUCCESS;
  OB_UNIS_ENCODE(item_type_);
  if (OB_SUCC(ret)) {
    if (T_REF_COLUMN == item_type_) {
      OB_UNIS_ENCODE(v2_.cell_index_);
      OB_UNIS_ENCODE(accuracy_);
    } else if (IS_DATATYPE_OR_QUESTIONMARK_OP(item_type_)) {
      ObObj tmp = get_obj();
      OB_UNIS_ENCODE(tmp);
      OB_UNIS_ENCODE(accuracy_);
    } else if (IS_EXPR_OP(item_type_)) {
      OB_UNIS_ENCODE(*v2_.op_);
    } else {
      ret = OB_UNKNOWN_OBJ;
      LOG_ERROR("Unknown expr item to serialize", K(ret), K_(item_type));
    }
  }
  return ret;
}

int ObPostExprItem::deserialize(ObIAllocator& alloc, const char* buf, const int64_t data_len, int64_t& pos)
{
  int ret = OB_SUCCESS;
  OB_UNIS_DECODE(item_type_);
  if (OB_SUCC(ret)) {
    if (T_REF_COLUMN == item_type_) {
      OB_UNIS_DECODE(v2_.cell_index_);
      OB_UNIS_DECODE(accuracy_);
    } else if (IS_DATATYPE_OR_QUESTIONMARK_OP(item_type_)) {
      ObObj tmp;
      OB_UNIS_DECODE(tmp);
      ObObj local_mem_obj;
      if (OB_FAIL(deep_copy_obj(alloc, tmp, local_mem_obj))) {
        LOG_WARN("failed to deep copy obj", K(ret));
      } else {
        new (&v2_.v1_) ObObj(local_mem_obj);
        OB_UNIS_DECODE(accuracy_);
      }
    } else if (IS_EXPR_OP(item_type_)) {
      ObExprOperatorFactory factory(alloc);
      if (OB_FAIL(factory.alloc(item_type_, v2_.op_))) {
        LOG_WARN("fail to alloc expr_op", K(ret));
      } else if (OB_ISNULL(v2_.op_)) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("failed to allc expr operator", K(ret), K_(item_type));
      } else {
        OB_UNIS_DECODE(*v2_.op_);
      }
    } else {
      ret = OB_UNKNOWN_OBJ;
      LOG_ERROR("Unknown expr item to deserialize", K(ret), K_(item_type));
    }
  }
  return ret;
}

DEFINE_GET_SERIALIZE_SIZE(ObPostExprItem)
{
  int64_t len = 0;
  OB_UNIS_ADD_LEN(item_type_);
  if (T_REF_COLUMN == item_type_) {
    OB_UNIS_ADD_LEN(v2_.cell_index_);
    OB_UNIS_ADD_LEN(accuracy_);
  } else if (IS_DATATYPE_OR_QUESTIONMARK_OP(item_type_)) {
    ObObj tmp = get_obj();
    OB_UNIS_ADD_LEN(tmp);
    OB_UNIS_ADD_LEN(accuracy_);
  } else if (IS_EXPR_OP(item_type_)) {
    OB_UNIS_ADD_LEN(*v2_.op_);
  } else {
    LOG_ERROR("Unknown expr item to serialize", K_(item_type));
  }
  return len;
}

////////////////////////////////////////////////////////////////

ObPostfixExpression::ObPostfixExpression(ObIAllocator& alloc, int64_t item_count)
    : post_exprs_(), str_buf_(alloc), output_column_count_(1)
{
  UNUSED(item_count);
}

ObPostfixExpression::~ObPostfixExpression()
{
  reset();
}

void ObPostfixExpression::reset()
{
  data_clear();
}

void ObPostfixExpression::data_clear()
{
  post_exprs_.reset(str_buf_);
  output_column_count_ = 1;
}

int ObPostfixExpression::assign(const ObPostfixExpression& other)
{
  int ret = OB_SUCCESS;
  if (&other != this) {
    data_clear();
    if (OB_FAIL(post_exprs_.reserve(other.post_exprs_.count(), str_buf_))) {
      LOG_WARN("failed to reserve", K(ret), "item_count", other.post_exprs_.count());
    } else {
      ObPostExprItem item_clone;
      for (int64_t i = 0; OB_SUCC(ret) && i < other.post_exprs_.count(); ++i) {
        const ObPostExprItem& item = other.post_exprs_[i];
        if (OB_FAIL(ob_write_expr_item(str_buf_, item, item_clone, NEW_OP_WHEN_COPY))) {
          LOG_WARN("failed to deep copy expr item", K(ret));
        } else if (OB_FAIL(post_exprs_.push_back(item_clone))) {
          LOG_WARN("failed to push into array", K(ret));
        }
      }  // end for
      output_column_count_ = other.output_column_count_;
    }
  }
  return ret;
}

int ObPostfixExpression::add_expr_item(const ObPostExprItem& item)
{
  int ret = OB_SUCCESS;
  ObPostExprItem item_clone;
  if (OB_FAIL(ob_write_expr_item(str_buf_, item, item_clone, NO_NEW_OP_WHEN_COPY))) {
    LOG_WARN("failed to deep copy expr item", K(ret));
  } else if (OB_FAIL(post_exprs_.push_back(item_clone))) {
    LOG_WARN("failed to push into array", K(ret));
  }
  return ret;
}

int ObPostfixExpression::generate_idx_for_regexp_ops(int16_t& cur_regexp_op_count)
{
  /*please note that, cur_regexp_op_count is a reference of a variable in ObCodeGeneratorImpl
   * it is used as a total counter here
   * This function maybe be called many times within different exprs
   * so, you should NOT set cur_regexp_op_count to be 0 here.
   */
  int ret = OB_SUCCESS;
  for (int64_t i = 0; OB_SUCC(ret) && i < post_exprs_.count(); ++i) {
    if (T_OP_REGEXP == post_exprs_.at(i).get_item_type()) {
      ObExprRegexp* regexp_op = static_cast<ObExprRegexp*>(post_exprs_.at(i).get_expr_operator());
      if (OB_ISNULL(regexp_op)) {
        ret = OB_BAD_NULL_ERROR;
        LOG_WARN("regexp op is null", K(ret));
      } else {
        regexp_op->set_regexp_idx(cur_regexp_op_count++);
      }
    }
  }
  return ret;
}

int ObPostfixExpression::calc(common::ObExprCtx& expr_ctx, const common::ObNewRow& row, ObObj& result_val) const
{
  int ret = OB_SUCCESS;
  int64_t last_idx = post_exprs_.count() - 1;
  if (OB_LIKELY(1 == post_exprs_.count()) && OB_LIKELY(post_exprs_.at(0).can_get_value_directly())) {
    const ObObj* value = NULL;
    if (OB_FAIL(post_exprs_.at(0).get_item_value_directly(*expr_ctx.phy_plan_ctx_, row, value)) || OB_ISNULL(value)) {
      ret = COVER_SUCC(OB_ERR_UNEXPECTED);
      LOG_WARN("get item value directly failed", K(ret), K(row), K_(post_exprs));
    } else if (!expr_ctx.is_pre_calculation_) {
      // in pre calculation, if only one question mark expr, return the question mark expression
      // result directly, even if it is a param array, this is to avoid constructing a param array
      // in the pre calculation
      if (OB_FAIL(ObSqlExpressionUtil::expand_array_params(expr_ctx, *value, value))) {
        LOG_WARN("expand array params failed", K(ret), KPC(value));
      }
    }
    if (OB_SUCC(ret)) {
      result_val = *value;
    }
  } else if (OB_UNLIKELY(post_exprs_.at(last_idx).get_item_type() == T_OP_SHADOW_UK_PROJECT)) {
    // fast pass for shadow unique key project
    if (OB_FAIL(uk_fast_project(expr_ctx, row, result_val))) {
      LOG_WARN("fail to do uk fast project", K(ret));
    }
  } else {
    ObNewRow result_row;
    result_row.cells_ = &result_val;
    result_row.count_ = 1;
    if (OB_FAIL(calc_result_row(expr_ctx, row, result_row))) {
      LOG_WARN("fail to calc result list", K(ret));
    } else {
      result_val = result_row.cells_[0];
    }
  }
  return ret;
}

int ObPostfixExpression::calc(
    common::ObExprCtx& expr_ctx, const common::ObNewRow& row1, const common::ObNewRow& row2, ObObj& result_val) const
{
  int ret = OB_SUCCESS;
  ObNewRow result_row;
  result_row.cells_ = &result_val;
  result_row.count_ = 1;
  if (OB_FAIL(calc_result_row(expr_ctx, row1, row2, result_row))) {
    LOG_WARN("fail to calc result list", K(ret), K(row1), K(row2));
  } else {
    result_val = result_row.cells_[0];
  }
  return ret;
}

inline int ObPostfixExpression::uk_fast_project(ObExprCtx& expr_ctx, const ObNewRow& row, ObObj& result_val) const
{
  int ret = OB_SUCCESS;
  int64_t expr_cnt = post_exprs_.count();
  const int64_t unique_key_cnt = expr_cnt - 2;
  if (OB_UNLIKELY(expr_cnt < 3)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("expr cnt is invalid", K(expr_cnt));
  } else if (OB_UNLIKELY(!expr_ctx.row_ctx_.is_uk_checked_)) {
    ObArray<int64_t> projector;
    for (int64_t i = 0; OB_SUCC(ret) && i < unique_key_cnt; ++i) {
      if (OB_UNLIKELY(post_exprs_.at(i).get_item_type() != T_REF_COLUMN)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("post expr item is invalid", K(post_exprs_.at(i)));
      } else {
        const int64_t col_idx = post_exprs_.at(i).get_column();
        if (OB_FAIL(projector.push_back(col_idx))) {
          LOG_WARN("fail to push back projector", K(ret));
        }
      }
    }
    if (OB_SUCC(ret)) {
      if (OB_FAIL(ObUniqueIndexRowTransformer::check_need_shadow_columns(row,
              static_cast<ObCompatibilityMode>(THIS_WORKER.get_compatibility_mode()),
              unique_key_cnt,
              &projector,
              expr_ctx.row_ctx_.is_uk_cnt_null_))) {
        LOG_WARN("fail to check need shadow columns", K(ret));
      }
    }
    expr_ctx.row_ctx_.is_uk_checked_ = true;
  }
  if (OB_SUCC(ret)) {
    const ObPostExprItem& item = post_exprs_.at(unique_key_cnt);
    if (!expr_ctx.row_ctx_.is_uk_cnt_null_) {
      result_val.set_null();
    } else if (OB_UNLIKELY(item.get_item_type() != T_REF_COLUMN)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("post expr item is invalid", K(item));
    } else {
      int64_t col_idx = item.get_column();
      if (OB_UNLIKELY(col_idx < 0) || OB_UNLIKELY(col_idx >= row.count_)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("column index is invalid", K(col_idx), K(row.count_));
      } else {
        result_val = row.cells_[col_idx];
      }
    }
  }
  return ret;
}

int ObPostfixExpression::calc_result_row(ObExprCtx& expr_ctx, const common::ObNewRow& row, ObNewRow& result_row) const
{
  int ret = OB_SUCCESS;
  // fast path for single ref column or question mark.
  if (1 == post_exprs_.count() &&
      (post_exprs_[0].get_item_type() == T_REF_COLUMN || post_exprs_[0].get_item_type() == T_QUESTIONMARK)) {
    const ObPostExprItem& item = post_exprs_[0];
    if (item.get_item_type() == T_REF_COLUMN) {
      int64_t idx = item.get_column();
      if (OB_UNLIKELY(idx < 0 || idx >= row.count_)) {
        ret = OB_ARRAY_OUT_OF_RANGE;
        LOG_WARN("cell index out of range", K(ret), K(idx), K_(row.count));
      } else {
        result_row.cells_[0] = row.cells_[idx];
      }
    } else {  // T_QUESTIONMARK
      const ObObj* obj = NULL;
      if (OB_FAIL(item.get_indirect_const(*expr_ctx.phy_plan_ctx_, obj))) {
        LOG_WARN("fail to get obj", K(ret));
      } else if (!expr_ctx.is_pre_calculation_) {
        // in pre calculation, if only one question mark expr, return the question mark expression
        // result directly, even if it is a param array, this is to avoid constructing a param array
        // in the pre calculation
        if (OB_FAIL(ObSqlExpressionUtil::expand_array_params(expr_ctx, *obj, obj))) {
          LOG_WARN("expand array params failed", K(ret), KPC(obj));
        }
      }
      if (OB_SUCC(ret)) {
        result_row.cells_[0] = *obj;
      }
    }
  } else {
    // infix_expr_ is need for parameter lazy evaluation in infix expression,
    // set to NULL to avoid evaluate in postfix expression.
    expr_ctx.infix_expr_ = NULL;

    int64_t idx = 0;
    static RLOCAL(int64_t, stack_top);
    int64_t stack_start = stack_top;
    ObObj* stack = NULL;
    auto* the_stack = GET_TSI_MULT(ObPostfixExpressionCalcStack, 1);
    if (OB_ISNULL(the_stack)) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_ERROR("no memory", K(ret));
    }
    if (OB_FAIL(ret)) {
      LOG_WARN("no memory or deep copy has failed", K(ret));
    } else if (OB_ISNULL(result_row.cells_)) {
      LOG_WARN("result row cells is null", K(ret));
    } else {
      result_row.cells_[0].set_type(ObMaxType);
      stack = the_stack->stack_;
      const int64_t expr_len = post_exprs_.count();
      for (idx = 0; OB_SUCC(ret) && idx < expr_len; ++idx) {
        if (OB_UNLIKELY(stack_top >= ObPostfixExpressionCalcStack::STACK_SIZE)) {
          ret = OB_SIZE_OVERFLOW;
          LOG_WARN("calculation stack overflow", K(+stack_top), K(idx), K(expr_len));
        } else {
          const ObPostExprItem& item = post_exprs_[idx];
          switch (item.get_item_type()) {
            case T_OP_AGG_PARAM_LIST: {
              if (OB_FAIL(calc_agg_param_list(result_row, item, stack, stack_top))) {
                LOG_WARN("failed to calc agg param list", K(ret), K_(post_exprs));
              }
              break;
            }
            case T_REF_COLUMN: {
              if (OB_FAIL(calc_ref_column(row, result_row, item, stack, stack_top))) {
                LOG_WARN("failed to calc ref column", K(ret), K_(post_exprs));
              }
              break;
            }
            case T_QUESTIONMARK: {
              if (OB_FAIL(calc_question_mark(expr_ctx, result_row, item, stack, stack_top))) {
                LOG_WARN("failed to calc question mark", K(ret), K_(post_exprs));
              }
              break;
            }
            default: {
              if (OB_FAIL(calc_other_op(expr_ctx, item, stack, stack_top))) {
                LOG_WARN("failed to calc other op", K(ret), K_(post_exprs));
              }
              break;
            }
          }  // end switch
        }    // end else
      }      // end for

      if (OB_SUCC(ret) && ObMaxType == result_row.cells_[0].get_type()) {
        if (OB_UNLIKELY(idx != expr_len || stack_top <= 0 || 1 != result_row.count_ || 1 != output_column_count_)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("idx not equal to expr_len, or stack top less than 0, or cell or column count is not 1",
              K(ret),
              K(idx),
              K(expr_len),
              K(+stack_top),
              K(result_row.count_),
              K_(output_column_count));
        } else {
          result_row.cells_[0] = stack[--stack_top];
        }
      }
    }
    stack_top = stack_start;
  }
  return ret;
}

int ObPostfixExpression::calc_result_row(
    ObExprCtx& expr_ctx, const common::ObNewRow& row1, const common::ObNewRow& row2, ObNewRow& result_row) const
{
  int ret = OB_SUCCESS;
  int64_t idx = 0;
  static RLOCAL(int64_t, stack_top);
  int64_t stack_start = stack_top;
  ObObj* stack = NULL;
  auto* the_stack = GET_TSI_MULT(ObPostfixExpressionCalcStack, 2);
  if (OB_ISNULL(the_stack)) {
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_ERROR("no memory");
  }

  // infix_expr_ is need for parameter lazy evaluation in infix expression,
  // set to NULL to avoid evaluate in postfix expression.
  expr_ctx.infix_expr_ = NULL;

  if (OB_FAIL(ret)) {
    LOG_WARN("no memory or deep copy has failed", K(ret));
  } else if (OB_ISNULL(result_row.cells_)) {
    LOG_WARN("result row cells is null", K(ret));
  } else {
    result_row.cells_[0].set_type(ObMaxType);
    stack = the_stack->stack_;
    const int64_t expr_len = post_exprs_.count();
    for (idx = 0; OB_SUCC(ret) && idx < expr_len; ++idx) {
      if (OB_UNLIKELY(stack_top >= ObPostfixExpressionCalcStack::STACK_SIZE)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("calculation stack overflow", K(+stack_top), K(idx), K(expr_len));
      } else {
        const ObPostExprItem& item = post_exprs_[idx];
        switch (item.get_item_type()) {
          case T_OP_AGG_PARAM_LIST: {
            if (OB_FAIL(calc_agg_param_list(result_row, item, stack, stack_top))) {
              LOG_WARN("failed to calc agg param list", K(ret));
            }
            break;
          }
          case T_REF_COLUMN: {
            if (OB_FAIL(calc_ref_column(row1, row2, result_row, item, stack, stack_top))) {
              LOG_WARN("failed to calc ref column", K(ret));
            }
            break;
          }
          case T_QUESTIONMARK: {
            if (OB_FAIL(calc_question_mark(expr_ctx, result_row, item, stack, stack_top))) {
              LOG_WARN("failed to calc question mark", K(ret));
            }
            break;
          }
          default: {
            if (OB_FAIL(calc_other_op(expr_ctx, item, stack, stack_top))) {
              LOG_WARN("failed to calc other op", K(ret));
            }
            break;
          }
        }  // end switch
      }    // end of else
    }      // end of for

    if (OB_SUCC(ret) && ObMaxType == result_row.cells_[0].get_type()) {
      if (OB_UNLIKELY(idx != expr_len || stack_top <= 0 || 1 != result_row.count_ || 1 != output_column_count_)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("idx not equal to expr_len, or stack top less than 0, or cell or column count is not 1",
            K(ret),
            K(idx),
            K(expr_len),
            K(+stack_top),
            K(result_row.count_),
            K_(output_column_count));
      } else {
        result_row.cells_[0] = stack[--stack_top];
      }
    }
  }
  stack_top = stack_start;
  return ret;
}

OB_INLINE int ObPostfixExpression::calc_agg_param_list(
    ObNewRow& result_row, const ObPostExprItem& item, ObObj* stack, int64_t stack_top) const
{
  int ret = OB_SUCCESS;
  const ObExprOperator* agg_param_list = item.get_expr_operator();
  if (OB_ISNULL(stack) || OB_ISNULL(agg_param_list) || OB_ISNULL(result_row.cells_) ||
      OB_UNLIKELY(stack_top < 0 || stack_top >= ObPostfixExpressionCalcStack::STACK_SIZE)) {
    ret = OB_BAD_NULL_ERROR;
    LOG_WARN("something is null, or stack_top out of range",
        K(ret),
        K(stack),
        K(agg_param_list),
        K_(result_row.cells),
        K(stack_top));
  } else {
    int32_t param_num = agg_param_list->get_real_param_num() * agg_param_list->get_row_dimension();
    if (OB_UNLIKELY(
            !(&item == &post_exprs_.at(post_exprs_.count() - 1) && T_OP_AGG_PARAM_LIST == agg_param_list->get_type() &&
                ObExprOperator::NOT_ROW_DIMENSION != agg_param_list->get_row_dimension() && param_num <= stack_top &&
                param_num == result_row.count_ && param_num == output_column_count_))) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("something is invalid",
          K(ret),
          K(agg_param_list->get_type()),
          K(agg_param_list->get_row_dimension()),
          K(param_num),
          K(stack_top),
          K_(result_row.count),
          K_(output_column_count));
    } else {
      for (int64_t i = 0, j = stack_top - param_num; OB_SUCC(ret) && i < param_num; ++i, ++j) {
        result_row.cells_[i] = stack[j];
      }
    }
  }
  return ret;
}

OB_INLINE int ObPostfixExpression::calc_ref_column(
    const ObNewRow& row, ObNewRow& result_row, const ObPostExprItem& item, ObObj* stack, int64_t& stack_top) const
{
  int ret = OB_SUCCESS;
  int64_t cell_idx = item.get_column();
  if (OB_ISNULL(stack) || OB_ISNULL(row.cells_) || OB_ISNULL(result_row.cells_) ||
      OB_UNLIKELY(stack_top < 0 || stack_top >= ObPostfixExpressionCalcStack::STACK_SIZE)) {
    ret = OB_BAD_NULL_ERROR;
    LOG_WARN("something is null, or stack_top out of range",
        K(ret),
        K(stack),
        K_(row.cells),
        K_(result_row.cells),
        K(stack_top));
  } else if (OB_UNLIKELY(cell_idx < 0 || cell_idx >= row.count_)) {
    ret = OB_ARRAY_OUT_OF_RANGE;
    LOG_WARN("cell_index out of range", K(ret), K(cell_idx), K_(row.count));
  } else {
    stack[stack_top] = row.cells_[cell_idx];
    if (OB_UNLIKELY(ObBitType == row.cells_[cell_idx].get_type())) {
      // use object scale to store bit length
      stack[stack_top].set_scale(item.get_accuracy().get_precision());
    } else if (-1 != item.get_accuracy().get_scale()) {
      stack[stack_top].set_scale(item.get_accuracy().get_scale());
    }
    ++stack_top;
  }
  return ret;
}

OB_INLINE int ObPostfixExpression::calc_ref_column(const ObNewRow& row1, const ObNewRow& row2, ObNewRow& result_row,
    const ObPostExprItem& item, ObObj* stack, int64_t& stack_top) const
{
  int ret = OB_SUCCESS;
  int64_t cell_idx = item.get_column();
  if (OB_ISNULL(stack) || OB_ISNULL(row1.cells_) || OB_ISNULL(row2.cells_) || OB_ISNULL(result_row.cells_) ||
      OB_UNLIKELY(stack_top < 0 || stack_top >= ObPostfixExpressionCalcStack::STACK_SIZE)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("something is null, or stack_top out of range",
        K(ret),
        K(stack),
        K_(row1.cells),
        K_(row2.cells),
        K_(result_row.cells),
        K(stack_top));
  } else if (OB_UNLIKELY(cell_idx < 0 || cell_idx >= row1.count_ + row2.count_)) {
    ret = OB_ARRAY_OUT_OF_RANGE;
    LOG_WARN("cell_index out of range", K(ret), K(cell_idx), K_(row1.count), K_(row2.count));
  } else {
    ObObj& obj = (cell_idx < row1.count_) ? row1.cells_[cell_idx] : row2.cells_[cell_idx - row1.count_];
    if (1 == post_exprs_.count()) {
      if (OB_UNLIKELY(!(1 == result_row.count_ && 1 == output_column_count_))) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("cell or column count is not 1", K(ret), K(result_row.count_), K_(output_column_count));
      } else {
        result_row.cells_[0] = obj;
      }
    } else {
      stack[stack_top] = obj;
      if (OB_UNLIKELY(ObBitType == obj.get_type())) {
        // use object scale to store bit length
        stack[stack_top++].set_scale(item.get_accuracy().get_precision());
      } else {
        stack[stack_top++].set_scale(item.get_accuracy().get_scale());
      }
    }
  }
  return ret;
}

OB_INLINE int ObPostfixExpression::calc_question_mark(
    ObExprCtx& expr_ctx, ObNewRow& result_row, const ObPostExprItem& item, ObObj* stack, int64_t& stack_top) const
{
  int ret = OB_SUCCESS;
  const ObObj* obj = NULL;
  if (OB_ISNULL(stack) || OB_ISNULL(result_row.cells_) || OB_ISNULL(expr_ctx.phy_plan_ctx_) ||
      OB_UNLIKELY(stack_top < 0 || stack_top >= ObPostfixExpressionCalcStack::STACK_SIZE)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("something is null, or stack_top out of range",
        K(ret),
        K(stack),
        K_(result_row.cells),
        K(stack_top),
        K_(expr_ctx.phy_plan_ctx));
  } else if (OB_FAIL(item.get_indirect_const(*expr_ctx.phy_plan_ctx_, obj))) {
    LOG_WARN("failed to get value obj", K(ret));
  } else if (OB_FAIL(ObSqlExpressionUtil::expand_array_params(expr_ctx, *obj, obj))) {
    LOG_WARN("expand array params failed", K(ret), KPC(obj));
  } else {
    stack[stack_top] = *obj;
    stack_top++;
  }
  return ret;
}

OB_INLINE int ObPostfixExpression::calc_other_op(
    ObExprCtx& expr_ctx, const ObPostExprItem& item, ObObj* stack, int64_t& stack_top) const
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(stack)) {
    ret = OB_BAD_NULL_ERROR;
    LOG_WARN("stack is null", K(ret));
  } else if (IS_DATATYPE_OP(item.get_item_type())) {
    stack[stack_top] = item.get_obj();
    stack_top++;
  } else if (IS_EXPR_OP(item.get_item_type())) {
    const ObExprOperator* expr_op = item.get_expr_operator();
    if (OB_ISNULL(expr_op)) {
      ret = OB_BAD_NULL_ERROR;
      LOG_WARN("expr_op is null", K(ret), K(item.get_item_type()));
    } else if (OB_FAIL(expr_op->call(stack, stack_top, expr_ctx))) {
      LOG_WARN("failed to call expr operator", K(ret), "expr_name", item.get_expr_operator()->get_name(), K(item));
    }
  } else {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid expression operator", K(ret), "item_type", get_type_name(item.get_item_type()));
  }
  return ret;
}

bool ObPostfixExpression::is_equijoin_cond(
    int64_t& c1, int64_t& c2, ObObjType& cmp_type, ObCollationType& cmp_cs_type, bool& is_null_safe) const
{
  bool ret = false;
  if (post_exprs_.count() == 3) {
    if ((post_exprs_[2].get_item_type() == T_OP_EQ || post_exprs_[2].get_item_type() == T_OP_NSEQ) &&
        post_exprs_[1].get_item_type() == T_REF_COLUMN && post_exprs_[0].get_item_type() == T_REF_COLUMN) {
      c1 = post_exprs_[0].get_column();
      c2 = post_exprs_[1].get_column();
      cmp_type = post_exprs_[2].get_expr_operator()->get_result_type().get_calc_type();
      cmp_cs_type = post_exprs_[2].get_expr_operator()->get_result_type().get_calc_collation_type();
      if (post_exprs_[2].get_item_type() == T_OP_NSEQ) {
        is_null_safe = true;
      }
      ret = true;
    }
  }
  return ret;
}

DEFINE_SERIALIZE(ObPostfixExpression)
{
  int ret = OB_SUCCESS;
  int64_t N = post_exprs_.count();
  OB_UNIS_ENCODE_ARRAY(post_exprs_.get_ptr(), N);
  OB_UNIS_ENCODE(output_column_count_);
  return ret;
}

DEFINE_DESERIALIZE(ObPostfixExpression)
{
  int ret = OB_SUCCESS;
  data_clear();
  int64_t item_count = 0;
  ObPostExprItem item;
  OB_UNIS_DECODE(item_count);
  if (OB_SUCC(ret)) {
    if (item_count > 0 && OB_FAIL(post_exprs_.reserve(item_count, str_buf_))) {
      LOG_WARN("failed to reserve", K(ret), K(item_count));
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < item_count; ++i) {
        if (OB_FAIL(item.deserialize(str_buf_, buf, data_len, pos))) {
          LOG_WARN("fail to deserialize post_item", K(ret));
        } else if (OB_FAIL(post_exprs_.push_back(item))) {
          LOG_WARN("failed to push into array", K(ret));
        }
      }  // end for
      OB_UNIS_DECODE(output_column_count_);
    }
  }
  return ret;
}

DEFINE_GET_SERIALIZE_SIZE(ObPostfixExpression)
{
  int64_t len = 0;
  int64_t N = post_exprs_.count();
  OB_UNIS_ADD_LEN_ARRAY(post_exprs_.get_ptr(), N);
  OB_UNIS_ADD_LEN(output_column_count_);
  return len;
}

int64_t ObPostfixExpression::to_string(char* buf, const int64_t buf_len) const
{
  int64_t pos = 0;
  J_ARRAY_START();
  for (int i = 0; i < post_exprs_.count(); ++i) {
    if (0 != i) {
      J_COMMA();
    }
    BUF_PRINTO(post_exprs_[i]);
  }  // end for
  J_ARRAY_END();
  return pos;
}
}  // namespace sql
}  // namespace oceanbase
