/** * 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 #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((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 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 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 T* get_expr_op_ctx(uint64_t expr_id) { T* ret = NULL; if (expr_id < iter_expr_ctxs_.count()) { ret = static_cast(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 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 { 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& 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& arg_arrs) const; virtual int calc_result_type1(ObExprResType& type, ObExprResType& type1, common::ObExprTypeCtx& type_ctx, common::ObIArray& arg_arrs) const; virtual int calc_result_type2(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx, common::ObIArray& arg_arrs) const; virtual int calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3, common::ObExprTypeCtx& type_ctx, common::ObIArray& arg_arrs) const; virtual int calc_result_typeN(ObExprResType& type, ObExprResType* types_array, int64_t param_num, common::ObExprTypeCtx& type_ctx, common::ObIArray& 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& 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& 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 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& 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& 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& 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& 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& 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::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 { 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& 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 foo(int v) { return foo(make_const_carray(v); } // template class ObConstCArray : public common::ObIArray { public: using common::ObIArray::at; using common::ObIArray::count; template ObConstCArray(const TS&... args) : common::ObIArray(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&) 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::data_; using common::ObIArray::count_; }; template 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_