Files
oceanbase/src/sql/engine/expr/ob_expr_operator.h

1754 lines
69 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_SQL_OB_EXPR_OPERATOR_H_
#define OCEANBASE_SQL_OB_EXPR_OPERATOR_H_
#include "share/ob_define.h"
#include "share/ob_errno.h"
#include <math.h>
#include "lib/objectpool/ob_tc_factory.h"
#include "lib/utility/ob_print_utils.h"
#include "lib/timezone/ob_timezone_info.h"
#include "lib/container/ob_iarray.h"
#include "share/ob_i_sql_expression.h"
#include "share/config/ob_server_config.h"
#include "share/datum/ob_datum_funcs.h"
#include "common/expression/ob_expr_string_buf.h"
#include "share/object/ob_obj_cast.h"
#include "common/object/ob_obj_compare.h"
#include "common/ob_accuracy.h"
#include "rpc/obmysql/ob_mysql_global.h"
#include "sql/parser/ob_item_type.h"
#include "sql/engine/expr/ob_expr_res_type.h"
#include "sql/engine/expr/ob_expr.h"
#include "sql/engine/expr/ob_expr_cmp_func.h"
#define GET_EXPR_CTX(ClassType, ctx, id) static_cast<ClassType*>((ctx).get_expr_op_ctx(id))
namespace oceanbase {
namespace sql {
class ObRawExpr;
class ObExprCGCtx;
class ObSubQueryIterator;
enum CollectionPredRes {
COLL_PRED_INVALID = -1,
COLL_PRED_FALSE,
COLL_PRED_TRUE,
COLL_PRED_NULL,
COLL_PRED_FIRST_COLL_ZERO,
COLL_PRED_SECOND_COLL_ZERO,
COLL_PRED_BOTH_COLL_ZERO,
};
class ObFuncInputType {
public:
OB_UNIS_VERSION_V(1);
public:
ObFuncInputType() : calc_meta_(), max_length_(0), flag_(0)
{}
ObFuncInputType(common::ObObjMeta calc_meta, common::ObLength max_length, uint32_t flag)
: calc_meta_(calc_meta), max_length_(max_length), flag_(flag)
{
if (OB_UNLIKELY(calc_meta.get_type() >= common::ObMaxType)) {
SQL_LOG(ERROR, "the wrong type");
}
}
common::ObObjType get_calc_type() const
{
return calc_meta_.get_type();
}
common::ObLength get_length() const
{
return max_length_;
}
const common::ObObjMeta& get_calc_meta() const
{
return calc_meta_;
}
common::ObLength get_max_length() const
{
return max_length_;
}
bool is_zerofill() const
{
return flag_ & OB_MYSQL_ZEROFILL_FLAG;
}
TO_STRING_KV(N_CALC_META, calc_meta_, N_LENGTH, max_length_, N_FLAG, flag_);
private:
// connvert ObObj to this type
common::ObObjMeta calc_meta_;
// for zerofill
common::ObLength max_length_;
uint32_t flag_;
};
class ObExprOperatorCtx {
public:
ObExprOperatorCtx()
{}
virtual ~ObExprOperatorCtx()
{}
virtual int64_t to_string(char* buffer, int64_t buf_len) const
{
UNUSED(buffer);
UNUSED(buf_len);
return 0;
}
};
typedef common::ObIArray<common::ObNewRowIterator*> RowIterIArray;
class ObIterExprCtx {
public:
ObIterExprCtx(ObExecContext& ctx, common::ObIAllocator& allocator)
: iter_expr_ctxs_(allocator), index_scan_iters_(NULL), ctx_(ctx), allocator_(allocator), cur_row_(NULL)
{}
int init(uint64_t expr_size, RowIterIArray* iters)
{
index_scan_iters_ = iters;
return iter_expr_ctxs_.prepare_allocate(expr_size);
}
RowIterIArray* get_index_scan_iters()
{
return index_scan_iters_;
}
template <typename T>
int create_expr_op_ctx(uint64_t expr_id, T*& op_ctx)
{
int ret = common::OB_SUCCESS;
if (expr_id >= iter_expr_ctxs_.count()) {
ret = common::OB_INVALID_ARGUMENT;
SQL_ENG_LOG(WARN, "invalid expr id", K(expr_id), K(iter_expr_ctxs_.count()));
} else {
void* ptr = allocator_.alloc(sizeof(T));
if (NULL == ptr) {
ret = common::OB_ALLOCATE_MEMORY_FAILED;
SQL_ENG_LOG(WARN, "allocate memory for expr op ctx failed");
} else {
op_ctx = new (ptr) T();
iter_expr_ctxs_.at(expr_id) = op_ctx;
}
}
return ret;
}
template <typename T>
T* get_expr_op_ctx(uint64_t expr_id)
{
T* ret = NULL;
if (expr_id < iter_expr_ctxs_.count()) {
ret = static_cast<T*>(iter_expr_ctxs_.at(expr_id));
}
return ret;
}
ObExecContext& get_exec_context()
{
return ctx_;
}
void set_cur_row(common::ObNewRow* cur_row)
{
cur_row_ = cur_row;
}
common::ObNewRow* get_cur_row() const
{
return cur_row_;
}
private:
common::ObFixedArray<ObExprOperatorCtx*, common::ObIAllocator> iter_expr_ctxs_;
RowIterIArray* index_scan_iters_;
ObExecContext& ctx_;
common::ObIAllocator& allocator_;
common::ObNewRow* cur_row_;
};
class ObFastExprOperator {
public:
ObFastExprOperator(ObExprOperatorType operator_type) : op_type_(operator_type)
{}
virtual ~ObFastExprOperator()
{}
virtual int calc(common::ObExprCtx& expr_ctx, const common::ObNewRow& row, common::ObObj& result) const = 0;
inline ObExprOperatorType get_op_type() const
{
return op_type_;
}
virtual int assign(const ObFastExprOperator& other) = 0;
protected:
ObExprOperatorType op_type_;
};
class ObIterExprOperator {
OB_UNIS_VERSION_V(1);
public:
ObIterExprOperator() : expr_id_(common::OB_INVALID_ID), expr_type_(T_INVALID)
{}
virtual ~ObIterExprOperator()
{}
virtual int get_next_row(ObIterExprCtx& expr_ctx, const common::ObNewRow*& result) const = 0;
inline uint64_t get_expr_id() const
{
return expr_id_;
}
inline void set_expr_id(uint64_t expr_id)
{
expr_id_ = expr_id;
}
inline void set_expr_type(ObExprOperatorType expr_type)
{
expr_type_ = expr_type;
}
inline ObExprOperatorType get_expr_type() const
{
return expr_type_;
}
TO_STRING_KV(K_(expr_id), K_(expr_type));
protected:
uint64_t expr_id_;
ObExprOperatorType expr_type_;
};
class ObExprOperator : public common::ObDLinkBase<ObExprOperator> {
OB_UNIS_VERSION_V(1);
public:
friend class ObRawExpr;
enum ObSqlParamNumFlag {
PARAM_NUM_UNKNOWN = -1,
MORE_THAN_ZERO = -2,
MORE_THAN_ONE = -3,
MORE_THAN_TWO = -4,
ZERO_OR_ONE = -5,
ONE_OR_TWO = -6,
TWO_OR_THREE = -7,
OCCUR_AS_PAIR = -8,
};
static const int32_t NOT_ROW_DIMENSION = -1;
ObExprOperator(common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num,
int32_t row_dimension = NOT_ROW_DIMENSION);
virtual ~ObExprOperator()
{}
virtual int assign(const ObExprOperator& other);
// initailize every expr operater's traits
// including eval_func_, inner_eval_func_, extra_
virtual int cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const;
// whether needs expression level's context. default is not needs;
// if need_rt_ctx, it should be put in corresponding child
// expression's implemention and it should define as following:
// virtual bool need_rt_ctx() const override { return true; }
virtual bool need_rt_ctx() const
{
return false;
}
// TODO : remove after all expr implemented in new engine.
// Check expr is default cg_expr() implement to detect the expr is supported in new engine.
bool is_default_expr_cg() const;
inline int32_t get_param_num() const
{
return param_num_;
}
inline int32_t get_real_param_num() const
{
return real_param_num_;
}
inline int32_t get_row_dimension() const
{
return row_dimension_;
}
inline const char* get_name() const
{
return name_;
};
virtual inline ObExprOperatorType get_type() const
{
return type_;
}
virtual inline void reset();
inline int32_t get_magic() const
{
return magic_;
};
inline ObRawExpr* get_raw_expr() const
{
return raw_expr_;
}
inline void set_magic(int32_t magic)
{
magic_ = magic;
};
inline bool is_called_in_sql() const
{
return is_called_in_sql_;
};
inline void set_is_called_in_sql(bool is_called_in_sql)
{
is_called_in_sql_ = is_called_in_sql;
};
inline uint64_t get_id() const
{
return id_;
};
inline void set_id(uint64_t id)
{
id_ = id;
};
inline const ObExprResType& get_result_type() const
{
return result_type_;
}
inline const common::ObIArray<ObFuncInputType>& get_input_types() const
{
return input_types_;
}
int set_input_types(const ObIExprResTypes& input_types); // convert ExprResTyp=>FuncInputType
inline void set_result_type(const ObExprResType& type)
{
result_type_ = type;
}
inline void set_result_type(const common::ObObjType& type)
{
result_type_.set_type(type);
}
inline void set_row_dimension(const int32_t row_dimension)
{
row_dimension_ = row_dimension;
}
inline void set_real_param_num(const int32_t param_num)
{
real_param_num_ = param_num;
};
inline void set_raw_expr(ObRawExpr* expr)
{
raw_expr_ = expr;
}
virtual int calc_result_type0(ObExprResType& type, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type1(ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3,
common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_typeN(
ObExprResType& type, ObExprResType* types_array, int64_t param_num, common::ObExprTypeCtx& type_ctx) const;
// define derive type from expr argument value
virtual int calc_result_type0(
ObExprResType& type, common::ObExprTypeCtx& type_ctx, common::ObIArray<common::ObObj*>& arg_arrs) const;
virtual int calc_result_type1(ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx,
common::ObIArray<common::ObObj*>& arg_arrs) const;
virtual int calc_result_type2(ObExprResType& type, ObExprResType& type1, ObExprResType& type2,
common::ObExprTypeCtx& type_ctx, common::ObIArray<common::ObObj*>& arg_arrs) const;
virtual int calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3,
common::ObExprTypeCtx& type_ctx, common::ObIArray<common::ObObj*>& arg_arrs) const;
virtual int calc_result_typeN(ObExprResType& type, ObExprResType* types_array, int64_t param_num,
common::ObExprTypeCtx& type_ctx, common::ObIArray<common::ObObj*>& arg_arrs) const;
// end define derive type from expr argment value
virtual int calc_result0(common::ObObj& result, common::ObExprCtx& expr_ctx) const;
virtual int calc_result1(common::ObObj& result, const common::ObObj& obj, common::ObExprCtx& expr_ctx) const;
virtual int calc_result2(
common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2, common::ObExprCtx& expr_ctx) const;
virtual int calc_result3(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
const common::ObObj& obj3, common::ObExprCtx& expr_ctx) const;
/**
* cal value
* @param[out] result
* @param[in] objs array ob input arguments
* @param[in] param_num number of obobj(value) const
*/
virtual int calc_resultN(
common::ObObj& result, const common::ObObj* objs_array, int64_t param_num, common::ObExprCtx& expr_ctx) const;
/**
* call the operation on the stack
* pop the input argument from the stack and push the result into it
* @param stack [in/out]
* @param stack_size [in/out]
*
* @return ob error
*/
virtual int call(common::ObObj* stack, int64_t& stack_size, common::ObExprCtx& expr_ctx) const;
// call() interface is used for postfix expression evaluation, will be discard.
// eval() is called in infix expression evaluation, support lazy evaluate.
virtual int eval(common::ObExprCtx& expr_ctx, common::ObObj& val, common::ObObj* params, int64_t param_num) const;
// parameter evaluation.
// NOTICE: %param must in %params array which passed by eval().
int param_eval(common::ObExprCtx& expr_ctx, const common::ObObj& param, const int64_t param_index) const;
static bool is_valid_nls_param(const common::ObString& nls_param_str);
inline bool is_param_lazy_eval() const
{
return param_lazy_eval_;
}
inline static bool is_type_valid(const common::ObObjType& type);
virtual bool need_charset_convert() const
{
return need_charset_convert_;
}
virtual int64_t to_string(char* buf, const int64_t buf_len) const
{
int64_t pos = 0;
J_OBJ_START();
J_KV(N_EXPR_TYPE,
get_type_name(type_),
N_EXPR_NAME,
name_,
N_PARAM_NUM,
param_num_,
N_DIM,
row_dimension_,
N_REAL_PARAM_NUM,
real_param_num_,
N_RESULT_TYPE,
result_type_,
N_INPUT_TYPE,
input_types_);
J_OBJ_END();
return pos;
}
public:
/*
Aggregate arguments for comparison, e.g: a=b, a LIKE b, a RLIKE b
- don't convert to @@character_set_connection if all arguments are numbers
- don't allow DERIVATION_NONE
*/
static int aggregate_charsets_for_comparison(common::ObObjMeta& type, const common::ObObjMeta* types,
int64_t param_num, const common::ObCollationType conn_coll_type);
static int aggregate_charsets_for_comparison(
ObExprResType& type, const ObExprResType* types, int64_t param_num, const common::ObCollationType conn_coll_type);
/*
Aggregate arguments for string result, e.g: CONCAT(a,b)
- convert to @@character_set_connection if all arguments are numbers
- allow DERIVATION_NONE
*/
static int aggregate_charsets_for_string_result(common::ObObjMeta& type, const common::ObObjMeta* types,
int64_t param_num, const common::ObCollationType conn_coll_type);
static int aggregate_charsets_for_string_result(
ObExprResType& type, const ObExprResType* types, int64_t param_num, const common::ObCollationType conn_coll_type);
static int aggregate_max_length_for_string_result(ObExprResType& type, const ObExprResType* types, int64_t param_num,
bool is_oracle_mode, const common::ObLengthSemantics default_length_semantics, bool need_merge_type = TRUE,
bool skip_null = FALSE);
/*
Aggregate arguments for string result, whe`.fn some comparison
is involved internally, only for: REPLACE(a,b,c) and SubStringIndex()
- convert to @@character_set_connection if all arguments are numbers
- disallow DERIVATION_NONE
*/
static int aggregate_charsets_for_string_result_with_comparison(common::ObObjMeta& type,
const common::ObObjMeta* types, int64_t param_num, const common::ObCollationType conn_coll_type);
static int aggregate_charsets_for_string_result_with_comparison(common::ObObjMeta& type, const ObExprResType* types,
int64_t param_num, const common::ObCollationType conn_coll_type);
static int aggregate_result_type_for_merge(ObExprResType& type, const ObExprResType* types, int64_t param_num,
const common::ObCollationType conn_coll_type, bool is_oracle_mode,
const common::ObLengthSemantics default_length_semantics, const sql::ObSQLSessionInfo* session,
bool need_merge_type = TRUE, bool skip_null = FALSE);
static int aggregate_result_type_for_case(ObExprResType& type, const ObExprResType* types, int64_t param_num,
const common::ObCollationType conn_coll_type, bool is_oracle_mode,
const common::ObLengthSemantics default_length_semantics, const sql::ObSQLSessionInfo* session,
bool need_merge_type = TRUE, bool skip_null = FALSE);
// oracle string's type deduce
static int aggregate_string_type_and_charset_oracle(const ObBasicSessionInfo& session,
const common::ObIArray<ObExprResType*>& params, ObExprResType& result, bool prefer_var_len_char = false);
static int deduce_string_param_calc_type_and_charset(
const ObBasicSessionInfo& session, const ObExprResType& result, common::ObIArray<ObExprResType*>& params);
typedef int (*calc_result_len_func)(const common::ObLengthSemantics param_ls, const common::ObLength param_len,
const bool byte_reach_limits, const common::ObLengthSemantics res_ls, common::ObLength& res_len);
static int sum_result_len(common::ObLength& res_len, common::ObLength delta_len)
{
res_len += delta_len;
return common::OB_SUCCESS;
}
static int max_result_len(common::ObLength& res_len, common::ObLength delta_len)
{
res_len = std::max(delta_len, res_len);
return common::OB_SUCCESS;
}
static common::ObCollationType get_default_collation_type(
common::ObObjType type, const ObBasicSessionInfo& session_info);
static int is_same_kind_type_for_case(const ObExprResType& type1, const ObExprResType& type2, bool& match);
static int aggregate_numeric_accuracy_for_merge(
ObExprResType& type, const ObExprResType* types, int64_t param_num, bool is_oracle_mode);
static int aggregate_temporal_accuracy_for_merge(ObExprResType& type, const ObExprResType* types, int64_t param_num);
static int aggregate_accuracy_for_merge(ObExprResType& type, const ObExprResType* types, int64_t param_num);
int calc_cmp_type2(ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2,
const common::ObCollationType coll_type) const;
int calc_cmp_type3(ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2,
const ObExprResType& type3, const common::ObCollationType coll_type) const;
int calc_trig_function_result_type1(ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx) const;
int calc_trig_function_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
public:
virtual common::ObCastMode get_cast_mode() const;
protected:
ObExpr* get_rt_expr(const ObRawExpr& raw_expr) const;
inline static void calc_result_flag1(ObExprResType& type, const ObExprResType& type1);
inline static void calc_result_flag2(ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2);
inline static void calc_result_flag3(
ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2, const ObExprResType& type3);
inline static void calc_result_flagN(ObExprResType& type, const ObExprResType* types, int64_t param_num);
static common::ObObjType get_calc_cast_type(common::ObObjType param_type, common::ObObjType calc_type);
static common::ObObjType enumset_calc_types_[common::ObMaxTC];
void disable_operand_auto_cast()
{
operand_auto_cast_ = false;
}
private:
// computation framework internally provided a universal datatype's converting
// method, which is able to convert param's type to input_types_. this may
// not be a expected behavior for some expression. If you want to prohibit
// this, please explictly call disable_operand_auto_cast() in constructor.
//
// @output: result should be store in stack
int cast_operand_type(common::ObObj* params, const int64_t param_num, common::ObExprCtx& expr_ctx) const;
int OB_INLINE cast_operand_type(common::ObObj& param, const ObFuncInputType& type, common::ObExprCtx& expr_ctx) const;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObExprOperator);
// types and constants
static const uint32_t OB_COLL_DISALLOW_NONE = 1;
static const uint32_t OB_COLL_ALLOW_NUMERIC_CONV = 2;
protected:
static int aggregate_collations(common::ObObjMeta& type, const common::ObObjMeta* types_array, int64_t param_num,
uint32_t flag, const common::ObCollationType conn_coll_type);
static int aggregate_charsets(common::ObObjMeta& type, const common::ObObjMeta* types, int64_t param_num,
uint32_t flags, const common::ObCollationType conn_coll_type);
static int aggregate_charsets(common::ObObjMeta& type, const ObExprResType* types, int64_t param_num, uint32_t flags,
const common::ObCollationType conn_coll_type);
// data members
int32_t magic_;
uint64_t id_;
const ObExprOperatorType type_; /* type defined in sql/ob_item_type.h */
const char* const name_;
const int32_t param_num_; /* expected param number*/
int32_t row_dimension_; /* if row, it is the number of row items, else -1 */
int32_t real_param_num_; /* if param is ObRowType, param_num_ mean num of row */
// is operand auto cast enabled, no need to serialize.
bool operand_auto_cast_;
// is param lazy evaluate supported, no need to serialize.
bool param_lazy_eval_;
ObExprResType result_type_;
// If you want to determine the meta information of each operand
// in the resolve phase (such as target type, zerofill, length, etc.),
// then you need to add @input_types_ and record the target type of
// the operand to it in the calc_result_type phase
//
// @details: In the calc_result_type stage, you can know all the information
// of the operator, especially the type of each operand to be converted
// during the operation. In the postfix expression calculation phase,
// the calculation framework will convert ObObj according to the
// type specified in @input_types_, and then call calc_result.
//
// No longer need to pay attention to the type of operand in calc_result, just assert the type.
//
typedef common::ObFixedArray<ObFuncInputType, common::ObIAllocator> ObExprOperatorInputTypeArray;
ObExprOperatorInputTypeArray input_types_;
// Indicates whether to perform automatic character set conversion, used in type inference, without serialization
bool need_charset_convert_;
ObRawExpr* raw_expr_;
bool is_called_in_sql_;
int64_t extra_serialize_;
};
class ObSQLSessionInfo;
const common::ObTimeZoneInfo* get_timezone_info(const ObSQLSessionInfo* session);
const common::ObObjPrintParams get_obj_print_params(const ObSQLSessionInfo* session);
const common::ObString* get_nls_formats(const ObSQLSessionInfo* session);
class ObPhysicalPlanCtx;
int64_t get_cur_time(ObPhysicalPlanCtx* phy_plan_ctx);
int get_tz_offset(const common::ObTimeZoneInfo* tz_info, int64_t& offset);
inline ObExprOperator::ObExprOperator(
common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num, int32_t row_dimension)
: magic_(0),
id_(common::OB_INVALID_ID),
type_(type),
name_(name),
param_num_(param_num),
row_dimension_(row_dimension),
real_param_num_(param_num),
operand_auto_cast_(true),
param_lazy_eval_(false),
result_type_(alloc),
input_types_(alloc),
need_charset_convert_(true),
raw_expr_(NULL),
is_called_in_sql_(true),
extra_serialize_(0)
{}
inline int ObExprOperator::calc_result_type0(
ObExprResType& type, common::ObExprTypeCtx& type_ctx, common::ObIArray<common::ObObj*>& arg_arrs) const
{
UNUSED(type);
UNUSED(type_ctx);
UNUSED(arg_arrs);
SQL_LOG(WARN, "not implement");
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_type1(ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx,
common::ObIArray<common::ObObj*>& arg_arrs) const
{
UNUSED(type);
UNUSED(type1);
UNUSED(type_ctx);
UNUSED(arg_arrs);
SQL_LOG(WARN, "not implement");
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_type2(ObExprResType& type, ObExprResType& type1, ObExprResType& type2,
common::ObExprTypeCtx& type_ctx, common::ObIArray<common::ObObj*>& arg_arrs) const
{
UNUSED(type);
UNUSED(type1);
UNUSED(type2);
UNUSED(type_ctx);
UNUSED(arg_arrs);
SQL_LOG(WARN, "not implement");
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2,
ObExprResType& type3, common::ObExprTypeCtx& type_ctx, common::ObIArray<common::ObObj*>& arg_arrs) const
{
UNUSED(type);
UNUSED(type1);
UNUSED(type2);
UNUSED(type3);
UNUSED(type_ctx);
UNUSED(arg_arrs);
SQL_LOG(WARN, "not implement");
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_typeN(ObExprResType& type, ObExprResType* types, int64_t param_num,
common::ObExprTypeCtx& type_ctx, common::ObIArray<common::ObObj*>& arg_arrs) const
{
UNUSED(type);
UNUSED(types);
UNUSED(param_num);
UNUSED(type_ctx);
UNUSED(arg_arrs);
SQL_LOG(ERROR, "not implement", K(type_), K(get_type_name(type_)));
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_type0(ObExprResType& type, common::ObExprTypeCtx& type_ctx) const
{
UNUSED(type);
UNUSED(type_ctx);
SQL_LOG(WARN, "not implement");
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_type1(
ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx) const
{
UNUSED(type);
UNUSED(type1);
UNUSED(type_ctx);
SQL_LOG(WARN, "not implement");
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const
{
UNUSED(type);
UNUSED(type1);
UNUSED(type2);
UNUSED(type_ctx);
SQL_LOG(WARN, "not implement");
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2,
ObExprResType& type3, common::ObExprTypeCtx& type_ctx) const
{
UNUSED(type);
UNUSED(type1);
UNUSED(type2);
UNUSED(type3);
UNUSED(type_ctx);
SQL_LOG(WARN, "not implement");
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result_typeN(
ObExprResType& type, ObExprResType* types, int64_t param_num, common::ObExprTypeCtx& type_ctx) const
{
UNUSED(type);
UNUSED(types);
UNUSED(param_num);
UNUSED(type_ctx);
SQL_LOG(ERROR, "not implement", K(type_), K(get_type_name(type_)));
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result0(common::ObObj& result, common::ObExprCtx& expr_ctx) const
{
UNUSED(result);
UNUSED(expr_ctx);
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result1(
common::ObObj& result, const common::ObObj& obj, common::ObExprCtx& expr_ctx) const
{
UNUSED(result);
UNUSED(obj);
UNUSED(expr_ctx);
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result2(
common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2, common::ObExprCtx& expr_ctx) const
{
UNUSED(result);
UNUSED(obj1);
UNUSED(obj2);
UNUSED(expr_ctx);
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_result3(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
const common::ObObj& obj3, common::ObExprCtx& expr_ctx) const
{
UNUSED(result);
UNUSED(obj1);
UNUSED(obj2);
UNUSED(obj3);
UNUSED(expr_ctx);
return common::OB_NOT_IMPLEMENT;
}
inline int ObExprOperator::calc_resultN(
common::ObObj& result, const common::ObObj* objs, int64_t param_num, common::ObExprCtx& expr_ctx) const
{
UNUSED(result);
UNUSED(objs);
UNUSED(param_num);
UNUSED(expr_ctx);
return common::OB_NOT_IMPLEMENT;
}
inline void ObExprOperator::reset()
{
common::ObDLinkBase<ObExprOperator>::reset();
row_dimension_ = NOT_ROW_DIMENSION;
result_type_.set_type(common::ObMaxType);
result_type_.reset();
input_types_.reset();
is_called_in_sql_ = true;
}
// may be a new mod can be defined for it
inline bool ObExprOperator::is_type_valid(const common::ObObjType& type)
{
common::ObObjTypeClass type_class = ob_obj_type_class(type);
return (common::ob_is_castable_type_class(type_class) || common::ObUnknownTC == type_class);
}
inline void ObExprOperator::calc_result_flag1(ObExprResType& type, const ObExprResType& type1)
{
if (type1.has_result_flag(OB_MYSQL_NOT_NULL_FLAG)) {
type.set_result_flag(OB_MYSQL_NOT_NULL_FLAG);
}
}
inline void ObExprOperator::calc_result_flag2(
ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2)
{
if (type1.has_result_flag(OB_MYSQL_NOT_NULL_FLAG) && type2.has_result_flag(OB_MYSQL_NOT_NULL_FLAG)) {
type.set_result_flag(OB_MYSQL_NOT_NULL_FLAG);
}
}
inline void ObExprOperator::calc_result_flag3(
ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2, const ObExprResType& type3)
{
if (type1.has_result_flag(OB_MYSQL_NOT_NULL_FLAG) && type2.has_result_flag(OB_MYSQL_NOT_NULL_FLAG) &&
type3.has_result_flag(OB_MYSQL_NOT_NULL_FLAG)) {
type.set_result_flag(OB_MYSQL_NOT_NULL_FLAG);
}
}
inline void ObExprOperator::calc_result_flagN(ObExprResType& type, const ObExprResType* types, int64_t param_num)
{
bool not_null = true;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 0)) {
SQL_LOG(ERROR, "null types or the wrong param_num");
} else {
for (int64_t i = 0; i < param_num; ++i) {
if (!types[i].has_result_flag(OB_MYSQL_NOT_NULL_FLAG)) {
not_null = false;
break;
}
}
if (not_null) {
type.set_result_flag(OB_MYSQL_NOT_NULL_FLAG);
}
}
}
////////////////////////////////////////////////////////////////
class ObFuncExprOperator : public ObExprOperator {
public:
ObFuncExprOperator(
common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num, int32_t dimension)
: ObExprOperator(alloc, type, name, param_num, dimension){};
virtual ~ObFuncExprOperator(){};
};
//
// In ObRelationalExprOperator, there are three concepts: res_type, cmp_type, calc_type
// The first two are relative to the expression; the latter one is relative to the parameters of the expression.
//
class ObRelationalExprOperator : public ObExprOperator {
public:
virtual int deserialize(const char* buf, const int64_t data_len, int64_t& pos) override;
public:
ObRelationalExprOperator(common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num,
int32_t dimension = NOT_ROW_DIMENSION)
: ObExprOperator(alloc, type, name, param_num, dimension), cmp_op_func2_(NULL)
{}
virtual ~ObRelationalExprOperator()
{}
/**
* general compare.
* use this func if you are NOT SURE the compare need cast or not.
* @param[out] result: true / false / -1 / 0 / 1 / null.
* @param[in] obj1
* @param[in] obj2
* @param[in] cmp_ctx
* @param[in] cast_ctx
* @param[in] cmp_op: CO_EQ / CO_LE / CO_LT / CO_GE / CO_GT / CO_NE / CO_CMP.
* @return ob error code.
*/
static int compare(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
const common::ObCompareCtx& cmp_ctx, common::ObCastCtx& cast_ctx, common::ObCmpOp cmp_op);
/**
* compare with no cast.
* use this func if you are SURE the compare NEED NOT cast.
* @param[out] result: true / false / -1 / 0 / 1 / null.
* @param[in] obj1
* @param[in] obj2
* @param[in] cmp_ctx
* @param[in] cmp_op: CO_EQ / CO_LE / CO_LT / CO_GE / CO_GT / CO_NE / CO_CMP.
* @param[out] need_cast: set to true if can't compare without cast, otherwise false.
* @return ob error code.
*/
OB_INLINE static int compare_nocast(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
const common::ObCompareCtx& cmp_ctx, common::ObCmpOp cmp_op, bool& need_cast)
{
return common::ObObjCmpFuncs::compare(result, obj1, obj2, cmp_ctx, cmp_op, need_cast);
}
/**
* compare with cast.
* use this func if you are SURE the compare always NEED cast.
* like ObExprBetween / ObExprNotBetween / ObExprField / ObExprStrcmp / ObExprOracleDecode.
* @param[out] result: true / false / -1 / 0 / 1 / null.
* @param[in] obj1
* @param[in] obj2
* @param[in] cmp_ctx
* @param[in] cast_ctx
* @param[in] cmp_op: CO_EQ / CO_LE / CO_LT / CO_GE / CO_GT / CO_NE / CO_CMP.
* @return ob error code.
*/
static int compare_cast(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
const common::ObCompareCtx& cmp_ctx, common::ObCastCtx& cast_ctx, common::ObCmpOp cmp_op);
/**
* general compare, null safe.
* use this func if you are NOT SURE the compare need cast or not.
* @param[out] result: -1 / 0 / 1.
* @param[in] obj1
* @param[in] obj2
* @param[in] cast_ctx
* @param[in] cmp_type
* @param[in] cmp_cs_type
* @return ob error code.
*/
static int compare_nullsafe(int64_t& result, const common::ObObj& obj1, const common::ObObj& obj2,
common::ObCastCtx& cast_ctx, common::ObObjType cmp_type, common::ObCollationType cmp_cs_type);
// determine the type used for comparison of the two types
// binary comparison
virtual int calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const override;
// deduce binary comparison result type and parameters types
static int deduce_cmp_type(const ObExprOperator& expr, ObExprResType& type, ObExprResType& type1,
ObExprResType& type2, common::ObExprTypeCtx& type_ctx);
// for between...and, not between...and etc.
// @todo need refactor, ....yzf....Thu, 6 Aug 2015....16:00....
virtual int calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3,
common::ObExprTypeCtx& type_ctx) const override;
virtual int calc_calc_type3(ObExprResType& type1, ObExprResType& type2, ObExprResType& type3,
common::ObExprTypeCtx& type_ctx, const common::ObObjType cmp_type) const;
int get_cmp_result_type3(ObExprResType& type, bool& need_no_cast, const ObExprResType* types, const int64_t param_num,
const sql::ObSQLSessionInfo& my_session);
// vector comparison, e.g. (a,b,c) > (1,2,3)
virtual int calc_result_typeN(
ObExprResType& type, ObExprResType* types, int64_t param_num, common::ObExprTypeCtx& type_ctx) const override;
virtual int calc_result2(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
common::ObExprCtx& expr_ctx, bool is_null_safe, common::ObCmpOp cmp_op) const;
virtual int calc_resultN(common::ObObj& result, const common::ObObj* objs_array, int64_t param_num,
common::ObExprCtx& expr_ctx, bool is_null_safe, common::ObCmpOp cmp_op) const;
static int is_equivalent(
const common::ObObjMeta& meta1, const common::ObObjMeta& meta2, const common::ObObjMeta& meta3, bool& result);
int assign(const ObExprOperator& other) override;
int set_cmp_func(const common::ObObjType type1, const common::ObObjType type2);
common::obj_cmp_func get_cmp_fun() const
{
return cmp_op_func2_;
}
// pure virtual but implemented, derived classes can use this implement.
virtual int cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const override = 0;
static int cg_row_cmp_expr(const int row_dim, common::ObIAllocator& allocator, const ObRawExpr& raw_expr,
const ObExprOperatorInputTypeArray& input_types, ObExpr& rt_expr);
static int cg_datum_cmp_expr(
const ObRawExpr& raw_expr, const ObExprOperatorInputTypeArray& input_types, ObExpr& rt_expr);
static int is_row_cmp(const ObRawExpr&, int& row_dim);
static int row_eval(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datm);
// row compare
// CAUTION: null safe equal row compare is not included.
static int row_cmp(
const ObExpr& expr, ObDatum& expr_datum, ObExpr** l_row, ObEvalCtx& l_ctx, ObExpr** r_row, ObEvalCtx& r_ctx);
OB_INLINE static int get_comparator_operands(const ObExpr& expr, ObEvalCtx& ctx, common::ObDatum*& left,
common::ObDatum*& right, ObDatum& result, bool& is_finish)
{
int ret = common::OB_SUCCESS;
if (OB_FAIL(expr.args_[0]->eval(ctx, left))) {
SQL_LOG(WARN, "left eval failed", K(ret));
} else if (left->is_null()) {
result.set_null();
is_finish = true;
} else if (OB_FAIL(expr.args_[1]->eval(ctx, right))) {
SQL_LOG(WARN, "right eval failed", K(ret));
} else if (right->is_null()) {
result.set_null();
is_finish = true;
} else { /* do nothing */
}
return ret;
}
static int get_equal_meta(common::ObObjMeta& meta, const common::ObObjMeta& meta1, const common::ObObjMeta& meta2);
static bool can_cmp_without_cast(
const ObExprResType& type1, const ObExprResType& type2, common::ObCmpOp cmp_op, const ObSQLSessionInfo& session);
protected:
static bool is_int_cmp_const_str(const ObExprResType* type1, const ObExprResType* type2, common::ObObjType& cmp_type);
OB_INLINE static common::ObCmpOp get_cmp_op(const ObExprOperatorType type)
{
/*
* maybe we can use associative array(table lookup) to get a better
* performance here. Yeah, just maybe, not absolutely. If you are free, you
* can have a profiling.
*/
common::ObCmpOp cmp_op = common::CO_MAX;
switch (type) {
case T_FUN_SYS_NULLIF: // nullif(e1, e2) check if e1 = e2
case T_OP_EQ: // fall through
case T_OP_NSEQ: // fall through
case T_OP_SQ_EQ: // fall through
case T_OP_SQ_NSEQ: {
cmp_op = common::CO_EQ;
break;
}
case T_OP_BTW: // a between b and c <==> b <= a and a <= c
// fall through
case T_OP_LE: // fall through
case T_OP_SQ_LE: {
cmp_op = common::CO_LE;
break;
}
case T_OP_NOT_BTW: // a not between b and c <==> a < b or c < a
// fall through
case T_OP_LT: // fall through
case T_OP_SQ_LT: {
cmp_op = common::CO_LT;
break;
}
case T_OP_GE: // fall through
case T_OP_SQ_GE: {
cmp_op = common::CO_GE;
break;
}
case T_OP_GT: // fall through
case T_OP_SQ_GT: {
cmp_op = common::CO_GT;
break;
}
case T_OP_NE: // fall through
case T_OP_SQ_NE: {
cmp_op = common::CO_NE;
break;
}
case T_FUN_SYS_STRCMP: {
cmp_op = common::CO_CMP;
}
default: {
// do nothing
break;
}
}
return cmp_op;
}
OB_INLINE static bool is_expected_cmp_ret(const common::ObCmpOp cmp_op, const int cmp_ret)
{
bool ret_bool = false;
switch (cmp_ret) {
case 0: {
ret_bool = (cmp_op == common::CO_EQ || cmp_op == common::CO_GE || cmp_op == common::CO_LE);
} break;
case 1: {
ret_bool = (cmp_op == common::CO_GT || cmp_op == common::CO_GE || cmp_op == common::CO_NE);
} break;
case -1: {
ret_bool = (cmp_op == common::CO_LT || cmp_op == common::CO_LE || cmp_op == common::CO_NE);
} break;
default: {
ret_bool = false;
}
}
return ret_bool;
}
/**
* fast path. cmp_func should not be NULL.
*/
OB_INLINE static int compare_nocast(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
const common::ObCompareCtx& cmp_ctx, common::ObCmpOp cmp_op, const common::obj_cmp_func cmp_func)
{
return common::ObObjCmpFuncs::compare(result, obj1, obj2, cmp_ctx, cmp_op, cmp_func);
}
protected:
// only use for comparison with 2 operands(calc_result2)
// if cmp_op_func2_ is not NULL, that means we can compare the 2 objs directly without any casts
// otherwise, compare_cast is necessary.
// It is used for performance optimization.
common::obj_cmp_func cmp_op_func2_;
};
class ObSubQueryRelationalExpr : public ObExprOperator {
OB_UNIS_VERSION(1);
public:
// extra info stored in ObExpr::extra_
struct ExtraInfo : public ObExprExtraInfoAccess<ExtraInfo> {
ObSubQueryKey subquery_key_;
// compare operator's left operator is row_iterator
bool left_is_iter_;
// compare operator's right operator is row_iterator
bool right_is_iter_;
TO_STRING_KV(K(subquery_key_), K(left_is_iter_), K(right_is_iter_));
} __attribute__((packed));
static_assert(sizeof(ExtraInfo) <= sizeof(uint64_t), "too big extra info");
ObSubQueryRelationalExpr(common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num,
int32_t dimension = NOT_ROW_DIMENSION)
: ObExprOperator(alloc, type, name, param_num, dimension),
subquery_key_(T_WITH_NONE),
left_is_iter_(false),
right_is_iter_(false)
{}
virtual ~ObSubQueryRelationalExpr()
{}
virtual int assign(const ObExprOperator& other) override;
void set_subquery_key(ObSubQueryKey key)
{
subquery_key_ = key;
}
void set_left_is_iter(bool is_iter)
{
left_is_iter_ = is_iter;
}
void set_right_is_iter(bool is_iter)
{
right_is_iter_ = is_iter;
}
virtual void reset() override
{
subquery_key_ = T_WITH_NONE;
left_is_iter_ = false;
right_is_iter_ = false;
}
virtual int calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const override;
virtual int calc_result_typeN(
ObExprResType& type, ObExprResType* types, int64_t param_num, common::ObExprTypeCtx& type_ctx) const override;
int calc_result2(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
common::ObExprCtx& expr_ctx) const override;
int calc_resultN(common::ObObj& result, const common::ObObj* param_array, int64_t param_num,
common::ObExprCtx& expr_ctx) const override;
virtual int call(common::ObObj* stack, int64_t& stack_size, common::ObExprCtx& expr_ctx) const override;
virtual int eval(
common::ObExprCtx& expr_ctx, common::ObObj& val, common::ObObj* params, int64_t param_num) const override;
static int subquery_cmp_eval(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum);
VIRTUAL_TO_STRING_KV(N_EXPR_TYPE, get_type_name(type_), N_REAL_PARAM_NUM, real_param_num_, N_RESULT_TYPE,
result_type_, K_(subquery_key), K_(left_is_iter), K_(right_is_iter));
protected:
// The result of processing the subquery is a vector. In this case, the result
// of the subquery has at most one row of data, and multiple rows of data are not allowed.
// According to the characteristics of the vector, the result of the subquery
// cannot be a single column of data. The result of a single row and single
// column subquery is a scalar.
int calc_result_with_none(
common::ObObj& result, const common::ObNewRow& left_row, int64_t subquery_idx, common::ObExprCtx& expr_ctx) const;
// In this case, the result of the subquery is a set, the comparison result
// of all elements in the set is true, and the result of the entire expression is true
// Otherwise, expression's result is false
int calc_result_with_all(
common::ObObj& result, const common::ObNewRow& left_row, int64_t subquery_idx, common::ObExprCtx& expr_ctx) const;
// In this case, the result of the subquery is a collection,
// and the comparison result of at least one element in the collection is true,
// and the result of the entire expression is TRUE
// Otherwise expression's result is false
int calc_result_with_any(
common::ObObj& result, const common::ObNewRow& left_row, int64_t subquery_idx, common::ObExprCtx& expr_ctx) const;
virtual int compare_single_row(const common::ObNewRow& left_row, const common::ObNewRow& right_row,
common::ObExprCtx& expr_ctx, common::ObObj& result) const;
int compare_obj(common::ObExprCtx& expr_ctx, const common::ObObj& obj1, const common::ObObj& obj2,
const ObExprCalcType& cmp_type, bool is_null_safe, common::ObObj& result) const;
virtual int calc_result_type2_(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
// pure virtual but implemented, derived classes can use this implement.
virtual int cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const override = 0;
int get_param_types(const ObRawExpr& param, const bool is_iter, common::ObIArray<common::ObObjMeta>& types) const;
static int setup_row(ObExpr** expr, ObEvalCtx& ctx, const bool is_iter, const int64_t cmp_func_cnt,
ObSubQueryIterator*& iter, ObExpr**& row);
static int subquery_cmp_eval_with_none(
const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res, ObExpr** l_row, ObExpr** r_row, ObSubQueryIterator* r_iter);
static int subquery_cmp_eval_with_any(
const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res, ObExpr** l_row, ObExpr** r_row, ObSubQueryIterator* r_iter);
static int subquery_cmp_eval_with_all(
const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res, ObExpr** l_row, ObExpr** r_row, ObSubQueryIterator* r_iter);
static int cmp_one_row(
const ObExpr& expr, ObDatum& res, ObExpr** l_row, ObEvalCtx& l_ctx, ObExpr** r_row, ObEvalCtx& r_ctx);
static int check_exists(const ObExpr& expr, ObEvalCtx& ctx, bool& exists);
protected:
ObSubQueryKey subquery_key_;
bool left_is_iter_;
bool right_is_iter_;
};
typedef int (*ObResultTypeFunc)(ObExprResType& type, const ObExprResType& type1, const ObExprResType& type2);
typedef int (*ObCalcTypeFunc)(common::ObObjType& calc_type, common::ObObjType& calc_ob1_type,
common::ObObjType& calc_ob2_type, const common::ObObjType type1, const common::ObObjType type2);
typedef int (*ObArithFunc)(common::ObObj& res, const common::ObObj& left, const common::ObObj& right,
common::ObIAllocator* allocator, common::ObScale scale);
class ObArithExprOperator : public ObExprOperator {
public:
ObArithExprOperator(common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num,
int32_t dimension, ObResultTypeFunc result_type_func, ObCalcTypeFunc calc_type_func,
const ObArithFunc* arith_funcs)
: ObExprOperator(alloc, type, name, param_num, dimension),
result_type_func_(result_type_func),
calc_type_func_(calc_type_func),
arith_funcs_(arith_funcs){};
virtual ~ObArithExprOperator(){};
virtual int assign(const ObExprOperator& other);
OB_INLINE static bool is_float_out_of_range(float res)
{
return (0 != isinff(res));
}
OB_INLINE static bool is_double_out_of_range(double res)
{
return (0 != ::isinf(res));
}
protected:
// temporary used, remove after all expr converted
OB_INLINE static int get_arith_operand(const ObExpr& expr, ObEvalCtx& ctx, common::ObDatum*& left,
common::ObDatum*& right, ObDatum& result, bool& is_finish)
{
int ret = common::OB_SUCCESS;
is_finish = false;
if (lib::is_oracle_mode()) {
if (OB_FAIL(expr.args_[0]->eval(ctx, left))) {
SQL_LOG(WARN, "left eval failed", K(ret));
} else if (left->is_null()) {
result.set_null();
is_finish = true;
} else if (OB_FAIL(expr.args_[1]->eval(ctx, right))) {
SQL_LOG(WARN, "right eval failed", K(ret));
} else if (right->is_null()) {
result.set_null();
is_finish = true;
}
} else {
if (OB_FAIL(expr.args_[0]->eval(ctx, left))) {
SQL_LOG(WARN, "left eval failed", K(ret));
} else if (OB_FAIL(expr.args_[1]->eval(ctx, right))) {
SQL_LOG(WARN, "right eval failed", K(ret));
} else if (left->is_null() || right->is_null()) {
result.set_null();
is_finish = true;
}
}
SQL_LOG(DEBUG, "finish get_arith_operand", KPC(expr.args_[0]), KPC(expr.args_[1]), K(result), K(is_finish));
return ret;
}
virtual int calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result2(
common::ObObj& result, const common::ObObj& left, const common::ObObj& right, common::ObExprCtx& expr_ctx) const;
static int calc(common::ObObj& result, const common::ObObj& left, const common::ObObj& right,
common::ObIAllocator* allocator, common::ObScale scale, ObCalcTypeFunc calc_type_func,
const ObArithFunc* arith_funcs);
static int calc(common::ObObj& result, const common::ObObj& left, const common::ObObj& right,
common::ObExprCtx& expr_ctx, common::ObScale calc_scale, ObCalcTypeFunc calc_type_func,
const ObArithFunc* arith_funcs);
ObResultTypeFunc result_type_func_;
ObCalcTypeFunc calc_type_func_;
const ObArithFunc* arith_funcs_;
protected:
static int calc_(common::ObObj& res, const common::ObObj& left, const common::ObObj& right,
common::ObExprCtx& expr_ctx, common::ObScale calc_scale, common::ObObjType calc_type,
const ObArithFunc* arith_func);
static bool is_datetime_add_minus_calc(const common::ObObjType calc_type, const ObArithFunc* arith_funcs);
static int interval_add_minus(common::ObObj& res, const common::ObObj& left, const common::ObObj& right,
common::ObExprCtx& expr_ctx, common::ObScale scale, bool is_minus = false);
};
class ObVectorExprOperator : public ObExprOperator {
public:
ObVectorExprOperator(
common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num, int32_t dimension)
: ObExprOperator(alloc, type, name, param_num, dimension)
{}
virtual ~ObVectorExprOperator()
{}
virtual int calc_result_type1(ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3,
common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_typeN(
ObExprResType& type, ObExprResType* types, int64_t param_num, common::ObExprTypeCtx& type_ctx) const;
private:
int calc_result_type2_(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
};
class ObLogicalExprOperator : public ObExprOperator {
public:
ObLogicalExprOperator(
common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num, int32_t dimension)
: ObExprOperator(alloc, type, name, param_num, dimension)
{}
virtual ~ObLogicalExprOperator()
{}
virtual int calc_result_type1(ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3,
common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_typeN(
ObExprResType& type, ObExprResType* types, int64_t param_num, common::ObExprTypeCtx& type_ctx) const;
protected:
static int is_true(const common::ObObj& obj, common::ObCastMode cast_mode, bool& result);
};
//
// Const ObIArray interface of c array, call the mutable method will got run time error.
// It used to adapt interface which need the ObIArray arguments. e.g:
//
// int foo(const ObIArray<int> &);
// int foo(int v) { return foo(make_const_carray(v); }
//
template <int64_t N, typename T>
class ObConstCArray : public common::ObIArray<T> {
public:
using common::ObIArray<T>::at;
using common::ObIArray<T>::count;
template <typename... TS>
ObConstCArray(const TS&... args) : common::ObIArray<T>(local_data_, N), local_data_{args...}
{
static_assert(N > 0 && N == sizeof...(TS), "wrong argument count");
}
virtual int push_back(const T&) override
{
return common::OB_NOT_SUPPORTED;
}
virtual void pop_back() override
{}
virtual int pop_back(T&) override
{
return common::OB_NOT_SUPPORTED;
}
virtual int remove(int64_t) override
{
return common::OB_NOT_SUPPORTED;
}
virtual int at(int64_t idx, T& obj) const override
{
int ret = common::OB_SUCCESS;
if (idx >= 0 && idx < count()) {
obj = at(idx);
} else {
ret = common::OB_INDEX_OUT_OF_RANGE;
}
return ret;
}
virtual void reset() override
{}
virtual void reuse() override
{}
virtual void destroy() override
{}
virtual int reserve(int64_t) override
{
return common::OB_NOT_SUPPORTED;
}
virtual int assign(const common::ObIArray<T>&) override
{
return common::OB_NOT_SUPPORTED;
}
virtual int prepare_allocate(int64_t) override
{
return common::OB_NOT_SUPPORTED;
}
virtual void extra_access_check() const override
{}
protected:
T local_data_[N];
using common::ObIArray<T>::data_;
using common::ObIArray<T>::count_;
};
template <typename T, typename... TS>
const ObConstCArray<1 + sizeof...(TS), T> make_const_carray(const T& t, const TS&... args)
{
return ObConstCArray<1 + sizeof...(TS), T>(t, args...);
}
// functions who's result type is string
class ObStringExprOperator : public ObExprOperator {
public:
ObStringExprOperator(common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num)
: ObExprOperator(alloc, type, name, param_num, NOT_ROW_DIMENSION)
{}
virtual ~ObStringExprOperator()
{}
static int convert_result_collation(
const ObExprResType& result_type, common::ObObj& result, common::ObIAllocator* allocator);
void calc_temporal_format_result_length(ObExprResType& type, const ObExprResType& format) const;
protected:
common::ObObjType get_result_type_mysql(int64_t char_length) const;
static const int64_t MAX_CHAR_LENGTH_FOR_VARCAHR_RESULT = 512;
static const int64_t MAX_CHAR_LENGTH_FOR_TEXT_RESULT = 65535;
private:
// types and constants
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObStringExprOperator);
// function members
private:
// data members
};
class ObBitwiseExprOperator : public ObExprOperator {
public:
ObBitwiseExprOperator(
common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num, int32_t dimension)
: ObExprOperator(alloc, type, name, param_num, dimension)
{}
virtual ~ObBitwiseExprOperator()
{}
// for static_typing_engine
static int set_calc_type(ObExprResType& type);
virtual int calc_result_type1(ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3,
common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result_typeN(
ObExprResType& type, ObExprResType* types, int64_t param_num, common::ObExprTypeCtx& type_ctx) const;
// for static engine
// retrive int64/uint64 from datum param, and do bit operations according to extra_ fields
// the difference between mysql mode and oracle mode is:
// mysql mode use get_uint64
// oracle mode use get_int64() and will calculate param's value even if former param is null
static int calc_result2_oracle(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum);
static int calc_result2_mysql(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum);
protected:
enum BitOperator {
BIT_AND,
BIT_OR,
BIT_XOR,
BIT_LEFT_SHIFT,
BIT_RIGHT_SHIFT,
BIT_NEG,
BIT_COUNT,
BIT_MAX,
};
int calc_(common::ObObj& res, const common::ObObj& obj1, const common::ObObj& obj2, common::ObExprCtx& expr_ctx,
BitOperator op) const;
static int get_uint64(const common::ObObj& obj, common::ObExprCtx& expr_ctx, bool is_round, uint64_t& out);
static int get_int64(const common::ObObj& obj, common::ObExprCtx& expr_ctx, bool is_round, int64_t& out);
// initailize eval_func_, inner_functions_, extra_ fields
static int cg_bitwise_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr, const BitOperator op);
// according to param's type, from 4 get_int/get_uint method
// to choose a suitable get_int64/get_uint64 function
static int choose_get_int_func(const common::ObObjType type, void*& out_func);
// get int64/uint64 from datum. For numbser should do some round/trunc operations;
// For int tc, it will directly retrive int value
typedef int (*GetIntFunc)(const common::ObDatum&, bool, int64_t&, common::ObCastMode&);
typedef int (*GetUIntFunc)(const common::ObDatum&, bool, uint64_t&, common::ObCastMode&);
static int get_int64_from_int_tc(
const common::ObDatum& datum, bool is_round, int64_t& out, const common::ObCastMode& cast_mode);
static int get_uint64_from_int_tc(
const common::ObDatum& datum, bool is_round, uint64_t& out, const common::ObCastMode& cast_mode);
static int get_int64_from_number_type(
const common::ObDatum& datum, bool is_round, int64_t& out, const common::ObCastMode& cast_mode);
static int get_uint64_from_number_type(
const common::ObDatum& datum, bool is_round, uint64_t& out, const common::ObCastMode& cast_mode);
};
class ObMinMaxExprOperator : public ObExprOperator {
public:
// constructor and destructor
ObMinMaxExprOperator(
common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num, int32_t dimension)
: ObExprOperator(alloc, type, name, param_num, dimension), need_cast_(true)
{}
virtual ~ObMinMaxExprOperator()
{}
virtual int assign(const ObExprOperator& other);
public:
// serialize and deserialize
virtual int serialize(char* buf, const int64_t buf_len, int64_t& pos) const;
virtual int deserialize(const char* buf, const int64_t data_len, int64_t& pos);
virtual int64_t get_serialize_size() const;
public:
OB_INLINE void set_need_cast(bool need_cast)
{
need_cast_ = need_cast;
}
protected:
/*
Aggregate result type for comparison
is involved by greatest, least
*/
int aggregate_result_type_for_comparison(
ObExprResType& type, const ObExprResType* types_stack, int64_t param_num) const;
/*
Aggregate cmp type for comparison
is involved by greatest, least
*/
int aggregate_cmp_type_for_comparison(ObExprResType& type, const ObExprResType* types, int64_t param_num) const;
protected:
// calculate greatest/least's result type
int calc_result_meta_for_comparison(ObExprResType& type, ObExprResType* types, int64_t param_num,
const common::ObCollationType coll_type, const common::ObLengthSemantics default_length_semantics) const;
protected:
// least should set cmp_op to CO_LT.
// greatest should set cmp_op to CO_GT.
static int calc_(common::ObObj& result, const common::ObObj* objs_stack, int64_t param_num,
const ObExprResType& result_type, common::ObExprCtx& expr_ctx, common::ObCmpOp cmp_op, bool need_cast);
OB_INLINE static int calc_without_cast(common::ObObj& result, const common::ObObj* objs_stack, int64_t param_num,
const ObExprResType& result_type, common::ObExprCtx& expr_ctx, common::ObCmpOp cmp_op);
OB_INLINE static int calc_with_cast(common::ObObj& result, const common::ObObj* objs_stack, int64_t param_num,
const ObExprResType& result_type, common::ObExprCtx& expr_ctx, common::ObCmpOp cmp_op);
protected:
// if all params are of same types
// or if all params are numeric
// need_no_cast_ will be ture and no casts are necessary during calculation
bool need_cast_;
};
////////////////////////////////////////////////////////////////
// locate instr position
class ObLocationExprOperator : public ObFuncExprOperator {
public:
ObLocationExprOperator(
common::ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num, int32_t dimension)
: ObFuncExprOperator(alloc, type, name, param_num, dimension){};
virtual ~ObLocationExprOperator(){};
virtual int calc_result_type2(
ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const;
virtual int calc_result2(
common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2, common::ObExprCtx& expr_ctx) const;
virtual int calc_result3(common::ObObj& result, const common::ObObj& obj1, const common::ObObj& obj2,
const common::ObObj& obj3, common::ObExprCtx& expr_ctx) const;
// for sql engine 3.0
static int calc_(
const ObExpr& expr, const ObExpr& sub_arg, const ObExpr& ori_arg, ObEvalCtx& ctx, ObDatum& res_datum);
static int calc_location_expr(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum);
static int get_calc_cs_type(const ObExpr& expr, common::ObCollationType& calc_cs_type);
virtual int cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const;
private:
OB_INLINE static int get_pos_int64(const common::ObObj& obj, common::ObExprCtx& expr_ctx, int64_t& out);
};
class ObExprTRDateFormat {
public:
// http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm#i1002084
// http://www.techonthenet.com/oracle/functions/trunc_date.php
enum FORMAT_ID {
SYYYY = 0,
YYYY = 1,
YEAR = 2,
SYEAR = 3,
YYY = 4,
YY = 5,
Y = 6,
IYYY = 7,
IY = 8,
I = 9,
Q = 10,
MONTH = 11,
MON = 12,
MM = 13,
RM = 14,
WW = 15,
IW = 16,
W = 17,
DDD = 18,
DD = 19,
J = 20,
DAY = 21,
DY = 22,
D = 23,
HH = 24,
HH12 = 25,
HH24 = 26,
MI = 27,
CC = 28,
SCC = 29,
FORMAT_MAX_TYPE
};
static int init();
static int calc_hash(const char* p, int64_t len, uint64_t& hash);
static int trunc_new_obtime(common::ObTime& ob_time, const common::ObString& fmt);
static int round_new_obtime(common::ObTime& ob_time, const common::ObString& fmt);
inline static void get_format_id(const uint64_t fmt_hash, int64_t& fmt_id)
{
fmt_id = SYYYY;
while (FORMATS_HASH[fmt_id] != fmt_hash && ++fmt_id < FORMAT_MAX_TYPE) {};
}
inline static void set_time_part_to_zero(common::ObTime& ob_time)
{
ob_time.parts_[DT_HOUR] = 0;
ob_time.parts_[DT_MIN] = 0;
ob_time.parts_[DT_SEC] = 0;
ob_time.parts_[DT_USEC] = 0;
}
public:
static const char* FORMATS_TEXT[FORMAT_MAX_TYPE];
static uint64_t FORMATS_HASH[FORMAT_MAX_TYPE];
};
} // end namespace sql
} // end namespace oceanbase
#define REGISTER_EXPR_OPERATOR(OP, OP_TYPE) \
REGISTER_CREATOR(oceanbase::sql::ObExprOperatorGFactory, ObExprOperator, OP, OP_TYPE)
////////////////////////////////////////////////////////////////
// macros that use new cast function.
#define EXPR_DEFINE_CMP_CTX(calc_type, is_null_safe, expr_ctx) \
ObCompareCtx cmp_ctx( \
calc_type.get_type(), calc_type.get_collation_type(), is_null_safe, expr_ctx.tz_offset_, default_null_pos())
#define EXPR_SET_CAST_CTX_MODE(expr_ctx) \
ObSQLUtils::set_compatible_cast_mode((expr_ctx).my_session_, (expr_ctx).cast_mode_)
// external variables: expr_ctx.
#define EXPR_DEFINE_CAST_CTX(expr_ctx, cast_mode) EXPR_DEFINE_CAST_CTX_ZF(expr_ctx, cast_mode, NULL)
#define EXPR_DEFINE_CAST_CTX_ZF(expr_ctx, cast_mode, zf_info) \
ObCollationType cast_coll_type = CS_TYPE_INVALID; \
ObCastMode cp_cast_mode_ = (expr_ctx).cast_mode_ | (cast_mode); \
if (NULL != (expr_ctx).my_session_) { \
if (lib::is_oracle_mode()) { \
if (common::OB_SUCCESS != (expr_ctx).my_session_->get_collation_server(cast_coll_type)) { \
SQL_LOG(ERROR, "fail to get server collation"); \
cast_coll_type = ObCharset::get_default_collation(ObCharset::get_default_charset()); \
} \
} else if (lib::is_mysql_mode()) { \
if (common::OB_SUCCESS != (expr_ctx).my_session_->get_collation_connection(cast_coll_type)) { \
SQL_LOG(ERROR, \
"fail to get collation_connection, " \
"set it to default collation"); \
cast_coll_type = ObCharset::get_default_collation(ObCharset::get_default_charset()); \
} else { \
} \
} \
if (common::OB_SUCCESS != ObSQLUtils::set_compatible_cast_mode((expr_ctx).my_session_, cp_cast_mode_)) { \
SQL_LOG(ERROR, "fail to get compatible mode for cast_mode"); \
} \
} else { \
SQL_LOG(WARN, "session is null"); \
cast_coll_type = ObCharset::get_system_collation(); \
} \
const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params((expr_ctx).my_session_); \
ObCastCtx cast_ctx((expr_ctx).calc_buf_, \
&dtc_params, \
get_cur_time((expr_ctx).phy_plan_ctx_), \
cp_cast_mode_, \
cast_coll_type, \
(zf_info));
// external variables: ret, cast_ctx.
// can not use do ... while(0), because the buf obj will be freed.
#define EXPR_CAST_OBJ_V2(obj_type, obj, res_obj) \
common::ObObj tmp_out_obj; \
if (OB_SUCC(ret) && OB_FAIL(ObObjCaster::to_type(obj_type, cast_ctx, obj, tmp_out_obj, res_obj))) { \
SQL_LOG(WARN, "failed to cast object to " #obj_type, K(ret), K(obj), K(obj_type)); \
}
// external variables: ret, cast_ctx.
#define EXPR_GET_VAL_V2(type, obj, val, func) \
do { \
const common::ObObj* res_obj = NULL; \
EXPR_CAST_OBJ_V2(type, obj, res_obj); \
if (OB_SUCC(ret)) { \
if (OB_ISNULL(res_obj)) { \
ret = OB_ERR_UNEXPECTED; \
SQL_LOG(WARN, "unexpected error. res_obj is null", K(ret), K(type), K(obj), K(type)); \
} else if (OB_FAIL(res_obj->get_##func(val))) { \
SQL_LOG(WARN, "unexpected error. get val failed", K(ret), K(obj), K(type), K(*res_obj)); \
} \
} \
} while (0)
#define EXPR_GET_TINYINT_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObTinyIntType, arg_obj, arg_val, tinyint)
#define EXPR_GET_INT32_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObInt32Type, arg_obj, arg_val, int32)
#define EXPR_GET_UINT32_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObUInt32Type, arg_obj, arg_val, uint32)
#define EXPR_GET_INT64_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObIntType, arg_obj, arg_val, int)
#define EXPR_GET_UINT64_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObUInt64Type, arg_obj, arg_val, uint64)
#define EXPR_GET_FLOAT_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObFloatType, arg_obj, arg_val, float)
#define EXPR_GET_DOUBLE_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObDoubleType, arg_obj, arg_val, double)
#define EXPR_GET_NUMBER_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObNumberType, arg_obj, arg_val, number)
#define EXPR_GET_DATETIME_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObDateTimeType, arg_obj, arg_val, datetime)
#define EXPR_GET_TIMESTAMP_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObTimestampType, arg_obj, arg_val, timestamp)
#define EXPR_GET_DATE_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObDateType, arg_obj, arg_val, date)
#define EXPR_GET_TIME_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObTimeType, arg_obj, arg_val, time)
#define EXPR_GET_VARCHAR_V2(arg_obj, arg_val) EXPR_GET_VAL_V2(ObVarcharType, arg_obj, arg_val, varchar)
#define TYPE_CHECK(obj_to_check, expected_type) \
do { \
if (OB_UNLIKELY(obj_to_check.get_type() != expected_type)) { \
ret = OB_INVALID_ARGUMENT; \
LOG_WARN("invalid argument. unexpected obj type", K(obj_to_check), K(expected_type), K(common::lbt())); \
return ret; \
} \
} while (0)
#define GET_EXEC_ALLOCATOR(expr_ctx) \
((nullptr == expr_ctx.exec_ctx_) ? nullptr : &(expr_ctx.exec_ctx_->get_allocator()));
#endif // OCEANBASE_SQL_OB_EXPR_OPERATOR_H_