diff --git a/deps/oblib/src/common/ob_common_types.h b/deps/oblib/src/common/ob_common_types.h index 87909f995..8ae95f328 100644 --- a/deps/oblib/src/common/ob_common_types.h +++ b/deps/oblib/src/common/ob_common_types.h @@ -264,6 +264,8 @@ struct ObQueryFlag set_not_use_block_cache(); set_not_use_bloomfilter_cache(); } + inline void set_is_new_query_range() { is_new_query_range_ = true; } + inline bool is_new_query_range() const { return is_new_query_range_; } inline bool is_mr_mview_refresh_base_scan() const { return RefreshMode == mr_mv_scan_; } inline bool is_mr_rt_mview_base_scan() const { return RealTimeMode == mr_mv_scan_; } inline bool is_mr_mview_query() const { return is_mr_mview_refresh_base_scan() || is_mr_rt_mview_base_scan(); } diff --git a/deps/oblib/src/common/ob_range.h b/deps/oblib/src/common/ob_range.h index d198082ec..a116f1e96 100644 --- a/deps/oblib/src/common/ob_range.h +++ b/deps/oblib/src/common/ob_range.h @@ -470,6 +470,33 @@ public: return cmp; } + /** + * compare endkey of current range with startkey of other range + * if endkey is equal to startkey, return value follows these rules: + * 1. if last obj of endkey is max_value or min value, compare result is 0 + * 2. if last obj of endkey is not max_value or min_value, check inclusive_end + * of current range and inclusive_start of other range. current range only + * less than other range when inclusive_end and inclusive_start are both false. + */ + inline int compare_endkey_with_startkey(const ObNewRange &r) const + { + int cmp = 0; + if (end_key_.is_max_row()) { + cmp = 1; + } else { + cmp = end_key_.compare(r.start_key_); + if (0 == cmp) { + if (end_key_.get_obj_ptr()[end_key_.get_obj_cnt() - 1].is_max_value() || + end_key_.get_obj_ptr()[end_key_.get_obj_cnt() - 1].is_min_value()) { + // do nothing + } else if (!border_flag_.inclusive_end() && !r.border_flag_.inclusive_start()) { + cmp = -1; + } + } + } + return cmp; + } + inline bool is_valid() const { return !empty(); } inline bool empty() const diff --git a/deps/oblib/src/lib/ob_name_def.h b/deps/oblib/src/lib/ob_name_def.h index 2fc8bba9b..6274fab93 100644 --- a/deps/oblib/src/lib/ob_name_def.h +++ b/deps/oblib/src/lib/ob_name_def.h @@ -1138,6 +1138,8 @@ #define N_INEER_IS_TRUE "inner_is_true" #define N_INNER_DECODE_LIKE "inner_decode_like" +#define N_INNER_DOUBLE_TO_INT "inner_double_to_int" +#define N_INNER_DECIMAL_TO_YEAR "inner_decimal_to_year" #define N_BM25 "bm25" #define N_EXTRACT_CERT_EXPIRED_TIME "extract_cert_expired_time" #define N_INNER_ROW_CMP_VALUE "inner_row_cmp_value" diff --git a/src/objit/include/objit/common/ob_item_type.h b/src/objit/include/objit/common/ob_item_type.h index df358230a..d839f4a6c 100644 --- a/src/objit/include/objit/common/ob_item_type.h +++ b/src/objit/include/objit/common/ob_item_type.h @@ -2740,7 +2740,8 @@ typedef enum ObOutlineType || ((op) == T_OP_OUTPUT_PACK) \ || ((op) == T_FUN_SYS_JSON_OBJECT) \ || ((op) == T_FUN_SYS_JSON_ARRAY) \ - || ((op) == T_OP_TO_OUTFILE_ROW)) \ + || ((op) == T_OP_TO_OUTFILE_ROW) \ + || ((op) == T_FUNC_SYS_INNER_IS_TRUE)) \ diff --git a/src/share/external_table/ob_external_table_utils.h b/src/share/external_table/ob_external_table_utils.h index 76e93a40e..129160c9c 100644 --- a/src/share/external_table/ob_external_table_utils.h +++ b/src/share/external_table/ob_external_table_utils.h @@ -34,7 +34,6 @@ namespace sql class ObDASTabletLoc; class ObExecContext; class ObExternalTableAccessService; -class ObQueryRange; class ObExprRegexContext; class ObExprRegexpSessionVariables; } diff --git a/src/share/parameter/ob_parameter_seed.ipp b/src/share/parameter/ob_parameter_seed.ipp index eb7964e70..77306de89 100644 --- a/src/share/parameter/ob_parameter_seed.ipp +++ b/src/share/parameter/ob_parameter_seed.ipp @@ -2105,9 +2105,9 @@ DEF_BOOL(_enable_range_extraction_for_not_in, OB_TENANT_PARAMETER, "True", "Enable extract query range for not in predicate", ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); -// DEF_BOOL(_enable_new_query_range_extraction, OB_TENANT_PARAMETER, "True", -// "decide whether use new algorithm to extract query range.", -// ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_BOOL(_enable_new_query_range_extraction, OB_TENANT_PARAMETER, "True", + "decide whether use new algorithm to extract query range.", + ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); DEF_TIME(_ha_diagnose_history_recycle_interval, OB_CLUSTER_PARAMETER, "7d", "[2m, 180d]", "The recycle interval time of diagnostic history data. Range: [2m, 180d]", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index 4f0d161e4..95d7c056f 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -427,6 +427,9 @@ ob_set_subtarget(ob_sql engine_expr engine/expr/ob_expr_ifnull.cpp engine/expr/ob_expr_inet.cpp engine/expr/ob_expr_initcap.cpp + engine/expr/ob_expr_inner_decode_like.cpp + engine/expr/ob_expr_inner_double_to_int.cpp + engine/expr/ob_expr_inner_decimal_to_year.cpp engine/expr/ob_expr_inner_trim.cpp engine/expr/ob_expr_insert.cpp engine/expr/ob_expr_instr.cpp @@ -1410,6 +1413,10 @@ ob_set_subtarget(ob_sql rewrite rewrite/ob_key_part.cpp rewrite/ob_predicate_deduce.cpp rewrite/ob_query_range.cpp + rewrite/ob_expr_range_converter.cpp + rewrite/ob_query_range_define.cpp + rewrite/ob_range_generator.cpp + rewrite/ob_range_graph_generator.cpp rewrite/ob_stmt_comparer.cpp rewrite/ob_transform_count_to_exists.cpp rewrite/ob_transform_aggr_subquery.cpp diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index 24c05e3cf..844e6af6f 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -5267,51 +5267,59 @@ int ObStaticEngineCG::generate_normal_tsc(ObLogTableScan &op, ObTableScanSpec &s ? NULL : op.get_plan()->get_optimizer_context().get_sql_schema_guard(); CK(OB_NOT_NULL(schema_guard)); - if (OB_SUCC(ret) && NULL != op.get_pre_query_range()) { - OZ(spec.tsc_ctdef_.pre_query_range_.deep_copy(*op.get_pre_query_range())); + if (OB_SUCC(ret) && NULL != op.get_pre_graph()) { + if (op.is_new_query_range()) { + OZ(spec.tsc_ctdef_.pre_range_graph_.deep_copy(*op.get_pre_range_graph())); + if (!op.is_skip_scan()) { + OZ(spec.tsc_ctdef_.pre_range_graph_.reset_skip_scan_range()); + } + } else { + OZ(spec.tsc_ctdef_.pre_query_range_.deep_copy(*op.get_pre_query_range())); + if (!op.is_skip_scan()) { + OZ(spec.tsc_ctdef_.pre_query_range_.reset_skip_scan_range()); + } + } if (OB_FAIL(ret)) { - } else if (!op.is_skip_scan() && OB_FAIL(spec.tsc_ctdef_.pre_query_range_.reset_skip_scan_range())) { - LOG_WARN("reset skip scan range failed", K(ret)); - } else if (OB_FAIL(spec.tsc_ctdef_.pre_query_range_.is_get(spec.tsc_ctdef_.scan_ctdef_.is_get_))) { + } else if (OB_FAIL(op.get_pre_graph()->is_get(spec.tsc_ctdef_.scan_ctdef_.is_get_))) { LOG_WARN("extract the query range whether get failed", K(ret)); } } OZ(generate_tsc_flags(op, spec)); OX(spec.set_est_cost_simple_info(op.get_est_cost_simple_info())); - bool is_equal_and = true; - ObKeyPart* root = spec.tsc_ctdef_.pre_query_range_.get_table_grapth().key_part_head_; - ObSEArray equal_offs; - while (OB_SUCC(ret) && NULL != root && is_equal_and) { - is_equal_and = is_equal_and & root->is_equal_condition(); - if (NULL != root->item_next_ || NULL != root->or_next_) { - is_equal_and = false; - } else if (root->is_normal_key()) { - int64_t param_idx = OB_INVALID_ID; - ObObj& cur = root->normal_keypart_->start_; - ObQueryRange::ObEqualOff equal_off; - if (cur.is_ext() || root->null_safe_) { - is_equal_and = false; //rollback old version - } else if (root->is_rowid_key_part()) { - is_equal_and = false; //not deal with rowid - } else if (cur.is_unknown()) { - if (OB_FAIL(cur.get_unknown(param_idx))) { - LOG_WARN("get question mark value failed", K(ret), K(cur)); - } else { - equal_off.param_idx_ = param_idx; - equal_off.pos_off_ = root->pos_.offset_; - equal_off.pos_type_ = root->pos_.column_type_.get_type(); - equal_offs.push_back(equal_off); - } - } else { - equal_off.only_pos_ = true; - equal_off.pos_off_ = root->pos_.offset_; - equal_off.pos_value_ = root->normal_keypart_->start_; - equal_offs.push_back(equal_off); - } - } - root = root->and_next_; - } + // bool is_equal_and = true; + // ObKeyPart* root = spec.tsc_ctdef_.pre_query_range_.get_table_grapth().key_part_head_; + // ObSEArray equal_offs; + // while (OB_SUCC(ret) && NULL != root && is_equal_and) { + // is_equal_and = is_equal_and & root->is_equal_condition(); + // if (NULL != root->item_next_ || NULL != root->or_next_) { + // is_equal_and = false; + // } else if (root->is_normal_key()) { + // int64_t param_idx = OB_INVALID_ID; + // ObObj& cur = root->normal_keypart_->start_; + // ObQueryRange::ObEqualOff equal_off; + // if (cur.is_ext() || root->null_safe_) { + // is_equal_and = false; //rollback old version + // } else if (root->is_rowid_key_part()) { + // is_equal_and = false; //not deal with rowid + // } else if (cur.is_unknown()) { + // if (OB_FAIL(cur.get_unknown(param_idx))) { + // LOG_WARN("get question mark value failed", K(ret), K(cur)); + // } else { + // equal_off.param_idx_ = param_idx; + // equal_off.pos_off_ = root->pos_.offset_; + // equal_off.pos_type_ = root->pos_.column_type_.get_type(); + // equal_offs.push_back(equal_off); + // } + // } else { + // equal_off.only_pos_ = true; + // equal_off.pos_off_ = root->pos_.offset_; + // equal_off.pos_value_ = root->normal_keypart_->start_; + // equal_offs.push_back(equal_off); + // } + // } + // root = root->and_next_; + // } // TODO the above optimization is overrode by ObTscCgService::generate_tsc_ctdef before this commit // but after the deep copy of pre_query_range_ is removed in ObTscCgService::generate_tsc_ctdef, // error is returned in such sql 'set global x=y', should fix this; diff --git a/src/sql/code_generator/ob_static_engine_expr_cg.cpp b/src/sql/code_generator/ob_static_engine_expr_cg.cpp index 24eb74dda..ed31c4430 100644 --- a/src/sql/code_generator/ob_static_engine_expr_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_expr_cg.cpp @@ -517,7 +517,8 @@ int ObStaticEngineExprCG::cg_expr_by_operator(const ObIArray &raw_e ret = OB_ERR_UNEXPECTED; LOG_WARN("arg is null", K(raw_expr), K(rt_expr), K(ret)); } else if (T_QUESTIONMARK == rt_expr->type_ && - (raw_expr->has_flag(IS_TABLE_ASSIGN) || rt_question_mark_eval_)) { + (raw_expr->has_flag(IS_TABLE_ASSIGN) || + (rt_question_mark_eval_ && (!is_dynamic_eval_qm(*raw_expr) || !contain_dynamic_eval_rt_qm_)))) { // generate question mark expr for get param from param store directly // if the questionmark is from TABLE_ASSIGN, use eval_assign_question_mark_func ObConstRawExpr *c_expr = static_cast(raw_expr); @@ -1818,7 +1819,8 @@ int ObStaticEngineExprCG::gen_expr_with_row_desc(const ObRawExpr *expr, ObIAllocator &allocator, ObSQLSessionInfo *session, ObSchemaGetterGuard *schema_guard, - ObTempExpr *&temp_expr) + ObTempExpr *&temp_expr, + bool contain_dynamic_eval_rt_qm_/* = false */) { int ret = OB_SUCCESS; temp_expr = NULL; @@ -1849,6 +1851,7 @@ int ObStaticEngineExprCG::gen_expr_with_row_desc(const ObRawExpr *expr, GET_MIN_CLUSTER_VERSION()); // ? expr_cg.set_rt_question_mark_eval(true); expr_cg.set_need_flatten_gen_col(false); + expr_cg.set_contain_dynamic_eval_rt_qm(contain_dynamic_eval_rt_qm_); OZ(expr_cg.generate(const_cast(expr), flattened_raw_exprs, *temp_expr)); } // generate row_idx to column expr pair; diff --git a/src/sql/code_generator/ob_static_engine_expr_cg.h b/src/sql/code_generator/ob_static_engine_expr_cg.h index 0a84b75ca..f20a2d7d0 100644 --- a/src/sql/code_generator/ob_static_engine_expr_cg.h +++ b/src/sql/code_generator/ob_static_engine_expr_cg.h @@ -107,7 +107,8 @@ public: rt_question_mark_eval_(false), need_flatten_gen_col_(true), cur_cluster_version_(cur_cluster_version), - gen_questionmarks_(allocator, param_cnt) + gen_questionmarks_(allocator, param_cnt), + contain_dynamic_eval_rt_qm_(false) { } virtual ~ObStaticEngineExprCG() {} @@ -156,6 +157,7 @@ public: void set_batch_size(const int64_t v) { batch_size_ = v; } void set_rt_question_mark_eval(const bool v) { rt_question_mark_eval_ = v; } + void set_contain_dynamic_eval_rt_qm(const bool v) { contain_dynamic_eval_rt_qm_ = v; } static int generate_partial_expr_frame(const ObPhysicalPlan &plan, ObExprFrameInfo &partial_expr_frame_info, @@ -169,7 +171,8 @@ public: ObIAllocator &alloctor, ObSQLSessionInfo *session, share::schema::ObSchemaGetterGuard *schema_guard, - ObTempExpr *&temp_expr); + ObTempExpr *&temp_expr, + bool contain_dynamic_eval_rt_qm_ = false); static int init_temp_expr_mem_size(ObTempExpr &temp_expr); @@ -499,6 +502,7 @@ private: bool need_flatten_gen_col_; uint64_t cur_cluster_version_; common::ObFixedArray gen_questionmarks_; + bool contain_dynamic_eval_rt_qm_; }; } // end namespace sql diff --git a/src/sql/code_generator/ob_tsc_cg_service.cpp b/src/sql/code_generator/ob_tsc_cg_service.cpp index 03fe9d503..2b36c1085 100644 --- a/src/sql/code_generator/ob_tsc_cg_service.cpp +++ b/src/sql/code_generator/ob_tsc_cg_service.cpp @@ -44,6 +44,9 @@ int ObTscCgService::generate_tsc_ctdef(ObLogTableScan &op, ObTableScanCtDef &tsc } else { query_flag.scan_order_ = ObQueryFlag::Forward; } + if (op.is_new_query_range()) { + query_flag.set_is_new_query_range(); + } OZ(generate_mr_mv_scan_flag(op, query_flag)); tsc_ctdef.scan_flags_ = query_flag; if (op.use_index_merge()) { diff --git a/src/sql/engine/expr/ob_datum_decint_cast.h b/src/sql/engine/expr/ob_datum_decint_cast.h index d1becf04e..014a543b4 100644 --- a/src/sql/engine/expr/ob_datum_decint_cast.h +++ b/src/sql/engine/expr/ob_datum_decint_cast.h @@ -1228,16 +1228,21 @@ REG_SER_FUNC_ARRAY(OB_SFA_DECIMAL_INT_CAST_EXPR_EVAL_BATCH, g_decimalint_cast_ba int eval_questionmark_decint2nmb(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { int ret = OB_SUCCESS; - // child is questionmark, do not need evaluation. - const ObDatum &child = expr.args_[0]->locate_expr_datum(ctx); - ObScale in_scale = expr.args_[0]->datum_meta_.scale_; - ObNumStackOnceAlloc tmp_alloc; - number::ObNumber out_nmb; - if (OB_FAIL(wide::to_number(child.get_decimal_int(), child.get_int_bytes(), in_scale, - tmp_alloc, out_nmb))) { - LOG_WARN("to_number failed", K(ret)); + ObDatum *child_eval_datum = NULL; + if (OB_FAIL(expr.args_[0]->eval(ctx, child_eval_datum))) { + LOG_WARN("failef to eval child datum"); } else { - expr_datum.set_number(out_nmb); + // child is questionmark, do not need evaluation. + const ObDatum &child = expr.args_[0]->locate_expr_datum(ctx); + ObScale in_scale = expr.args_[0]->datum_meta_.scale_; + ObNumStackOnceAlloc tmp_alloc; + number::ObNumber out_nmb; + if (OB_FAIL(wide::to_number(child.get_decimal_int(), child.get_int_bytes(), in_scale, + tmp_alloc, out_nmb))) { + LOG_WARN("to_number failed", K(ret)); + } else { + expr_datum.set_number(out_nmb); + } } return ret; } @@ -1246,21 +1251,26 @@ static int _eval_questionmark_nmb2decint(const ObExpr &expr, ObEvalCtx &ctx, ObD const ObCastMode cm) { int ret = OB_SUCCESS; - // child is questionmark, do not need evaluation. - const ObDatum &child = expr.args_[0]->locate_expr_datum(ctx); - ObDecimalIntBuilder tmp_alloc, res_val; - number::ObNumber in_nmb(child.get_number()); - ObScale in_scale = in_nmb.get_scale(); - ObPrecision out_prec = expr.datum_meta_.precision_; - ObScale out_scale = expr.datum_meta_.scale_; - ObDecimalInt *decint = nullptr; - int32_t int_bytes = 0; - if (OB_FAIL(wide::from_number(in_nmb, tmp_alloc, in_scale, decint, int_bytes))) { - LOG_WARN("from number failed", K(ret)); - } else if (OB_FAIL(scale_const_decimalint_expr(decint, int_bytes, in_scale, out_scale, out_prec, cm, res_val))) { - LOG_WARN("scale const decimal int failed", K(ret)); + ObDatum *child_eval_datum = NULL; + if (OB_FAIL(expr.args_[0]->eval(ctx, child_eval_datum))) { + LOG_WARN("failef to eval child datum"); } else { - expr_datum.set_decimal_int(res_val.get_decimal_int(), res_val.get_int_bytes()); + // child is questionmark, do not need evaluation. + const ObDatum &child = expr.args_[0]->locate_expr_datum(ctx); + ObDecimalIntBuilder tmp_alloc, res_val; + number::ObNumber in_nmb(child.get_number()); + ObScale in_scale = in_nmb.get_scale(); + ObPrecision out_prec = expr.datum_meta_.precision_; + ObScale out_scale = expr.datum_meta_.scale_; + ObDecimalInt *decint = nullptr; + int32_t int_bytes = 0; + if (OB_FAIL(wide::from_number(in_nmb, tmp_alloc, in_scale, decint, int_bytes))) { + LOG_WARN("from number failed", K(ret)); + } else if (OB_FAIL(scale_const_decimalint_expr(decint, int_bytes, in_scale, out_scale, out_prec, cm, res_val))) { + LOG_WARN("scale const decimal int failed", K(ret)); + } else { + expr_datum.set_decimal_int(res_val.get_decimal_int(), res_val.get_int_bytes()); + } } return ret; } @@ -1269,16 +1279,21 @@ static int _eval_questionmark_decint2decint(const ObExpr &expr, ObEvalCtx &ctx, const ObCastMode cm) { int ret = OB_SUCCESS; - ObScale out_scale = expr.datum_meta_.scale_; - ObPrecision out_prec = expr.datum_meta_.precision_; - ObScale in_scale = expr.args_[0]->datum_meta_.scale_; - ObDecimalIntBuilder res_val; - const ObDatum &child = expr.args_[0]->locate_expr_datum(ctx); - if (OB_FAIL(ObDatumCast::common_scale_decimalint(child.get_decimal_int(), child.get_int_bytes(), - in_scale, out_scale, out_prec, cm, res_val))) { - LOG_WARN("common scale decimal int failed", K(ret)); + ObDatum *child_eval_datum = NULL; + if (OB_FAIL(expr.args_[0]->eval(ctx, child_eval_datum))) { + LOG_WARN("failef to eval child datum"); } else { - expr_datum.set_decimal_int(res_val.get_decimal_int(), res_val.get_int_bytes()); + ObScale out_scale = expr.datum_meta_.scale_; + ObPrecision out_prec = expr.datum_meta_.precision_; + ObScale in_scale = expr.args_[0]->datum_meta_.scale_; + ObDecimalIntBuilder res_val; + const ObDatum &child = expr.args_[0]->locate_expr_datum(ctx); + if (OB_FAIL(ObDatumCast::common_scale_decimalint(child.get_decimal_int(), child.get_int_bytes(), + in_scale, out_scale, out_prec, cm, res_val))) { + LOG_WARN("common scale decimal int failed", K(ret)); + } else { + expr_datum.set_decimal_int(res_val.get_decimal_int(), res_val.get_int_bytes()); + } } return ret; } diff --git a/src/sql/engine/expr/ob_expr_eval_functions.cpp b/src/sql/engine/expr/ob_expr_eval_functions.cpp index 20b3d3db8..6762867d7 100644 --- a/src/sql/engine/expr/ob_expr_eval_functions.cpp +++ b/src/sql/engine/expr/ob_expr_eval_functions.cpp @@ -415,6 +415,9 @@ #include "ob_expr_audit_log_func.h" #include "ob_expr_can_access_trigger.h" #include "ob_expr_split_part.h" +#include "ob_expr_inner_decode_like.h" +#include "ob_expr_inner_double_to_int.h" +#include "ob_expr_inner_decimal_to_year.h" #include "ob_expr_array_overlaps.h" #include "ob_expr_array_contains_all.h" #include "ob_expr_array_distinct.h" @@ -1140,15 +1143,15 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { ObExprIs::decimal_int_is_false, /* 612 */ ObExprIsNot::decimal_int_is_not_true, /* 613 */ ObExprIsNot::decimal_int_is_not_false, /* 614 */ - NULL, //ObExprInnerIsTrue::int_is_true_start, /* 615 */ - NULL, //ObExprInnerIsTrue::int_is_true_end, /* 616 */ - NULL, //ObExprInnerIsTrue::float_is_true_start, /* 617 */ - NULL, //ObExprInnerIsTrue::float_is_true_end, /* 618 */ - NULL, //ObExprInnerIsTrue::double_is_true_start, /* 619 */ - NULL, //ObExprInnerIsTrue::double_is_true_end, /* 620 */ - NULL, //ObExprInnerIsTrue::number_is_true_start, /* 621 */ - NULL, //ObExprInnerIsTrue::number_is_true_end, /* 622 */ - NULL, //ObExprInnerDecodeLike::eval_inner_decode_like /* 623 */ + ObExprInnerIsTrue::int_is_true_start, /* 615 */ + ObExprInnerIsTrue::int_is_true_end, /* 616 */ + ObExprInnerIsTrue::float_is_true_start, /* 617 */ + ObExprInnerIsTrue::float_is_true_end, /* 618 */ + ObExprInnerIsTrue::double_is_true_start, /* 619 */ + ObExprInnerIsTrue::double_is_true_end, /* 620 */ + ObExprInnerIsTrue::number_is_true_start, /* 621 */ + ObExprInnerIsTrue::number_is_true_end, /* 622 */ + ObExprInnerDecodeLike::eval_inner_decode_like, /* 623 */ ObExprJsonSchemaValid::eval_json_schema_valid, /* 624 */ ObExprJsonSchemaValidationReport::eval_json_schema_validation_report, /* 625 */ ObExprInsertChildXml::eval_insert_child_xml, /* 626 */ @@ -1253,8 +1256,8 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { ObExprVectorDims::calc_dims, /* 725 */ ObExprVectorNorm::calc_norm, /* 726 */ ObExprVectorDistance::calc_distance, /* 727 */ - NULL, // ObExprInnerDoubleToInt::eval_inner_double_to_int /* 728 */ - NULL, // ObExprInnerDecimalToYear::eval_inner_decimal_to_year /* 729 */ + ObExprInnerDoubleToInt::eval_inner_double_to_int, /* 728 */ + ObExprInnerDecimalToYear::eval_inner_decimal_to_year, /* 729 */ ObExprSm3::eval_sm3, /* 730 */ ObExprSm4Encrypt::eval_sm4_encrypt, /* 731 */ ObExprSm4Decrypt::eval_sm4_decrypt, /* 732 */ @@ -1289,10 +1292,10 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { NULL, // ObExprMysqlProcInfo::eval_mysql_proc_info /* 761 */ ObExprArrayOverlaps::eval_array_overlaps, /* 762 */ ObExprArrayContainsAll::eval_array_contains_all, /* 763 */ - NULL, // ObExprInnerIsTrue::decimal_int_is_true_start, /* 764 */ - NULL, // ObExprInnerIsTrue::decimal_int_is_true_end, /* 765 */ - NULL, // ObExprInnerIsTrue::json_is_true_start, /* 766 */ - NULL, // ObExprInnerIsTrue::json_is_true_end, /* 767 */ + ObExprInnerIsTrue::decimal_int_is_true_start, /* 764 */ + ObExprInnerIsTrue::decimal_int_is_true_end, /* 765 */ + ObExprInnerIsTrue::json_is_true_start, /* 766 */ + ObExprInnerIsTrue::json_is_true_end, /* 767 */ ObExprGetMySQLRoutineParameterTypeStr::get_mysql_routine_parameter_type_str, /* 768 */ ObExprArrayDistinct::eval_array_distinct, /* 769 */ ObExprArrayRemove::eval_array_remove_int64_t, /* 770 */ diff --git a/src/sql/engine/expr/ob_expr_inner_decimal_to_year.cpp b/src/sql/engine/expr/ob_expr_inner_decimal_to_year.cpp new file mode 100644 index 000000000..e3503f4d9 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_inner_decimal_to_year.cpp @@ -0,0 +1,119 @@ +/** + * 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. + * This file contains implementation for _st_asewkb expr. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "ob_expr_inner_decimal_to_year.h" +#include "sql/session/ob_sql_session_info.h" +#include "sql/engine/ob_exec_context.h" + +namespace oceanbase +{ +using namespace common; +namespace sql +{ +ObExprInnerDecimalToYear::ObExprInnerDecimalToYear(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_INNER_DECIMAL_TO_YEAR, N_INNER_DECIMAL_TO_YEAR, 1, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION, + INTERNAL_IN_MYSQL_MODE, INTERNAL_IN_ORACLE_MODE) +{ +} +const int64_t YEAR_MIN = 1901; +const int64_t YEAR_MAX = 2155; +const int64_t YEAR_BASE = 1900; +const uint8_t OBJ_YEAR_MIN = 1; +const uint8_t OBJ_YEAR_MAX = 255; +const uint8_t OBJ_YEAR_LOW = 0; + +int ObExprInnerDecimalToYear::eval_inner_decimal_to_year(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) +{ + int ret = OB_SUCCESS; + ObDatum* val_datum = NULL; + int64_t year_int = 0; + bool is_start = (expr.extra_ & 1) == 1; + bool is_equal = (expr.extra_ & 2) == 2; + if (OB_FAIL(expr.args_[0]->eval(ctx, val_datum))) { + LOG_WARN("fail to eval conv", K(ret), K(expr)); + } else if (val_datum->is_null()) { + expr_datum.set_null(); + } else { + const number::ObNumber& val = val_datum->get_number(); + if (val.is_negative()) { + if (is_equal) { + expr_datum.set_year(is_start ? (int8_t)OBJ_YEAR_MAX : (int8_t)OBJ_YEAR_LOW); + } else { + expr_datum.set_year((int8_t)OBJ_YEAR_LOW); + } + } else if (OB_FAIL(val.extract_valid_int64_with_trunc(year_int))) { + LOG_WARN("extract_valid_int64_with_trunc fail.", K(ret), K(year_int)); + } else if (val.is_valid_int()) { + if (year_int > YEAR_BASE && year_int <= YEAR_MAX) { + expr_datum.set_year((int8_t)(year_int - YEAR_BASE)); + } else if (year_int == 0) { + expr_datum.set_year((int8_t)OBJ_YEAR_LOW); + } else if (is_equal) { + expr_datum.set_year(is_start ? (int8_t)OBJ_YEAR_MAX : (int8_t)OBJ_YEAR_LOW); + } else if (year_int > YEAR_MAX) { + expr_datum.set_year((int8_t)OBJ_YEAR_MAX); + } else if (year_int <= YEAR_BASE && year_int > 0) { + expr_datum.set_year(is_start ? (int8_t)OBJ_YEAR_MIN : (int8_t)OBJ_YEAR_LOW); + } + } else { + if (is_equal) { + expr_datum.set_year(is_start ? (int8_t)OBJ_YEAR_MAX : (int8_t)OBJ_YEAR_LOW); + } else { + if (year_int >= YEAR_BASE && year_int < YEAR_MAX) { + year_int = is_start ? year_int + 1 : year_int; + expr_datum.set_year((int8_t)(year_int - YEAR_BASE)); + } else if (year_int >= YEAR_MAX) { + expr_datum.set_year((int8_t)OBJ_YEAR_MAX); + } else if (year_int < YEAR_BASE && year_int >= 0) { + expr_datum.set_year(is_start ? (int8_t)OBJ_YEAR_MIN : (int8_t)OBJ_YEAR_LOW); + } + } + } + } + return ret; +} + +int ObExprInnerDecimalToYear::calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + UNUSED(type_ctx); + type.set_year(); + type1.set_calc_type(ObNumberType); + return ret; +} + +int ObExprInnerDecimalToYear::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(1 != rt_expr.arg_cnt_)) { + ret = OB_ERR_PARAM_SIZE; + LOG_WARN("invalid arg cnt of expr", K(ret), K(rt_expr)); + } else if (OB_ISNULL(rt_expr.args_[0])) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("the arg of inner double to int is null.", K(ret), K(rt_expr)); + } else { + rt_expr.eval_func_ = ObExprInnerDecimalToYear::eval_inner_decimal_to_year; + rt_expr.extra_ = raw_expr.get_extra(); + } + return ret; +} + +} +} \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_inner_decimal_to_year.h b/src/sql/engine/expr/ob_expr_inner_decimal_to_year.h new file mode 100644 index 000000000..77041a062 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_inner_decimal_to_year.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DECIMAL_TO_YEAR_ +#define OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DECIMAL_TO_YEAR_ + +#include "sql/engine/expr/ob_expr_operator.h" + +namespace oceanbase +{ +namespace sql +{ +//This expression is used to extract double to int range. +//inner_decimal_to_year(val) +//for example: inner_decimal_to_year(1991) = 1991 +class ObExprInnerDecimalToYear : public ObFuncExprOperator +{ +public: + explicit ObExprInnerDecimalToYear(common::ObIAllocator &alloc); + virtual ~ObExprInnerDecimalToYear() {}; + + virtual int calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const; + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; + static int eval_inner_decimal_to_year(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprInnerDecimalToYear) const; +}; +} // namespace sql +} // namespace oceanbase + +#endif // OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DECIMAL_TO_YEAR_ diff --git a/src/sql/engine/expr/ob_expr_inner_decode_like.cpp b/src/sql/engine/expr/ob_expr_inner_decode_like.cpp new file mode 100644 index 000000000..a6e55e41d --- /dev/null +++ b/src/sql/engine/expr/ob_expr_inner_decode_like.cpp @@ -0,0 +1,230 @@ +/** + * 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. + * This file contains implementation for _st_asewkb expr. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "ob_expr_inner_decode_like.h" +#include "sql/session/ob_sql_session_info.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_datum_cast.h" + +namespace oceanbase +{ +using namespace common; +namespace sql +{ +ObExprInnerDecodeLike::ObExprInnerDecodeLike(ObIAllocator &alloc) + : ObStringExprOperator(alloc, T_FUN_SYS_INNER_DECODE_LIKE, N_INNER_DECODE_LIKE, 6, NOT_VALID_FOR_GENERATED_COL, + INTERNAL_IN_MYSQL_MODE, INTERNAL_IN_ORACLE_MODE) +{ +} + +int ObExprInnerDecodeLike::cg_expr(ObExprCGCtx &op_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(op_cg_ctx); + UNUSED(raw_expr); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(6 != rt_expr.arg_cnt_)) { + ret = OB_ERR_PARAM_SIZE; + LOG_WARN("invalid arg cnt of expr", K(ret), K(rt_expr)); + } else { + rt_expr.eval_func_ = ObExprInnerDecodeLike::eval_inner_decode_like; + } + return ret; +} + +int ObExprInnerDecodeLike::eval_inner_decode_like(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { + int ret = OB_SUCCESS; + ObDatum *pattern = NULL; + ObDatum *escape = NULL; + ObDatum *is_start = NULL; + ObDatum *col_type = NULL; + ObDatum *col_collation = NULL; + ObDatum *col_length = NULL; + ObDatum *pattern_val = NULL; + const ObDataTypeCastParams &dtc_params = ctx.exec_ctx_.get_my_session()->get_dtc_params(); + if (OB_ISNULL(expr.args_[0]) ||OB_ISNULL(expr.args_[1])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(expr.eval_param_value(ctx, pattern, escape, is_start, col_type, col_collation, col_length))) { + LOG_WARN("eval args failed", K(ret)); + } else if (OB_ISNULL(pattern) || OB_ISNULL(escape) + || OB_ISNULL(is_start) || OB_ISNULL(col_collation) || OB_ISNULL(col_length)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("params are unexpected null", K(ret), K(pattern), K(escape), + K(is_start), K(col_collation), K(col_length)); + } else if (pattern->is_null()) { + //a like null return empty range + expr_datum.set_null(); + } else if (col_length->get_int() <= 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument, unexpected length", K(ret)); + } else if (OB_FAIL(cast_like_obj_if_needed(ctx, *expr.args_[0], pattern, expr, pattern_val))) { + LOG_WARN("failed to cast like obj if needed", K(ret)); + } else { + int64_t mbmaxlen = 1; + ObCollationType cs_type = static_cast(col_collation->get_int()); + int32_t col_len = static_cast(col_length->get_int()); + ObString escape_str; + ObString pattern_str = pattern_val->get_string(); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + if (escape->is_null()) { //如果escape是null,则给默认的'\\' + escape_str.assign_ptr("\\", 1); + } else { + ObString escape_val = escape->get_string(); + ObCollationType escape_collation = expr.args_[1]->datum_meta_.cs_type_; + if (ObCharset::is_cs_nonascii(escape_collation)) { + if (OB_FAIL(ObCharset::charset_convert(tmp_alloc_g.get_allocator(), + escape_val, + escape_collation, + CS_TYPE_UTF8MB4_GENERAL_CI, + escape_str, true))) { + LOG_WARN("failed to do charset convert", K(ret), K(escape_val)); + } + } else { + escape_str = escape->get_string(); + if (escape_str.empty()) { + escape_str.assign_ptr("\\", 1); + } else { /* do nothing */ } + } + } + if (OB_FAIL(ret)) { + // do nothing; + } else if (OB_FAIL(ObCharset::get_mbmaxlen_by_coll(cs_type, mbmaxlen))) { + LOG_WARN("fail to get mbmaxlen", K(ret), K(cs_type), K(pattern), K(escape)); + } else if (OB_ISNULL(escape_str.ptr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Escape str should not be NULL", K(ret)); + } else if (OB_UNLIKELY(1 > escape_str.length())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("failed to check escape length", K(escape_str), K(escape_str.length())); + LOG_USER_ERROR(OB_INVALID_ARGUMENT, "ESCAPE"); + } else { + //convert character counts to len in bytes + col_len = static_cast(col_len * mbmaxlen); + size_t min_str_len = col_len; + size_t max_str_len = col_len; + size_t res_len = 0; + int32_t start_flag = is_start->get_int(); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + char *min_str_buf = NULL; + char *max_str_buf = NULL; + char *res_buf = NULL; + if (OB_ISNULL(min_str_buf = (char*)temp_allocator.alloc(min_str_len))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("alloc memory failed", K(min_str_len)); + } else if (OB_ISNULL(max_str_buf = (char*)temp_allocator.alloc(max_str_len))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("alloc memory failed", K(max_str_len)); + } else if (OB_FAIL(ObCharset::like_range(cs_type, + pattern_str, + *(escape_str.ptr()), + static_cast(min_str_buf), + &min_str_len, + static_cast(max_str_buf), + &max_str_len))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("calc like range failed", K(ret), K(pattern_str), K(escape_str), K(cs_type)); + } else { + ObExprStrResAlloc res_alloc(expr, ctx); + char *buf = NULL; + if (is_start->get_int() == 1) { + res_buf = min_str_buf; + res_len = min_str_len; + } else { + res_buf = max_str_buf; + res_len = max_str_len; + } + buf = (char*)res_alloc.alloc(res_len); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("alloc memory failed", K(ret), K(min_str_len)); + } else { + MEMCPY(buf, res_buf, res_len); + expr_datum.set_string(buf, res_len); + } + } + } + } + return ret; +} + +int ObExprInnerDecodeLike::calc_result_typeN(ObExprResType &type, + ObExprResType *types_stack, + int64_t param_num, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + if (param_num != 6) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid param num", K(ret), K(param_num)); + } else { + const ObObj &dest_type = types_stack[3].get_param(); + const ObObj &dest_collation = types_stack[4].get_param(); + const ObObj &dest_length = types_stack[5].get_param(); + if (!types_stack[2].is_int() || !types_stack[3].is_int() || !types_stack[4].is_int() || !types_stack[5].is_int() + || !types_stack[1].is_string_type() || !types_stack[0].is_string_type()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument, unexpected obj type", K(ret), K(types_stack[0]), K(types_stack[1]), K(types_stack[2]), + K(types_stack[3]), K(types_stack[4]), K(types_stack[5])); + } else { + ObObjType expected_type = static_cast(dest_type.get_int()); + ObCollationType cs_type = static_cast(dest_collation.get_int()); + int64_t length = dest_length.get_int(); + type.set_type(expected_type); + type.set_length(length); + type.set_collation_level(CS_LEVEL_COERCIBLE); + type.set_collation_type(cs_type); + //pattern + types_stack[0].set_calc_meta(types_stack[0].get_obj_meta()); + types_stack[0].set_calc_collation_type(types_stack[0].get_collation_type()); + types_stack[0].set_calc_collation_level(CS_LEVEL_COERCIBLE); + //escape + types_stack[1].set_calc_meta(types_stack[1].get_obj_meta()); + types_stack[1].set_calc_collation_type(types_stack[1].get_collation_type()); + types_stack[1].set_calc_collation_level(CS_LEVEL_COERCIBLE); + //is_start + types_stack[2].set_calc_type(ObIntType); + //column type + types_stack[3].set_calc_type(ObIntType); + //column collation + types_stack[4].set_calc_type(ObIntType); + //column length + types_stack[5].set_calc_type(ObIntType); + } + } + return ret; +} + +int ObExprInnerDecodeLike::cast_like_obj_if_needed(ObEvalCtx &ctx, const ObExpr &pattern_expr, ObDatum *pattern_datum, + const ObExpr &dst_expr, ObDatum * &cast_datum) { + int ret = OB_SUCCESS; + ObCastMode cm = CM_NONE; + if (OB_FAIL(ObSQLUtils::get_default_cast_mode(false /*is_explicit_cast*/, + 0 /*result_flag*/, + ctx.exec_ctx_.get_my_session(), + cm))) { + LOG_WARN("get default cast mode failed", K(ret)); + } else if (pattern_expr.datum_meta_.type_ == dst_expr.datum_meta_.type_ + && pattern_expr.datum_meta_.cs_type_ == dst_expr.datum_meta_.cs_type_) { + cast_datum = pattern_datum; + } else if (OB_ISNULL(ctx.datum_caster_) && OB_FAIL(ctx.init_datum_caster())) { + LOG_WARN("init datum caster failed", K(ret)); + } else if (OB_FAIL(ctx.datum_caster_->to_type(dst_expr.datum_meta_, pattern_expr, cm, cast_datum, ctx.get_batch_idx()))) { + LOG_WARN("fail to dynamic cast", K(ret)); + } + return ret; +} +} +} \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_inner_decode_like.h b/src/sql/engine/expr/ob_expr_inner_decode_like.h new file mode 100644 index 000000000..c4a4ba746 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_inner_decode_like.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DECODE_LIKE_ +#define OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DECODE_LIKE_ + +#include "sql/engine/expr/ob_expr_operator.h" + +namespace oceanbase +{ +namespace sql +{ +//This expression is used to extract like range. +//inner_decode_like(pattern, escape, is_start, column_type, column_collation, column_length) +//for example: inner_decode_like('123%', '\\', 1, 22 \*ObVarcharType*\, 45 \*CS_TYPE_UTF8MB4_GENERAL_CI*\, 4) = '123\min\min\min...' (length:16) +// inner_decode_like('123%', '\\', 0, 22 \*ObVarcharType*\, 45 \*CS_TYPE_UTF8MB4_GENERAL_CI*\, 4) = '123\max\max\max...' (length:16) +class ObExprInnerDecodeLike : public ObStringExprOperator +{ +public: + explicit ObExprInnerDecodeLike(common::ObIAllocator &alloc); + virtual ~ObExprInnerDecodeLike() {}; + + virtual int calc_result_typeN(ObExprResType &type, + ObExprResType *types_stack, + int64_t param_num, + common::ObExprTypeCtx &type_ctx) const; + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; + static int eval_inner_decode_like(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + +private: + static int cast_like_obj_if_needed(ObEvalCtx &ctx, const ObExpr &pattern_expr, ObDatum *pattern_datum, + const ObExpr &dst_expr, ObDatum * &cast_datum); + DISALLOW_COPY_AND_ASSIGN(ObExprInnerDecodeLike) const; +}; +} // namespace sql +} // namespace oceanbase + +#endif // OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DECODE_LIKE_ diff --git a/src/sql/engine/expr/ob_expr_inner_double_to_int.cpp b/src/sql/engine/expr/ob_expr_inner_double_to_int.cpp new file mode 100644 index 000000000..6e37ccbc7 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_inner_double_to_int.cpp @@ -0,0 +1,402 @@ +/** + * 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. + * This file contains implementation for _st_asewkb expr. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "ob_expr_inner_double_to_int.h" +#include "sql/session/ob_sql_session_info.h" +#include "sql/engine/ob_exec_context.h" + +namespace oceanbase +{ +using namespace common; +namespace sql +{ +const int64_t MAX_PRECISE_DOUBLE_INT64 = 9007199254740991; // 2^53 - 1 +const int64_t MIN_PRECISE_DOUBLE_INT64 = -9007199254740991; // -2^53 + 1 +const int DOUBLE_BIAS = 1023; +const int64_t DOUBLE_EXP_MASK = 0x7ff; +const int64_t DOUBLE_DIG_MASK = 0xfffffffffffff; +const double MAX_PRECISE_DOUBLE = 9007199254740991.0; // 2^53 - 1 +const double MIN_PRECISE_DOUBLE = -9007199254740991.0; // -2^53 + 1 +const double MAX_DOUBLE_TO_INT64 = 9.223372036854776e+18; +const double MIN_DOUBLE_TO_INT64 = -9.223372036854776e+18; +const double MIN_DOUBLE_TO_UINT64 = 0.; +const double MAX_DOUBLE_TO_UINT64 = 1.8446744073709552e+19; +const int MAX_DOUBLE_PRINT_SIZE = 512; +ObExprInnerDoubleToInt::ObExprInnerDoubleToInt(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_INNER_DOUBLE_TO_INT, N_INNER_DOUBLE_TO_INT, 1, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION, + INTERNAL_IN_MYSQL_MODE, INTERNAL_IN_ORACLE_MODE) +{ +} +/** + * The function convert_double_to_int64_range is used to convert a double with potential precision + * loss into the corresponding upper and lower bounds of an int64. + * For example, the number 9.223372036854776e+18, after being processed by this function, + * would be converted to start=9223372036854775296 and end=INT64_MAX. + * The conversion logic here cannot directly call ceil or floor because for large integers (greater than 2^53 + 1) + * both would return the same value. + */ +int ObExprInnerDoubleToInt::convert_double_to_int64_range(double d, int64_t &start, int64_t &end) +{ + int64_t v = static_cast(d); + if (v >= MIN_PRECISE_DOUBLE_INT64 && v <= MAX_PRECISE_DOUBLE_INT64) { + start = v; + end = v; + } else { + uint64_t num = *reinterpret_cast(&d); + int64_t exp = ((num >> 52) & DOUBLE_EXP_MASK) - DOUBLE_BIAS; + int64_t bits = exp - 52; + int64_t out = (((int64_t)1 << 52) + (num & DOUBLE_DIG_MASK)); + int64_t p = (1 << (bits - 1)); + uint64_t sign = num & 0x8000000000000000; + if (exp == 63) { + start = 9223372036854775296; + end = INT64_MAX; + } else if (exp > 63) { + start = INT64_MAX; + end = INT64_MAX; + } else if ((num & 1) == 1) { + if (bits == 1) { + out = out << bits; + start = out; + end = out; + } else { + start = ((out - 1) << bits) + p + 1; + end = (out << bits) + p - 1; + } + } else { + start = ((out - 1) << bits) + p; + end = ((out) << bits) + p; + } + if (start < MAX_PRECISE_DOUBLE_INT64 + 1) { + start = MAX_PRECISE_DOUBLE_INT64 + 1; + } + if (sign == 0x8000000000000000) { + start = -start; + end = -end; + std::swap(start, end); + } + } + return OB_SUCCESS; +} + +/** + * This function is used to convert a double to the upper and lower bounds of a uint64. + * The conversion logic is similar to convert_double_to_int64_range, but with a different range of values. + */ +int ObExprInnerDoubleToInt::convert_double_to_uint64_range(double d, uint64_t &start, uint64_t &end) +{ + uint64_t v = static_cast(d); + if (v >= 0 && v <= MAX_PRECISE_DOUBLE_INT64) { + start = v; + end = v; + } else { + uint64_t num = *reinterpret_cast(&d); + int64_t exp = ((num >> 52) & DOUBLE_EXP_MASK) - DOUBLE_BIAS; + int64_t bits = exp - 52; + uint64_t out = (((uint64_t)1 << 52) + (num & DOUBLE_DIG_MASK)); + uint64_t p = (1 << (bits - 1)); + if (exp == 64) { + start = 18446744073709550592u; + end = UINT64_MAX; + } else if (exp > 64) { + start = UINT64_MAX; + end = UINT64_MAX; + } else if ((num & 1) == 1) { + if (bits == 1) { + out = out << bits; + start = out; + end = out; + } else { + start = ((out - 1) << bits) + p + 1; + end = (out << bits) + p - 1; + } + } else { + start = ((out - 1) << bits) + p; + end = ((out) << bits) + p; + } + if (start < MAX_PRECISE_DOUBLE_INT64 + 1) { + start = MAX_PRECISE_DOUBLE_INT64 + 1; + } + } + return OB_SUCCESS; +} + +/** + * This function's purpose is to generate a double value out_d that is guaranteed to be greater than the original input value d. + * The algorithm achieves this by adding 1 to the least significant digit of the double's mantissa; if this causes an overflow, then 1 is added to the exponent part instead. + * + * To illustrate the effect of this function with an example, suppose the input value is 3.14. After being processed by the function, the resulting value would be 3.1400000000000006. + * + * Why do we need this auxiliary function? + * When converting a double to a decimal, because a decimal has a fractional part and the precision can vary, + * it's not possible to obtain an exact value as with converting to an integer. Therefore, we need to generate an imprecise range that ensures the produced range is a superset of the original one. + * For instance, for c1 = 3.14, the resulting range would be [3.1399999999999997; 3.1400000000000006]. + * + * Why doesn't the conversion function simply add 1? + * For numbers smaller than 2^53, adding 1 is not an issue, + * but for large integers, directly adding 1 doesn't cause any change to the double value. + * For example, 9.223372036854776e+18 + 1 is equal to 9.223372036854776e+18, showing no change. +*/ +int ObExprInnerDoubleToInt::add_double_bit_1(double d, double &out_d) +{ + int ret = OB_SUCCESS; + int64_t v = static_cast(d); + uint64_t num = *reinterpret_cast(&d); + int64_t exp = ((num >> 52) & DOUBLE_EXP_MASK); + int64_t bits = exp - 52; + int64_t out = (((int64_t)1 << 52) + (num & 0xfffffffffffff)); + uint64_t sign = num & 0x8000000000000000; + out += 1; + if ((out & 0x20000000000000) == 0x20000000000000) { + out = out >> 1; + exp += 1; + } + num = sign | (exp << 52) | (out & 0xfffffffffffff); + out_d = *reinterpret_cast(&num); + return ret; +} + +/** + * This function serves the opposite purpose to add_double_bit_1, yielding a double that is smaller than the input number, + * effectively subtracting 1 from the least significant digit of the double's precision. + */ +int ObExprInnerDoubleToInt::sub_double_bit_1(double d, double &out_d) +{ + int ret = OB_SUCCESS; + int64_t v = static_cast(d); + uint64_t num = *reinterpret_cast(&d); + int64_t exp = ((num >> 52) & DOUBLE_EXP_MASK); + int64_t bits = exp - 52; + int64_t out = (((int64_t)1 << 52) + (num & 0xfffffffffffff)); + uint64_t sign = num & 0x8000000000000000; + out -= 1; + if ((out & 0x10000000000000) == 0) { + out = (out << 1) + 1; + exp -= 1; + } + num = sign | (exp << 52) | (out & 0xfffffffffffff); + out_d = *reinterpret_cast(&num); + return ret; +} + +int ObExprInnerDoubleToInt::double_to_number(double in_val, + ObIAllocator &alloc, + number::ObNumber &number) +{ + int ret = OB_SUCCESS; + int64_t length = 0; + ObScale res_scale; // useless + ObPrecision res_precision; + ObString str; + SMART_VAR(char[MAX_DOUBLE_PRINT_SIZE], buf) { + MEMSET(buf, 0, MAX_DOUBLE_PRINT_SIZE); + length = ob_gcvt_opt(in_val, OB_GCVT_ARG_DOUBLE, static_cast(sizeof(buf) - 1), + buf, NULL, lib::is_oracle_mode(), TRUE); + str.assign_ptr(buf, length); + ret = number.from_sci_opt(str.ptr(), str.length(), alloc, + &res_precision, &res_scale); + if (OB_NUMERIC_OVERFLOW == ret) { + int64_t i = 0; + while (i < str.length() && isspace(str[i])) { + ++i; + } + bool is_neg = (str[i] == '-'); + int tmp_ret = OB_SUCCESS; + const ObPrecision prec = OB_MAX_DECIMAL_PRECISION; + const ObScale scale = 0; + const number::ObNumber *bound_num = NULL; + if (is_neg) { + bound_num = &(ObNumberConstValue::MYSQL_MIN[prec][scale]); + } else { + bound_num = &(ObNumberConstValue::MYSQL_MAX[prec][scale]); + } + if (OB_ISNULL(bound_num)) { + tmp_ret = OB_ERR_UNEXPECTED; + LOG_WARN("bound_num is NULL", K(tmp_ret), K(ret), K(is_neg)); + } else if (OB_SUCCESS != (tmp_ret = number.from(*bound_num, alloc))) { + LOG_WARN("copy min number failed", K(ret), K(tmp_ret), KPC(bound_num)); + } else { + ret = OB_SUCCESS; + } + } + } + return ret; +} + +int ObExprInnerDoubleToInt::eval_inner_double_to_int(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { + int ret = OB_SUCCESS; + ObDatum* val_datum = NULL; + double val = 0.; + double ceil_val = 0.; + double floor_val = 0.; + bool is_start = (expr.extra_ & 1) == 1; + bool is_equal = (expr.extra_ & 2) == 2; + bool is_unsigned = (expr.extra_ & 4) == 4; + bool is_decimal = (expr.extra_ & 8) == 8; + if (OB_FAIL(expr.args_[0]->eval(ctx, val_datum))) { + LOG_WARN("fail to eval conv", K(ret), K(expr)); + } else if (val_datum->is_null()) { + expr_datum.set_null(); + } else if (OB_FALSE_IT(val = val_datum->get_double())) { + } else if (is_decimal) { + ObNumStackOnceAlloc tmp_alloc; + number::ObNumber number; + double tmp_d; + if (val == DBL_MAX || val == DBL_MIN || + val == -DBL_MAX || val == -DBL_MIN) { + // do nothing + } else if ((val > 0. && !is_start) || + (val < 0. && is_start)) { + if (OB_FAIL(add_double_bit_1(val, tmp_d))) { + LOG_WARN("failed to add double bit 1", K(ret)); + } else { + val = tmp_d; + } + } else if ((val > 0. && is_start) || + (val < 0. && !is_start)) { + if (OB_FAIL(sub_double_bit_1(val, tmp_d))) { + LOG_WARN("failed to sub double bit 1", K(ret)); + } else { + val = tmp_d; + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(double_to_number(val, tmp_alloc, number))) { + LOG_WARN("failed to trans double to number", K(ret)); + } else { + expr_datum.set_number(number); + } + } else if (!is_unsigned) { + int64_t start = 0, end = 0; + if (val >= MIN_PRECISE_DOUBLE && val <= MAX_PRECISE_DOUBLE) { + ceil_val = ceill(val); + floor_val = floorl(val); + if (ceil_val == floor_val) { + expr_datum.set_int(static_cast(val)); + } else if (is_equal) { + expr_datum.set_int(is_start ? INT64_MAX : INT64_MIN); + } else if (is_start) { + expr_datum.set_int(static_cast(ceil_val)); + } else { + expr_datum.set_int(static_cast(floor_val)); + } + } else if (val > MAX_DOUBLE_TO_INT64) { + if (is_equal) { + expr_datum.set_int(is_start ? INT64_MAX : INT64_MIN); + } else { + expr_datum.set_int(INT64_MAX); + } + } else if (val < MIN_DOUBLE_TO_INT64) { + if (is_equal) { + expr_datum.set_int(is_start ? INT64_MAX : INT64_MIN); + } else { + expr_datum.set_int(INT64_MIN); + } + } else { + if (OB_FAIL(convert_double_to_int64_range(val, start, end))) { + LOG_WARN("failed to convert double to int64 range", K(ret)); + } else if (is_start) { + expr_datum.set_int(start); + } else { + expr_datum.set_int(end); + } + } + } else { + uint64_t start = 0, end = 0; + if (val >= MIN_DOUBLE_TO_UINT64 && val <= MAX_PRECISE_DOUBLE) { + ceil_val = ceill(val); + floor_val = floorl(val); + if (ceil_val == floor_val) { + expr_datum.set_uint(static_cast(val)); + } else if (is_equal) { + expr_datum.set_uint(is_start ? UINT64_MAX : 0); + } else if (is_start) { + expr_datum.set_uint(static_cast(ceil_val)); + } else { + expr_datum.set_uint(static_cast(floor_val)); + } + } else if (val > MAX_DOUBLE_TO_UINT64) { + if (is_equal) { + expr_datum.set_uint(is_start ? UINT64_MAX : 0); + } else { + expr_datum.set_uint(UINT64_MAX); + } + } else if (val < MIN_DOUBLE_TO_UINT64) { + if (is_equal) { + expr_datum.set_uint(is_start ? UINT64_MAX : 0); + } else { + expr_datum.set_uint(0); + } + } else { + if (OB_FAIL(convert_double_to_uint64_range(val, start, end))) { + LOG_WARN("failed to convert double to int64 range", K(ret)); + } else if (is_start) { + expr_datum.set_uint(start); + } else { + expr_datum.set_uint(end); + } + } + } + + return ret; +} + +int ObExprInnerDoubleToInt::calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObRawExpr *raw_expr = get_raw_expr(); + UNUSED(type_ctx); + if (OB_ISNULL(raw_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("op raw expr is null or param_count error", K(ret), K(raw_expr)); + } else { + bool is_unsigned = (raw_expr->get_extra() & 4) == 4; + bool is_decimal = (raw_expr->get_extra() & 8) == 8; + if (is_decimal) { + type.set_number(); + } else if (is_unsigned) { + type.set_uint64(); + } else { + type.set_int(); + } + type1.set_calc_type(ObDoubleType); + } + + return ret; +} + +int ObExprInnerDoubleToInt::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(1 != rt_expr.arg_cnt_)) { + ret = OB_ERR_PARAM_SIZE; + LOG_WARN("invalid arg cnt of expr", K(ret), K(rt_expr)); + } else if (OB_ISNULL(rt_expr.args_[0])) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("the arg of inner double to int is null.", K(ret), K(rt_expr)); + } else { + rt_expr.eval_func_ = ObExprInnerDoubleToInt::eval_inner_double_to_int; + rt_expr.extra_ = raw_expr.get_extra(); + } + return ret; +} + +} +} \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_inner_double_to_int.h b/src/sql/engine/expr/ob_expr_inner_double_to_int.h new file mode 100644 index 000000000..c517d26ab --- /dev/null +++ b/src/sql/engine/expr/ob_expr_inner_double_to_int.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DOUBLE_TO_INT_ +#define OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DOUBLE_TO_INT_ + +#include "sql/engine/expr/ob_expr_operator.h" + +namespace oceanbase +{ +namespace sql +{ +//This expression is used to extract double to int range. +//inner_double_to_int(val) +//for example: inner_double_to_int(9.223372036854776e+18) = 9223372036854775296 +// inner_double_to_int(9.223372036854776e+18) = INT64_MAX +class ObExprInnerDoubleToInt : public ObFuncExprOperator +{ +public: + explicit ObExprInnerDoubleToInt(common::ObIAllocator &alloc); + virtual ~ObExprInnerDoubleToInt() {}; + + virtual int calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const; + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; + static int eval_inner_double_to_int(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + + static int convert_double_to_int64_range(double d, int64_t &start, int64_t &end); + + static int convert_double_to_uint64_range(double d, uint64_t &start, uint64_t &end); + + static int add_double_bit_1(double d, double &out); + + static int sub_double_bit_1(double d, double &out); + + static int double_to_number(double in_val, ObIAllocator &alloc, + number::ObNumber &number); + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprInnerDoubleToInt) const; +}; +} // namespace sql +} // namespace oceanbase + +#endif // OCEANBASE_SQL_ENGINE_EXPR_OB_EXPR_INNER_DOUBLE_TO_INT_ diff --git a/src/sql/engine/expr/ob_expr_inner_trim.cpp b/src/sql/engine/expr/ob_expr_inner_trim.cpp index f9361324a..02c11304c 100644 --- a/src/sql/engine/expr/ob_expr_inner_trim.cpp +++ b/src/sql/engine/expr/ob_expr_inner_trim.cpp @@ -65,7 +65,7 @@ DEF_SET_LOCAL_SESSION_VARS(ObExprInnerTrim, raw_expr) { int ret = OB_SUCCESS; if (lib::is_mysql_mode()) { SET_LOCAL_SYSVAR_CAPACITY(1); - EXPR_ADD_LOCAL_SYSVAR(SYS_VAR_COLLATION_CONNECTION); + EXPR_ADD_LOCAL_SYSVAR(share::SYS_VAR_COLLATION_CONNECTION); } return ret; } diff --git a/src/sql/engine/expr/ob_expr_is.cpp b/src/sql/engine/expr/ob_expr_is.cpp index c83d00a3b..5cdff3f18 100644 --- a/src/sql/engine/expr/ob_expr_is.cpp +++ b/src/sql/engine/expr/ob_expr_is.cpp @@ -465,6 +465,115 @@ int ObExprIsNot::calc_is_not_nan(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &ex return ret; } +int ObExprInnerIsTrue::calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObRawExpr *raw_expr = get_raw_expr(); + if (OB_ISNULL(raw_expr) || OB_UNLIKELY(raw_expr->get_param_count() != 2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("op raw expr is null", K(ret), K(raw_expr)); + } else if (OB_UNLIKELY(type1.is_ext())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected type", K(type1)); + } else { + type.set_type(ObExtendType); + type.set_precision(DEFAULT_PRECISION_FOR_TEMPORAL); + type.set_scale(SCALE_UNKNOWN_YET); + type.set_result_flag(NOT_NULL_FLAG); + type2.set_calc_type(type2.get_type()); + if (ob_is_numeric_type(type1.get_type())) { + type1.set_calc_meta(type1.get_obj_meta()); + type1.set_calc_accuracy(type1.get_accuracy()); + } else if (ob_is_json(type1.get_type())) { + type1.set_calc_meta(type1.get_obj_meta()); + type1.set_calc_accuracy(type1.get_accuracy()); + } else { + type1.set_calc_type(ObNumberType); + const ObAccuracy &calc_acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[0][ObNumberType]; + type1.set_calc_accuracy(calc_acc); + } + } + type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NO_RANGE_CHECK); + + return ret; +} + +int ObExprInnerIsTrue::cg_expr(ObExprCGCtx &op_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + const ObConstRawExpr *param2 = NULL; + ObObjType param1_type = ObMaxType; + if (rt_expr.arg_cnt_ != 2) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("inner is true expr should have 2 params", K(ret), K(rt_expr.arg_cnt_)); + } else if (OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0]) || OB_ISNULL(rt_expr.args_[1])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("children of inner is true expr is null", K(ret), K(rt_expr.args_)); + } else if (OB_ISNULL(param2 = static_cast(raw_expr.get_param_expr(1)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("const raw expr param is null", K(param2)); + } else if (OB_UNLIKELY(!param2->get_value().is_int())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("const value is not int type", KPC(param2)); + } else { + param1_type = rt_expr.args_[0]->datum_meta_.type_; + bool is_start = param2->get_value().get_int() > 0; + switch (param1_type) { + case ObTinyIntType: + case ObSmallIntType: + case ObMediumIntType: + case ObInt32Type: + case ObIntType: + case ObUTinyIntType: + case ObUSmallIntType: + case ObUMediumIntType: + case ObUInt32Type: + case ObUInt64Type: + case ObBitType: { + rt_expr.eval_func_ = is_start ? ObExprInnerIsTrue::int_is_true_start + : ObExprInnerIsTrue::int_is_true_end; + break; + } + case ObFloatType: + case ObUFloatType:{ + rt_expr.eval_func_ = is_start ? ObExprInnerIsTrue::float_is_true_start + : ObExprInnerIsTrue::float_is_true_end; + break; + } + case ObDoubleType: + case ObUDoubleType: { + rt_expr.eval_func_ = is_start ? ObExprInnerIsTrue::double_is_true_start + : ObExprInnerIsTrue::double_is_true_end; + break; + } + case ObDecimalIntType: { + rt_expr.eval_func_ = is_start ? ObExprInnerIsTrue::decimal_int_is_true_start + : ObExprInnerIsTrue::decimal_int_is_true_end; + break; + } + case ObJsonType: { + rt_expr.eval_func_ = is_start ? ObExprInnerIsTrue::json_is_true_start + : ObExprInnerIsTrue::json_is_true_end; + break; + } + case ObMaxType: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("is expr got unexpected type param", K(ret), K(param1_type)); + break; + } + default: { + rt_expr.eval_func_ = is_start ? ObExprInnerIsTrue::number_is_true_start + : ObExprInnerIsTrue::number_is_true_end; + break; + } + } + } + return ret; +} + template int ObExprIsBase::is_zero(T number, const uint32_t len) { @@ -544,5 +653,51 @@ NUMERIC_CALC_FUNC(number, ObExprIs, false, false, is) NUMERIC_CALC_FUNC(decimal_int, ObExprIs, false, false, is) NUMERIC_CALC_FUNC(json, ObExprIs, false, false, is) +#define INNER_NUMERIC_CALC_FUNC(type, is_start, str_pos) \ + int ObExprInnerIsTrue::type##_##is_true##_##str_pos(const ObExpr &expr, ObEvalCtx &ctx, \ + ObDatum &expr_datum) \ + { \ + int ret = OB_SUCCESS; \ + ObDatum *param1 = NULL; \ + void *ptr = NULL; \ + bool ret_bool = false; \ + if (OB_FAIL(expr.args_[0]->eval(ctx, param1))) { \ + LOG_WARN("eval first param failed", K(ret)); \ + } else if (param1->is_null()) { \ + ret_bool = false; \ + } else { \ + ret_bool = !is_zero(param1->get_##type(), param1->len_); \ + } \ + if (OB_SUCC(ret)) { \ + if (OB_ISNULL(ptr = expr.get_str_res_mem(ctx, sizeof(ObObj)))) { \ + ret = OB_ALLOCATE_MEMORY_FAILED; \ + LOG_WARN("failed to allocate expr result memory"); \ + } else { \ + ObObj *res_obj = new(ptr)ObObj(); \ + if ((ret_bool && is_start) || (!ret_bool && !is_start)) { \ + res_obj->set_min_value(); \ + } else { \ + res_obj->set_max_value(); \ + } \ + ret = expr_datum.from_obj(*res_obj); \ + } \ + } \ + return ret; \ + } + +INNER_NUMERIC_CALC_FUNC(int, true, start) +INNER_NUMERIC_CALC_FUNC(float, true, start) +INNER_NUMERIC_CALC_FUNC(double, true, start) +INNER_NUMERIC_CALC_FUNC(number, true, start) +INNER_NUMERIC_CALC_FUNC(decimal_int, true, start) +INNER_NUMERIC_CALC_FUNC(json, true, start) + +INNER_NUMERIC_CALC_FUNC(int, false, end) +INNER_NUMERIC_CALC_FUNC(float, false, end) +INNER_NUMERIC_CALC_FUNC(double, false, end) +INNER_NUMERIC_CALC_FUNC(number, false, end) +INNER_NUMERIC_CALC_FUNC(decimal_int, false, end) +INNER_NUMERIC_CALC_FUNC(json, false, end) + } } diff --git a/src/sql/engine/expr/ob_expr_is.h b/src/sql/engine/expr/ob_expr_is.h index 92b13ba0a..9bbf368d8 100644 --- a/src/sql/engine/expr/ob_expr_is.h +++ b/src/sql/engine/expr/ob_expr_is.h @@ -134,6 +134,52 @@ private: // data members }; +/** + * inner_is_true(expr, is_start) is used by extract query range only + * if expr is true + * inner_is_true(expr, 1) return min_value + * inner_is_true(expr, 0) return max_value + * if expr is false + * inner_is_true(expr, 1) return max_value + * inner_is_true(expr, 0) return min_value +*/ +class ObExprInnerIsTrue: public ObExprIsBase +{ + public: + explicit ObExprInnerIsTrue(common::ObIAllocator &alloc) + : ObExprIsBase(alloc, T_FUNC_SYS_INNER_IS_TRUE, N_INEER_IS_TRUE) {}; + virtual ~ObExprInnerIsTrue() {}; + + int calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const; + + virtual int cg_expr(ObExprCGCtx &op_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; + + static int int_is_true_start(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int int_is_true_end(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int float_is_true_start(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int float_is_true_end(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int double_is_true_start(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int double_is_true_end(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int number_is_true_start(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int number_is_true_end(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int decimal_int_is_true_start(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int decimal_int_is_true_end(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int json_is_true_start(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + static int json_is_true_end(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); +private: + // types and constants +private: + DISALLOW_COPY_AND_ASSIGN(ObExprInnerIsTrue); + // function members +private: + // data members +}; + } // end namespace sql } // end namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_json_search.cpp b/src/sql/engine/expr/ob_expr_json_search.cpp index 1c185fa36..8cafa92d7 100644 --- a/src/sql/engine/expr/ob_expr_json_search.cpp +++ b/src/sql/engine/expr/ob_expr_json_search.cpp @@ -18,6 +18,7 @@ #include "share/ob_json_access_utils.h" #include "sql/session/ob_sql_session_info.h" #include "ob_expr_json_func_helper.h" +#include "sql/engine/ob_exec_context.h" using namespace oceanbase::common; using namespace oceanbase::sql; diff --git a/src/sql/engine/expr/ob_expr_operator_factory.cpp b/src/sql/engine/expr/ob_expr_operator_factory.cpp index e6ecf2812..386ec1a3b 100644 --- a/src/sql/engine/expr/ob_expr_operator_factory.cpp +++ b/src/sql/engine/expr/ob_expr_operator_factory.cpp @@ -479,6 +479,9 @@ #include "sql/engine/expr/ob_expr_audit_log_func.h" #include "sql/engine/expr/ob_expr_can_access_trigger.h" #include "sql/engine/expr/ob_expr_split_part.h" +#include "sql/engine/expr/ob_expr_inner_decode_like.h" +#include "sql/engine/expr/ob_expr_inner_double_to_int.h" +#include "sql/engine/expr/ob_expr_inner_decimal_to_year.h" #include "sql/engine/expr/ob_expr_array_overlaps.h" #include "sql/engine/expr/ob_expr_array_contains_all.h" #include "sql/engine/expr/ob_expr_array_distinct.h" @@ -489,6 +492,7 @@ #include "sql/engine/expr/ob_expr_priv_st_geohash.h" #include "sql/engine/expr/ob_expr_priv_st_makepoint.h" + using namespace oceanbase::common; namespace oceanbase { @@ -1191,6 +1195,10 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP(ObExprSm4Encrypt); REG_OP(ObExprSm4Decrypt); REG_OP(ObExprSplitPart); + REG_OP(ObExprInnerIsTrue); + REG_OP(ObExprInnerDecodeLike); + REG_OP(ObExprInnerDoubleToInt); + REG_OP(ObExprInnerDecimalToYear); REG_OP(ObExprTokenize); REG_OP(ObExprArrayOverlaps); REG_OP(ObExprArrayContainsAll); @@ -1531,6 +1539,9 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP_ORCL(ObExprGetPath); REG_OP_ORCL(ObExprDecodeTraceId); REG_OP_ORCL(ObExprSplitPart); + REG_OP_ORCL(ObExprInnerIsTrue); + REG_OP_ORCL(ObExprInnerDecodeLike); + REG_OP_ORCL(ObExprInnerDoubleToInt); REG_OP_ORCL(ObExprCalcOdpsSize); } diff --git a/src/sql/engine/expr/ob_expr_sys_makexml.cpp b/src/sql/engine/expr/ob_expr_sys_makexml.cpp index 1e24e546c..f6a957a9e 100644 --- a/src/sql/engine/expr/ob_expr_sys_makexml.cpp +++ b/src/sql/engine/expr/ob_expr_sys_makexml.cpp @@ -14,6 +14,7 @@ #define USING_LOG_PREFIX SQL_ENG #include "ob_expr_sys_makexml.h" #include "sql/engine/expr/ob_expr_xml_func_helper.h" +#include "sql/engine/ob_exec_context.h" using namespace oceanbase::common; using namespace oceanbase::sql; diff --git a/src/sql/engine/ob_physical_plan_ctx.h b/src/sql/engine/ob_physical_plan_ctx.h index 4c711b974..8c1af89b2 100644 --- a/src/sql/engine/ob_physical_plan_ctx.h +++ b/src/sql/engine/ob_physical_plan_ctx.h @@ -489,6 +489,7 @@ public: bool is_ps_protocol() const { return is_ps_protocol_; } void set_original_param_cnt(const int64_t cnt) { original_param_cnt_ = cnt; } int64_t get_original_param_cnt() const { return original_param_cnt_; } + bool is_exec_param_readable() const { return param_store_.count() > original_param_cnt_; } void set_orig_question_mark_cnt(const int64_t cnt) { orig_question_mark_cnt_ = cnt; } int64_t get_orig_question_mark_cnt() const { return orig_question_mark_cnt_; } void set_is_ps_rewrite_sql() { is_ps_rewrite_sql_ = true; } diff --git a/src/sql/engine/px/ob_granule_pump.cpp b/src/sql/engine/px/ob_granule_pump.cpp index b773958d3..0ccac65e0 100644 --- a/src/sql/engine/px/ob_granule_pump.cpp +++ b/src/sql/engine/px/ob_granule_pump.cpp @@ -797,7 +797,7 @@ int ObGranuleSplitter::split_gi_task(ObGranulePumpArgs &args, && OB_FAIL(ranges.assign(args.query_range_by_runtime_filter_))) { LOG_WARN("failed to assign query range", K(ret), K(tablets)); } else if (args.query_range_by_runtime_filter_.empty() - && OB_FAIL(get_query_range(*args.ctx_, tsc->get_query_range(), ranges, ss_ranges, + && OB_FAIL(get_query_range(*args.ctx_, tsc->get_query_range_provider(), ranges, ss_ranges, table_id, op_id, partition_granule, ObGranuleUtil::with_param_down(args.gi_attri_flag_)))) { LOG_WARN("get query range failed", K(ret)); @@ -850,7 +850,7 @@ int ObGranuleSplitter::split_gi_task(ObGranulePumpArgs &args, } int ObGranuleSplitter::get_query_range(ObExecContext &ctx, - const ObQueryRange &tsc_pre_query_range, + const ObQueryRangeProvider &tsc_pre_query_range, ObIArray &ranges, ObIArray &ss_ranges, int64_t table_id, diff --git a/src/sql/engine/px/ob_granule_pump.h b/src/sql/engine/px/ob_granule_pump.h index 5696ba8ea..df2468958 100644 --- a/src/sql/engine/px/ob_granule_pump.h +++ b/src/sql/engine/px/ob_granule_pump.h @@ -210,7 +210,7 @@ public : virtual ~ObGranuleSplitter() = default; static int get_query_range(ObExecContext &ctx, - const ObQueryRange &tsc_pre_query_range, + const ObQueryRangeProvider &tsc_pre_query_range, ObIArray &ranges, ObIArray &ss_ranges, int64_t table_id, diff --git a/src/sql/engine/px/ob_px_util.cpp b/src/sql/engine/px/ob_px_util.cpp index 4a28c2ec8..acb3f444b 100644 --- a/src/sql/engine/px/ob_px_util.cpp +++ b/src/sql/engine/px/ob_px_util.cpp @@ -209,7 +209,7 @@ int ObPXServerAddrUtil::get_external_table_loc( ObExecContext &ctx, uint64_t table_id, uint64_t ref_table_id, - const ObQueryRange &pre_query_range, + const ObQueryRangeProvider &pre_query_range, ObDfo &dfo, ObDASTableLoc *&table_loc) { @@ -491,7 +491,7 @@ int ObPXServerAddrUtil::alloc_by_data_distribution_inner( LOG_WARN("fail to get table loc", K(ret), K(table_location_key), K(ref_table_id), K(DAS_CTX(ctx).get_table_loc_list())); } else if (OB_NOT_NULL(scan_op) && scan_op->is_external_table_) { // create new table loc for a random dfo distribution for external table - OZ (get_external_table_loc(ctx, table_location_key, ref_table_id, scan_op->get_query_range(), dfo, table_loc)); + OZ (get_external_table_loc(ctx, table_location_key, ref_table_id, scan_op->get_query_range_provider(), dfo, table_loc)); } } @@ -1183,7 +1183,7 @@ int ObPXServerAddrUtil::set_dfo_accessed_location(ObExecContext &ctx, LOG_WARN("failed to get phy table location", K(ret)); } else if (scan_op->is_external_table_ && OB_FAIL(get_external_table_loc(ctx, table_location_key, ref_table_id, - scan_op->get_query_range(), dfo, table_loc))) { + scan_op->get_query_range_provider(), dfo, table_loc))) { LOG_WARN("fail to get external table loc", K(ret)); } else if (OB_FAIL(set_sqcs_accessed_location(ctx, // dml op has already set sqc.get_location information, diff --git a/src/sql/engine/px/ob_px_util.h b/src/sql/engine/px/ob_px_util.h index 40105c64d..415f8587f 100644 --- a/src/sql/engine/px/ob_px_util.h +++ b/src/sql/engine/px/ob_px_util.h @@ -196,7 +196,7 @@ public: ObExecContext &ctx, uint64_t table_id, uint64_t ref_table_id, - const ObQueryRange &pre_query_range, + const ObQueryRangeProvider &pre_query_range, ObDfo &dfo, ObDASTableLoc *&table_loc); diff --git a/src/sql/engine/table/ob_table_scan_op.cpp b/src/sql/engine/table/ob_table_scan_op.cpp index 8a238297d..696434c9f 100644 --- a/src/sql/engine/table/ob_table_scan_op.cpp +++ b/src/sql/engine/table/ob_table_scan_op.cpp @@ -110,6 +110,7 @@ OB_DEF_SERIALIZE(ObTableScanCtDef) { int ret = OB_SUCCESS; bool has_lookup = (lookup_ctdef_ != nullptr); + bool is_new_query_range = scan_flags_.is_new_query_range(); OB_UNIS_ENCODE(pre_query_range_); OB_UNIS_ENCODE(flashback_item_.need_scn_); OB_UNIS_ENCODE(flashback_item_.flashback_query_expr_); @@ -137,6 +138,9 @@ OB_DEF_SERIALIZE(ObTableScanCtDef) OB_UNIS_ENCODE(abandoned_always_false_text_ir); OB_UNIS_ENCODE(attach_spec_); OB_UNIS_ENCODE(flags_); + if (is_new_query_range) { + OB_UNIS_ENCODE(pre_range_graph_); + } return ret; } @@ -144,6 +148,7 @@ OB_DEF_SERIALIZE_SIZE(ObTableScanCtDef) { int64_t len = 0; bool has_lookup = (lookup_ctdef_ != nullptr); + bool is_new_query_range = scan_flags_.is_new_query_range(); OB_UNIS_ADD_LEN(pre_query_range_); OB_UNIS_ADD_LEN(flashback_item_.need_scn_); OB_UNIS_ADD_LEN(flashback_item_.flashback_query_expr_); @@ -171,6 +176,9 @@ OB_DEF_SERIALIZE_SIZE(ObTableScanCtDef) OB_UNIS_ADD_LEN(abandoned_always_false_text_ir); OB_UNIS_ADD_LEN(attach_spec_); OB_UNIS_ADD_LEN(flags_); + if (is_new_query_range) { + OB_UNIS_ADD_LEN(pre_range_graph_); + } return len; } @@ -222,6 +230,10 @@ OB_DEF_DESERIALIZE(ObTableScanCtDef) OB_UNIS_DECODE(abandoned_always_false_text_ir); OB_UNIS_DECODE(attach_spec_); OB_UNIS_DECODE(flags_); + bool is_new_query_range = scan_flags_.is_new_query_range(); + if (is_new_query_range) { + OB_UNIS_DECODE(pre_range_graph_); + } return ret; } @@ -1358,74 +1370,68 @@ int ObTableScanOp::prepare_single_scan_range(int64_t group_idx) ObIAllocator &range_allocator = (table_rescan_allocator_ != nullptr ? *table_rescan_allocator_ : ctx_.get_allocator()); bool is_same_type = true; // use for extract equal pre_query_range - if (OB_FAIL(single_equal_scan_check_type(plan_ctx->get_param_store(), is_same_type))) { - LOG_WARN("failed to check type about single equal scan", K(ret)); - } else if (is_same_type && MY_CTDEF.pre_query_range_.get_is_equal_and()) { - int64_t column_count = MY_CTDEF.pre_query_range_.get_column_count(); - size_t range_size = sizeof(ObNewRange) + sizeof(ObObj) * column_count * 2; - void *range_buffers = static_cast(tsc_rtdef_.range_buffers_) + tsc_rtdef_.range_buffer_idx_ * range_size; - if (tsc_rtdef_.range_buffer_idx_ < 0 || tsc_rtdef_.range_buffer_idx_ >= tsc_rtdef_.max_group_size_) { - ret = OB_ERROR_OUT_OF_RANGE; - LOG_WARN("get wrong offset of range_buffers_", K(ret)); - } else if (OB_FAIL(ObSQLUtils::extract_equal_pre_query_range( - MY_CTDEF.pre_query_range_, - range_buffers, - plan_ctx->get_param_store(), - key_ranges))) { - LOG_WARN("failed to extract equal pre query ranges", K(ret)); - } - } else { - if (OB_UNLIKELY(!need_extract_range())) { - // virtual table, do nothing - } else if (MY_CTDEF.pre_query_range_.is_contain_geo_filters() && - OB_FAIL(ObSQLUtils::extract_geo_query_range( - MY_CTDEF.pre_query_range_, - range_allocator, - ctx_, - key_ranges, - MY_INPUT.mbr_filters_, - ObBasicSessionInfo::create_dtc_params(ctx_.get_my_session())))) { - LOG_WARN("failed to extract pre query ranges", K(ret)); - } else if (!MY_CTDEF.pre_query_range_.is_contain_geo_filters() && - OB_FAIL(ObSQLUtils::extract_pre_query_range( - MY_CTDEF.pre_query_range_, - range_allocator, - ctx_, - key_ranges, - ObBasicSessionInfo::create_dtc_params(ctx_.get_my_session())))) { - LOG_WARN("failed to extract pre query ranges", K(ret)); - } else if (MY_CTDEF.scan_ctdef_.is_external_table_) { - uint64_t table_loc_id = MY_SPEC.get_table_loc_id(); - ObDASTableLoc *tab_loc = DAS_CTX(ctx_).get_table_loc_by_id(table_loc_id, MY_CTDEF.scan_ctdef_.ref_table_id_); - const ObString &table_format_or_properties = MY_CTDEF.scan_ctdef_.external_file_format_str_.str_; - ObArray partition_ids; - if (OB_ISNULL(tab_loc)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("table lock is null", K(ret)); - } else { - for (DASTabletLocListIter iter = tab_loc->tablet_locs_begin(); OB_SUCC(ret) - && iter != tab_loc->tablet_locs_end(); ++iter) { - ret = partition_ids.push_back((*iter)->partition_id_); - } + if (OB_UNLIKELY(!need_extract_range())) { + // virtual table, do nothing + } else if (MY_CTDEF.get_query_range_provider().is_contain_geo_filters() && + OB_FAIL(ObSQLUtils::extract_geo_query_range( + MY_CTDEF.get_query_range_provider(), + range_allocator, + ctx_, + key_ranges, + MY_INPUT.mbr_filters_, + ObBasicSessionInfo::create_dtc_params(ctx_.get_my_session())))) { + LOG_WARN("failed to extract pre query ranges", K(ret)); + } else if (!MY_CTDEF.get_query_range_provider().is_contain_geo_filters() && + MY_CTDEF.get_query_range_provider().is_fast_nlj_range() && + OB_FAIL(MY_CTDEF.get_query_range_provider().get_fast_nlj_tablet_ranges( + tsc_rtdef_.fast_final_nlj_range_ctx_, + range_allocator, + ctx_, + plan_ctx->get_param_store(), + locate_range_buffer(), + key_ranges, + ObBasicSessionInfo::create_dtc_params(ctx_.get_my_session())))) { + LOG_WARN("failed to extract pre fast nlj query range", K(ret)); + } else if (!MY_CTDEF.get_query_range_provider().is_contain_geo_filters() && + !MY_CTDEF.get_query_range_provider().is_fast_nlj_range() && + OB_FAIL(ObSQLUtils::extract_pre_query_range( + MY_CTDEF.get_query_range_provider(), + range_allocator, + ctx_, + key_ranges, + ObBasicSessionInfo::create_dtc_params(ctx_.get_my_session())))) { + LOG_WARN("failed to extract pre query ranges", K(ret)); + } else if (MY_CTDEF.scan_ctdef_.is_external_table_) { + uint64_t table_loc_id = MY_SPEC.get_table_loc_id(); + ObDASTableLoc *tab_loc = DAS_CTX(ctx_).get_table_loc_by_id(table_loc_id, MY_CTDEF.scan_ctdef_.ref_table_id_); + const ObString &table_format_or_properties = MY_CTDEF.scan_ctdef_.external_file_format_str_.str_; + ObArray partition_ids; + if (OB_ISNULL(tab_loc)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table lock is null", K(ret)); + } else { + for (DASTabletLocListIter iter = tab_loc->tablet_locs_begin(); OB_SUCC(ret) + && iter != tab_loc->tablet_locs_end(); ++iter) { + ret = partition_ids.push_back((*iter)->partition_id_); } - if (OB_FAIL(ret)) { - } else if (OB_FAIL(ObExternalTableUtils::prepare_single_scan_range( - ctx_.get_my_session()->get_effective_tenant_id(), - MY_CTDEF.scan_ctdef_.ref_table_id_, - table_format_or_properties, - partition_ids, - key_ranges, - range_allocator, - key_ranges, - tab_loc->loc_meta_->is_external_files_on_disk_))) { - LOG_WARN("failed to prepare single scan range for external table", K(ret)); - } - } else if (OB_FAIL(MY_CTDEF.pre_query_range_.get_ss_tablet_ranges(range_allocator, - ctx_, - ss_key_ranges, - ObBasicSessionInfo::create_dtc_params(ctx_.get_my_session())))) { - LOG_WARN("failed to final extract index skip query range", K(ret)); } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObExternalTableUtils::prepare_single_scan_range( + ctx_.get_my_session()->get_effective_tenant_id(), + MY_CTDEF.scan_ctdef_.ref_table_id_, + table_format_or_properties, + partition_ids, + key_ranges, + range_allocator, + key_ranges, + tab_loc->loc_meta_->is_external_files_on_disk_))) { + LOG_WARN("failed to prepare single scan range for external table", K(ret)); + } + } else if (OB_FAIL(MY_CTDEF.get_query_range_provider().get_ss_tablet_ranges(range_allocator, + ctx_, + ss_key_ranges, + ObBasicSessionInfo::create_dtc_params(ctx_.get_my_session())))) { + LOG_WARN("failed to final extract index skip query range", K(ret)); } if (OB_FAIL(ret)) { } else if (!ss_key_ranges.empty()) { @@ -1698,8 +1704,8 @@ int ObTableScanOp::inner_open() // here need add plan batch_size, because in vectorized execution, // left batch may greater than OB_MAX_BULK_JOIN_ROWS tsc_rtdef_.max_group_size_ = OB_MAX_BULK_JOIN_ROWS + MY_SPEC.plan_->get_batch_size(); - if (MY_CTDEF.pre_query_range_.get_is_equal_and()) { - int64_t column_count = MY_CTDEF.pre_query_range_.get_column_count(); + if (MY_CTDEF.get_query_range_provider().is_fast_nlj_range()) { + int64_t column_count = MY_CTDEF.get_query_range_provider().get_column_count(); size_t range_size = sizeof(ObNewRange) + sizeof(ObObj) * column_count * 2; if (!MY_SPEC.batch_scan_flag_) { tsc_rtdef_.range_buffers_ = ctx_.get_allocator().alloc(range_size); @@ -2854,7 +2860,7 @@ int ObTableScanOp::reassign_task_ranges(ObGranuleTaskInfo &info) { int ret = OB_SUCCESS; if (MY_SPEC.gi_above_ && !iter_end_) { - if (OB_UNLIKELY(MY_SPEC.get_query_range().is_contain_geo_filters())) { + if (OB_UNLIKELY(MY_SPEC.get_query_range_provider().is_contain_geo_filters())) { MY_INPUT.key_ranges_.reuse(); MY_INPUT.ss_key_ranges_.reuse(); MY_INPUT.mbr_filters_.reuse(); diff --git a/src/sql/engine/table/ob_table_scan_op.h b/src/sql/engine/table/ob_table_scan_op.h index f47cafc7b..956dff113 100644 --- a/src/sql/engine/table/ob_table_scan_op.h +++ b/src/sql/engine/table/ob_table_scan_op.h @@ -168,6 +168,7 @@ public: allocator_(allocator), calc_part_id_expr_(NULL), global_index_rowkey_exprs_(allocator), + pre_range_graph_(allocator), attach_spec_(allocator_, &scan_ctdef_), flags_(0) { } @@ -183,6 +184,11 @@ public: lookup_ctdef_->access_column_ids_ : scan_ctdef_.access_column_ids_; } + const ObQueryRangeProvider& get_query_range_provider() const + { + return scan_flags_.is_new_query_range() ? static_cast(pre_range_graph_) + : static_cast(pre_query_range_); + } int allocate_dppr_table_loc(); ObDASScanCtDef *get_lookup_ctdef(); const ObDASScanCtDef *get_lookup_ctdef() const; @@ -227,6 +233,7 @@ public: ObExpr *calc_part_id_expr_; ExprFixedArray global_index_rowkey_exprs_; // end for Global Index Lookup + ObPreRangeGraph pre_range_graph_; ObDASAttachSpec attach_spec_; union { uint64_t flags_; @@ -246,6 +253,7 @@ struct ObTableScanRtDef lookup_rtdef_(nullptr), range_buffers_(nullptr), range_buffer_idx_(0), + fast_final_nlj_range_ctx_(), group_size_(0), max_group_size_(0), attach_rtinfo_(nullptr), @@ -266,6 +274,7 @@ struct ObTableScanRtDef // for equal_query_range opt void *range_buffers_; int64_t range_buffer_idx_; + ObFastFinalNLJRangeCtx fast_final_nlj_range_ctx_; // for equal_query_range opt end int64_t group_size_; int64_t max_group_size_; @@ -346,7 +355,7 @@ public: int explain_index_selection_info(char *buf, int64_t buf_len, int64_t &pos) const; virtual bool is_table_scan() const override { return true; } - inline const ObQueryRange &get_query_range() const { return tsc_ctdef_.pre_query_range_; } + inline const ObQueryRangeProvider &get_query_range_provider() const { return tsc_ctdef_.get_query_range_provider(); } inline uint64_t get_table_loc_id() const { return table_loc_id_; } bool use_dist_das() const { return use_dist_das_; } int64_t get_rowkey_cnt() const { @@ -524,7 +533,7 @@ protected: int prepare_batch_scan_range(); int build_bnlj_params(); int single_equal_scan_check_type(const ParamStore ¶m_store, bool& is_same_type); - bool need_extract_range() const { return MY_SPEC.tsc_ctdef_.pre_query_range_.has_range(); } + bool need_extract_range() const { return MY_SPEC.tsc_ctdef_.get_query_range_provider().has_range(); } int prepare_single_scan_range(int64_t group_idx = 0); int prepare_index_merge_scan_range(int64_t group_idx = 0); int prepare_range_for_each_index(int64_t group_idx, ObIAllocator &allocator, ObDASBaseRtDef *rtdef); @@ -682,6 +691,13 @@ protected: int64_t range_buffer_idx_; }; + OB_INLINE void* locate_range_buffer() + { + int64_t column_count = MY_SPEC.tsc_ctdef_.get_query_range_provider().get_column_count(); + size_t range_size = sizeof(ObNewRange) + sizeof(ObObj) * column_count * 2; + void *range_buffers = static_cast(tsc_rtdef_.range_buffers_) + tsc_rtdef_.range_buffer_idx_ * range_size; + return range_buffers; + } private: const ObTableScanSpec& get_tsc_spec() {return MY_SPEC;} const ObTableScanCtDef& get_tsc_ctdef() {return MY_SPEC.tsc_ctdef_;} diff --git a/src/sql/ob_sql_utils.cpp b/src/sql/ob_sql_utils.cpp index 1ab1b59b6..b3d38b51f 100644 --- a/src/sql/ob_sql_utils.cpp +++ b/src/sql/ob_sql_utils.cpp @@ -2875,7 +2875,7 @@ bool check_stack_overflow_c() return is_overflow; } -int ObSQLUtils::extract_pre_query_range(const ObQueryRange &pre_query_range, +int ObSQLUtils::extract_pre_query_range(const ObQueryRangeProvider &query_range_provider, ObIAllocator &allocator, ObExecContext &exec_ctx, ObQueryRangeArray &key_ranges, @@ -2883,55 +2883,65 @@ int ObSQLUtils::extract_pre_query_range(const ObQueryRange &pre_query_range, { int ret = OB_SUCCESS; bool dummy_all_single_value_ranges = false; - if (OB_FAIL(pre_query_range.get_tablet_ranges(allocator, exec_ctx, key_ranges, - dummy_all_single_value_ranges, - dtc_params))) { + if (OB_FAIL(query_range_provider.get_tablet_ranges(allocator, exec_ctx, key_ranges, + dummy_all_single_value_ranges, + dtc_params))) { LOG_WARN("failed to get tablet ranges", K(ret)); } return ret; } -int ObSQLUtils::extract_geo_query_range(const ObQueryRange &pre_query_range, - ObIAllocator &allocator, - ObExecContext &exec_ctx, - ObQueryRangeArray &key_ranges, - ObMbrFilterArray &mbr_filters, - const ObDataTypeCastParams &dtc_params) +int ObSQLUtils::extract_geo_query_range(const ObQueryRangeProvider &query_range_provider, + ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &key_ranges, + ObMbrFilterArray &mbr_filters, + const ObDataTypeCastParams &dtc_params) { int ret = OB_SUCCESS; bool dummy_all_single_value_ranges = false; - if (OB_LIKELY(!pre_query_range.need_deep_copy())) { - //对于大多数查询来说,query条件是非常规范和工整的,这种条件我们不需要拷贝进行graph的变化,可以直接提取 - if (OB_FAIL(pre_query_range.direct_get_tablet_ranges(allocator, - exec_ctx, - key_ranges, - dummy_all_single_value_ranges, - dtc_params))) { - LOG_WARN("fail to get tablet ranges", K(ret)); - } else { - const MbrFilterArray &pre_filters = pre_query_range.get_mbr_filter(); - FOREACH_X(it, pre_filters, OB_SUCC(ret) && it != pre_filters.end()) { - if (OB_FAIL(mbr_filters.push_back(*it))) { - LOG_WARN("store mbr_filters_ failed", K(ret)); - } - } + if (query_range_provider.is_new_query_range()) { + if (OB_FAIL(query_range_provider.get_tablet_ranges(allocator, exec_ctx, key_ranges, + dummy_all_single_value_ranges, + dtc_params, + mbr_filters))) { + LOG_WARN("failed to get tablet ranges", K(ret)); } } else { - ObQueryRange final_query_range(allocator); - if (OB_FAIL(final_query_range.deep_copy(pre_query_range))) { - // MUST deep copy to make it thread safe - LOG_WARN("fail to create final query range", K(ret), K(pre_query_range)); - } else if (OB_FAIL(final_query_range.final_extract_query_range(exec_ctx, dtc_params))) { - LOG_WARN("fail to final extract query range", K(ret), K(final_query_range)); - } else if (OB_FAIL(final_query_range.get_tablet_ranges(key_ranges, - dummy_all_single_value_ranges, - dtc_params))) { - LOG_WARN("fail to get tablet ranges from query range", K(ret), K(final_query_range)); + const ObQueryRange &pre_query_range = static_cast(query_range_provider); + if (OB_LIKELY(!pre_query_range.need_deep_copy())) { + //对于大多数查询来说,query条件是非常规范和工整的,这种条件我们不需要拷贝进行graph的变化,可以直接提取 + if (OB_FAIL(pre_query_range.direct_get_tablet_ranges(allocator, + exec_ctx, + key_ranges, + dummy_all_single_value_ranges, + dtc_params))) { + LOG_WARN("fail to get tablet ranges", K(ret)); + } else { + const MbrFilterArray &pre_filters = pre_query_range.get_mbr_filter(); + FOREACH_X(it, pre_filters, OB_SUCC(ret) && it != pre_filters.end()) { + if (OB_FAIL(mbr_filters.push_back(*it))) { + LOG_WARN("store mbr_filters_ failed", K(ret)); + } + } + } } else { - const MbrFilterArray &pre_filters = final_query_range.get_mbr_filter(); - FOREACH_X(it, pre_filters, OB_SUCC(ret) && it != pre_filters.end()) { - if (OB_FAIL(mbr_filters.push_back(*it))) { - LOG_WARN("store mbr_filters_ failed", K(ret)); + ObQueryRange final_query_range(allocator); + if (OB_FAIL(final_query_range.deep_copy(pre_query_range))) { + // MUST deep copy to make it thread safe + LOG_WARN("fail to create final query range", K(ret), K(pre_query_range)); + } else if (OB_FAIL(final_query_range.final_extract_query_range(exec_ctx, dtc_params))) { + LOG_WARN("fail to final extract query range", K(ret), K(final_query_range)); + } else if (OB_FAIL(final_query_range.get_tablet_ranges(key_ranges, + dummy_all_single_value_ranges, + dtc_params))) { + LOG_WARN("fail to get tablet ranges from query range", K(ret), K(final_query_range)); + } else { + const MbrFilterArray &pre_filters = final_query_range.get_mbr_filter(); + FOREACH_X(it, pre_filters, OB_SUCC(ret) && it != pre_filters.end()) { + if (OB_FAIL(mbr_filters.push_back(*it))) { + LOG_WARN("store mbr_filters_ failed", K(ret)); + } } } } @@ -6419,6 +6429,17 @@ bool ObSQLUtils::is_data_version_ge_424_or_433(uint64_t data_version) return ((MOCK_DATA_VERSION_4_2_4_0 <= data_version && data_version < DATA_VERSION_4_3_0_0) || data_version >= DATA_VERSION_4_3_3_0); } +bool ObSQLUtils::is_min_cluster_version_ge_425_or_435() +{ + uint64_t version = GET_MIN_CLUSTER_VERSION(); + return ((MOCK_CLUSTER_VERSION_4_2_5_0 <= version && version < CLUSTER_VERSION_4_3_0_0) || version >= CLUSTER_VERSION_4_3_5_0); +} + +bool ObSQLUtils::is_opt_feature_version_ge_425_or_435(uint64_t opt_feature_version) +{ + return ((COMPAT_VERSION_4_2_5 <= opt_feature_version && opt_feature_version < COMPAT_VERSION_4_3_0) || opt_feature_version >= COMPAT_VERSION_4_3_5); +} + int ObSQLUtils::get_strong_partition_replica_addr(const ObCandiTabletLoc &phy_part_loc_info, ObAddr &selected_addr) { diff --git a/src/sql/ob_sql_utils.h b/src/sql/ob_sql_utils.h index 17b74c2ad..5c7bbf4fe 100644 --- a/src/sql/ob_sql_utils.h +++ b/src/sql/ob_sql_utils.h @@ -14,6 +14,7 @@ #define _OCEANBASE_SQL_OB_SQL_UTILS_H #include "common/ob_range.h" +#include "sql/rewrite/ob_query_range_provider.h" #include "common/object/ob_object.h" #include "lib/container/ob_vector.h" #include "lib/container/ob_2d_array.h" @@ -456,7 +457,7 @@ public: common::ObExprCtx &expr_ctx); // use get_tablet_ranges instead. - static int extract_pre_query_range(const ObQueryRange &pre_query_range, + static int extract_pre_query_range(const ObQueryRangeProvider &query_range_provider, common::ObIAllocator &allocator, ObExecContext &exec_ctx, ObQueryRangeArray &key_ranges, @@ -466,7 +467,7 @@ public: void *range_buffer, const ParamStore ¶m_store, ObQueryRangeArray &key_ranges); - static int extract_geo_query_range(const ObQueryRange &pre_query_range, + static int extract_geo_query_range(const ObQueryRangeProvider &query_range_provider, ObIAllocator &allocator, ObExecContext &exec_ctx, ObQueryRangeArray &key_ranges, @@ -776,6 +777,8 @@ public: static bool is_data_version_ge_423_or_431(uint64_t data_version); static bool is_data_version_ge_423_or_432(uint64_t data_version); static bool is_data_version_ge_424_or_433(uint64_t data_version); + static bool is_min_cluster_version_ge_425_or_435(); + static bool is_opt_feature_version_ge_425_or_435(uint64_t opt_feature_version); static int get_proxy_can_activate_role(const ObIArray &role_id_array, const ObIArray &role_id_option_array, diff --git a/src/sql/optimizer/ob_access_path_estimation.cpp b/src/sql/optimizer/ob_access_path_estimation.cpp index 486a19e2b..2ef037c04 100644 --- a/src/sql/optimizer/ob_access_path_estimation.cpp +++ b/src/sql/optimizer/ob_access_path_estimation.cpp @@ -316,8 +316,8 @@ int ObAccessPathEstimation::choose_best_est_method(ObOptimizerContext &ctx, if (OB_ISNULL(paths.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(paths.at(i))); - } else if (paths.at(i)->pre_query_range_ != NULL && - OB_FAIL(paths.at(i)->pre_query_range_->is_get(is_table_get))) { + } else if (paths.at(i)->get_query_range_provider() != NULL && + OB_FAIL(paths.at(i)->get_query_range_provider()->is_get(is_table_get))) { LOG_WARN("check query range is table get", K(ret)); } } @@ -1076,9 +1076,13 @@ int ObAccessPathEstimation::process_storage_estimation_result(ObIArrayget_query_range_provider() != NULL && + path->get_query_range_provider()->is_new_query_range() && + path->get_query_range_provider()->has_exec_param()); if (result_helpers.at(i).result_.logical_row_count_ >= 0 && OB_FAIL(estimate_prefix_range_rowcount(result_helpers.at(i).result_.logical_row_count_, result_helpers.at(i).result_.physical_row_count_, + new_range_with_exec_param, path->est_cost_info_))) { LOG_WARN("failed to estimate prefix range rowcount", K(ret)); } else if (OB_FAIL(fill_cost_table_scan_info(path->est_cost_info_))) { @@ -1166,6 +1170,7 @@ int ObAccessPathEstimation::do_storage_estimation(ObOptimizerContext &ctx, int ObAccessPathEstimation::estimate_prefix_range_rowcount( const double res_logical_row_count, const double res_physical_row_count, + bool new_range_with_exec_param, ObCostTableScanInfo &est_cost_info) { int ret = OB_SUCCESS; @@ -1179,6 +1184,17 @@ int ObAccessPathEstimation::estimate_prefix_range_rowcount( physical_row_count += get_range_count; // NLJ or SPF push down prefix filters + if (new_range_with_exec_param) { + /** + * new query range extraction always get (min; max) for range graph with exec param. + * for NLJ push down path with expr (c1 = 1 and c2 = ?). old query range generate + * (1, min; 1, max), New query range generate (min, min; max, max). This behavior will + * cause row estimate with new query range get a larger result.Hence, we need multiple + * prefix_filter_sel for push down path with exec param to get a more accurate row count. + */ + logical_row_count *= est_cost_info.prefix_filter_sel_; + physical_row_count *= est_cost_info.prefix_filter_sel_; + } logical_row_count *= est_cost_info.pushdown_prefix_filter_sel_; physical_row_count *= est_cost_info.pushdown_prefix_filter_sel_; @@ -1491,7 +1507,8 @@ int ObAccessPathEstimation::calc_skip_scan_prefix_ndv(AccessPath &ap, double &pr ObJoinOrder *join_order = NULL; ObLogPlan *log_plan = NULL; const ObTableMetaInfo *table_meta_info = NULL; - if (OB_ISNULL(ap.pre_query_range_) || !ap.pre_query_range_->is_ss_range() + ObQueryRangeProvider *query_range_provider = ap.get_query_range_provider(); + if (OB_ISNULL(query_range_provider) || !query_range_provider->is_ss_range() || OptSkipScanState::SS_DISABLE == ap.use_skip_scan_) { /* do nothing */ } else if (OB_ISNULL(join_order = ap.parent_) || OB_ISNULL(log_plan = join_order->get_plan()) @@ -1509,7 +1526,7 @@ int ObAccessPathEstimation::calc_skip_scan_prefix_ndv(AccessPath &ap, double &pr const double temp_rows = log_plan->get_selectivity_ctx().get_current_rows(); log_plan->get_selectivity_ctx().init_op_ctx(&join_order->get_output_equal_sets(), prefix_range_row_count); if (OB_FAIL(get_skip_scan_prefix_exprs(ap.est_cost_info_.range_columns_, - ap.pre_query_range_->get_skip_scan_offset(), + query_range_provider->get_skip_scan_offset(), prefix_exprs))) { LOG_WARN("failed to get skip scan prefix expers", K(ret)); } else if (OB_FAIL(ObOptSelectivity::update_table_meta_info(log_plan->get_basic_table_metas(), @@ -1517,7 +1534,7 @@ int ObAccessPathEstimation::calc_skip_scan_prefix_ndv(AccessPath &ap, double &pr log_plan->get_selectivity_ctx(), ap.get_table_id(), prefix_range_row_count, - ap.pre_query_range_->get_range_exprs(), + query_range_provider->get_range_exprs(), log_plan->get_predicate_selectivities()))) { LOG_WARN("failed to update table meta info", K(ret)); } else if (OB_FAIL(ObOptSelectivity::calculate_distinct(tmp_metas, diff --git a/src/sql/optimizer/ob_access_path_estimation.h b/src/sql/optimizer/ob_access_path_estimation.h index e8d0636c3..dcbf63f41 100644 --- a/src/sql/optimizer/ob_access_path_estimation.h +++ b/src/sql/optimizer/ob_access_path_estimation.h @@ -286,6 +286,7 @@ private: static int estimate_prefix_range_rowcount( const double res_logical_row_count, const double res_physical_row_count, + bool new_range_with_exec_param, ObCostTableScanInfo &est_cost_info); static int fill_cost_table_scan_info(ObCostTableScanInfo &est_cost_info); diff --git a/src/sql/optimizer/ob_index_info_cache.h b/src/sql/optimizer/ob_index_info_cache.h index dbf08f8cc..d01c601e6 100644 --- a/src/sql/optimizer/ob_index_info_cache.h +++ b/src/sql/optimizer/ob_index_info_cache.h @@ -14,6 +14,7 @@ #define OCEANBASE_SQL_OPTIMIZER_OB_INDEX_INFO_CACHE_H 1 #include "sql/rewrite/ob_query_range.h" +#include "sql/rewrite/ob_query_range_define.h" #include "sql/ob_sql_define.h" namespace oceanbase @@ -28,6 +29,7 @@ public: QueryRangeInfo() : is_valid_(false), contain_always_false_(false), query_range_(NULL), + pre_range_graph_(NULL), ranges_(), ss_ranges_(), equal_prefix_count_(0), @@ -35,8 +37,15 @@ public: range_prefix_count_(0), index_column_count_(0), range_columns_(), - expr_constraints_() {} + expr_constraints_(), + index_prefix_(-1) {} const ObQueryRange* get_query_range() const { return query_range_; } + const ObPreRangeGraph* get_pre_range_graph() const { return pre_range_graph_; } + const ObQueryRangeProvider *get_query_range_provider() const + { + return pre_range_graph_ != nullptr ? static_cast(pre_range_graph_) + : static_cast(query_range_); + } const ObQueryRangeArray& get_ranges() const { return ranges_; } const common::ObIArray &get_range_columns() const { return range_columns_; } const common::ObIArray &get_expr_constraints() const @@ -53,6 +62,7 @@ public: ObQueryRangeArray& get_ss_ranges() { return ss_ranges_; } const ObQueryRangeArray& get_ss_ranges() const { return ss_ranges_; } void set_query_range(ObQueryRange *query_range) { query_range_ = query_range; } + void set_pre_range_graph(ObPreRangeGraph *pre_range_graph) { pre_range_graph_ = pre_range_graph; } common::ObIArray &get_range_columns() { return range_columns_; } common::ObIArray &get_expr_constraints() { return expr_constraints_; } void set_valid() { is_valid_ = true; } @@ -87,14 +97,18 @@ public: { index_column_count_ = index_column_count; }; void set_contain_always_false(const bool contain_always_false) { contain_always_false_ = contain_always_false; } + void set_index_prefix(int64_t index_prefix) + { index_prefix_ = index_prefix; } + int64_t get_index_prefix() const { return index_prefix_; } TO_STRING_KV(K_(is_valid), K_(contain_always_false), K_(range_columns), K_(equal_prefix_count), K_(equal_prefix_null_count), K_(range_prefix_count), - K_(index_column_count), K_(expr_constraints)); + K_(index_column_count), K_(expr_constraints), K_(index_prefix)); private: bool is_valid_; bool contain_always_false_; ObQueryRange *query_range_; + ObPreRangeGraph *pre_range_graph_; ObQueryRangeArray ranges_; ObQueryRangeArray ss_ranges_; // for index skip scan, postfix range int64_t equal_prefix_count_; @@ -103,6 +117,7 @@ private: int64_t index_column_count_; // index column count without adding primary key common::ObArray range_columns_; common::ObArray expr_constraints_; + int64_t index_prefix_; DISALLOW_COPY_AND_ASSIGN(QueryRangeInfo); }; diff --git a/src/sql/optimizer/ob_join_order.cpp b/src/sql/optimizer/ob_join_order.cpp index fe1b83a4e..52224d5c3 100755 --- a/src/sql/optimizer/ob_join_order.cpp +++ b/src/sql/optimizer/ob_join_order.cpp @@ -32,6 +32,7 @@ #include "share/stat/ob_opt_stat_manager.h" #include "sql/rewrite/ob_predicate_deduce.h" #include "share/vector_index/ob_vector_index_util.h" +#include "sql/rewrite/ob_query_range_define.h" using namespace oceanbase; using namespace sql; using namespace oceanbase::common; @@ -87,17 +88,18 @@ int ObJoinOrder::fill_query_range_info(const QueryRangeInfo &range_info, ObSEArray cur_const_exprs; ObSEArray columns; bool has_exec_param = false; - if (OB_ISNULL(range_info.get_query_range())) { + const ObQueryRangeProvider *provider = range_info.get_query_range_provider(); + if (OB_ISNULL(provider)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected NULL", K(ret), K(range_info.get_query_range())); - } else if (OB_FAIL(check_has_exec_param(*range_info.get_query_range(), has_exec_param))) { + LOG_WARN("unexpected NULL", K(ret), K(provider)); + } else if (OB_FAIL(check_has_exec_param(*provider, has_exec_param))) { LOG_WARN("failed to check has exec param", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(range_info.get_query_range()->get_range_exprs(), + } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(provider->get_range_exprs(), columns))) { LOG_WARN("failed to extract column exprs", K(ret)); } else if (columns.empty() || !has_exec_param) { /* do nothing */ - } else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(range_info.get_query_range()->get_range_exprs(), + } else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(provider->get_range_exprs(), cur_const_exprs))) { // for inner path, const expr is computed without pushdown filter. // need compute const expr by range_exprs. @@ -982,7 +984,7 @@ int ObJoinOrder::get_query_range_info(const uint64_t table_id, ObOptimizerContext *opt_ctx = NULL; ObSqlSchemaGuard *schema_guard = NULL; ObExecContext *exec_ctx = NULL; - ObQueryRange *query_range = NULL; + ObQueryRangeProvider *query_range_provider = NULL; const share::schema::ObTableSchema *index_schema = NULL; ObQueryRangeArray &ranges = range_info.get_ranges(); ObQueryRangeArray &ss_ranges = range_info.get_ss_ranges(); @@ -1026,6 +1028,7 @@ int ObJoinOrder::get_query_range_info(const uint64_t table_id, int64_t range_prefix_count = 0; bool contain_always_false = false; bool has_exec_param = false; + int64_t out_index_prefix = -1; bool is_domain_index = (is_geo_index || is_multi_index); common::ObSEArray agent_table_filter; @@ -1040,35 +1043,36 @@ int ObJoinOrder::get_query_range_info(const uint64_t table_id, : helper.filters_, range_info.get_expr_constraints(), table_id, - query_range, - index_id))) { + query_range_provider, + index_id, + out_index_prefix))) { LOG_WARN("failed to extract query range", K(ret), K(index_id)); } else if (is_geo_index && OB_FAIL(extract_geo_preliminary_query_range(range_columns, is_oracle_inner_index_table ? agent_table_filter : helper.filters_, domain_columnInfo_map, - query_range))) { + query_range_provider))) { LOG_WARN("failed to extract query range", K(ret), K(index_id)); } else if (is_multi_index && OB_FAIL(extract_multivalue_preliminary_query_range(range_columns, is_oracle_inner_index_table ? agent_table_filter : helper.filters_, - query_range))) { + query_range_provider))) { LOG_WARN("failed to extract query range", K(ret), K(index_id)); - } else if (OB_ISNULL(query_range)) { + } else if (OB_ISNULL(query_range_provider)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(query_range), K(ret)); - } else if (OB_FAIL(query_range->get_tablet_ranges(*allocator_, - *exec_ctx, - ranges, - all_single_value_range, - dtc_params))) { + LOG_WARN("get unexpected null", K(query_range_provider), K(ret)); + } else if (OB_FAIL(query_range_provider->get_tablet_ranges(*allocator_, + *exec_ctx, + ranges, + all_single_value_range, + dtc_params))) { LOG_WARN("failed to final extract query range", K(ret)); - } else if (OB_FAIL(query_range->get_ss_tablet_ranges(*allocator_, - *exec_ctx, - ss_ranges, - dtc_params))) { + } else if (OB_FAIL(query_range_provider->get_ss_tablet_ranges(*allocator_, + *exec_ctx, + ss_ranges, + dtc_params))) { LOG_WARN("failed to final extract index skip query range", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::check_prefix_ranges_count(range_info.get_ranges(), equal_prefix_count, @@ -1076,7 +1080,7 @@ int ObJoinOrder::get_query_range_info(const uint64_t table_id, range_prefix_count, contain_always_false))) { LOG_WARN("failed to compute query range prefix count", K(ret)); - } else if (OB_FAIL(check_has_exec_param(*query_range, has_exec_param))) { + } else if (OB_FAIL(check_has_exec_param(*query_range_provider, has_exec_param))) { LOG_WARN("failed to check has exec param", K(ret)); } else if (!has_exec_param) { //没有exec param就使用真实query range计算equal prefix count @@ -1084,30 +1088,35 @@ int ObJoinOrder::get_query_range_info(const uint64_t table_id, range_info.set_equal_prefix_count(equal_prefix_count); range_info.set_range_prefix_count(range_prefix_count); range_info.set_contain_always_false(contain_always_false); - } else if (OB_FAIL(get_preliminary_prefix_info(*query_range, range_info))) { + } else if (OB_FAIL(get_preliminary_prefix_info(*query_range_provider, range_info))) { LOG_WARN("failed to get preliminary prefix info", K(ret)); } - range_info.set_valid(); - range_info.set_query_range(query_range); - range_info.set_equal_prefix_null_count(equal_prefix_null_count); - range_info.set_index_column_count(index_schema->is_index_table() ? - index_schema->get_index_column_num() : - index_schema->get_rowkey_column_num()); - if (OB_FAIL(ret)) { - if (NULL != query_range) { - query_range->~ObQueryRange(); - query_range = NULL; + if (OB_SUCC(ret)) { + range_info.set_valid(); + if (query_range_provider->is_new_query_range()) { + range_info.set_pre_range_graph(static_cast(query_range_provider)); + } else { + range_info.set_query_range(static_cast(query_range_provider)); } - } else { + range_info.set_equal_prefix_null_count(equal_prefix_null_count); + range_info.set_index_column_count(index_schema->is_index_table() ? + index_schema->get_index_column_num() : + index_schema->get_rowkey_column_num()); + range_info.set_index_prefix(out_index_prefix); LOG_TRACE("succeed to get query range", K(ranges), K(ss_ranges), K(helper.filters_), - K(*query_range), K(range_columns), K(query_range->get_range_exprs()), - K(table_id), K(index_id)); + KPC(query_range_provider), K(range_columns), + K(query_range_provider->get_range_exprs()), K(table_id), K(index_id)); + } else { + if (NULL != query_range_provider) { + query_range_provider->~ObQueryRangeProvider(); + query_range_provider = NULL; + } } } return ret; } -int ObJoinOrder::check_has_exec_param(const ObQueryRange &query_range, +int ObJoinOrder::check_has_exec_param(const ObQueryRangeProvider &query_range, bool &has_exec_param) { int ret = OB_SUCCESS; @@ -1125,22 +1134,18 @@ int ObJoinOrder::check_has_exec_param(const ObQueryRange &query_range, return ret; } -int ObJoinOrder::get_preliminary_prefix_info(ObQueryRange &query_range, +int ObJoinOrder::get_preliminary_prefix_info(ObQueryRangeProvider &query_range_provider, QueryRangeInfo &range_info) { int ret = OB_SUCCESS; int64_t equal_prefix_count = 0; int64_t range_prefix_count = 0; bool contain_always_false = false; - const ObKeyPart *key_part_head = query_range.get_table_grapth().key_part_head_; - if (OB_ISNULL(key_part_head)) { - ret = OB_NOT_INIT; - LOG_WARN("table_graph.key_part_head_ is not inited.", K(ret)); + if (OB_FAIL(query_range_provider.get_prefix_info(equal_prefix_count, + range_prefix_count, + contain_always_false))) { + LOG_WARN("failed to get prefix info"); } else { - get_prefix_info(key_part_head, - equal_prefix_count, - range_prefix_count, - contain_always_false); range_info.set_equal_prefix_count(equal_prefix_count); range_info.set_range_prefix_count(range_prefix_count); range_info.set_contain_always_false(contain_always_false); @@ -1150,35 +1155,6 @@ int ObJoinOrder::get_preliminary_prefix_info(ObQueryRange &query_range, return ret; } -void ObJoinOrder::get_prefix_info(const ObKeyPart *key_part, - int64_t &equal_prefix_count, - int64_t &range_prefix_count, - bool &contain_always_false) -{ - if (OB_NOT_NULL(key_part)) { - equal_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; - range_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; - for ( /*do nothing*/ ; NULL != key_part; key_part = key_part->or_next_) { - int64_t cur_equal_prefix_count = 0; - int64_t cur_range_prefix_count = 0; - if (key_part->is_equal_condition()) { - get_prefix_info(key_part->and_next_, - cur_equal_prefix_count, - cur_range_prefix_count, - contain_always_false); - ++cur_equal_prefix_count; - ++cur_range_prefix_count; - } else if (key_part->is_range_condition()) { - ++cur_range_prefix_count; - } else if (key_part->is_always_false()) { - contain_always_false = true; - } - equal_prefix_count = std::min(cur_equal_prefix_count, equal_prefix_count); - range_prefix_count = std::min(cur_range_prefix_count, range_prefix_count); - } - } -} - int ObJoinOrder::add_table_by_heuristics(const uint64_t table_id, const uint64_t ref_table_id, const ObIndexInfoCache &index_info_cache, @@ -1750,6 +1726,7 @@ int ObJoinOrder::create_one_access_path(const uint64_t table_id, ap->interesting_order_info_ = index_info_entry->get_interesting_order_info(); ap->for_update_ = table_item->for_update_; ap->use_skip_scan_ = use_skip_scan; + ap->index_prefix_ = index_info_entry->get_range_info().get_index_prefix(); ap->use_column_store_ = use_column_store; ap->est_cost_info_.use_column_store_ = use_column_store; @@ -1760,7 +1737,7 @@ int ObJoinOrder::create_one_access_path(const uint64_t table_id, LOG_WARN("failed to init sample info", K(ret)); } else if (OB_FAIL(add_access_filters(ap, ordering_info.get_index_keys(), - range_info.get_query_range()->get_range_exprs(), + (nullptr == range_info.get_query_range_provider()) ? nullptr : &range_info.get_query_range_provider()->get_range_exprs(), helper))) { LOG_WARN("failed to add access filters", K(*ap), K(ordering_info.get_index_keys()), K(ret)); } else if (OB_FAIL(get_plan()->get_stmt()->get_column_items(table_id, ap->est_cost_info_.access_column_items_))) { @@ -1775,6 +1752,7 @@ int ObJoinOrder::create_one_access_path(const uint64_t table_id, LOG_WARN("failed to create index keys expression array", K(index_id), K(ret)); } else if (ordering_info.get_index_keys().count() > 0) { ap->pre_query_range_ = const_cast(range_info.get_query_range()); + ap->pre_range_graph_ = const_cast(range_info.get_pre_range_graph()); if (OB_FAIL(ap->index_keys_.assign(ordering_info.get_index_keys()))) { LOG_WARN("failed to get index keys", K(ret)); } else if (OB_FAIL(ap->est_cost_info_.range_columns_.assign(range_info.get_range_columns()))) { @@ -1795,7 +1773,7 @@ int ObJoinOrder::create_one_access_path(const uint64_t table_id, if (OB_SUCC(ret)) { if (OB_FAIL(fill_filters(ap->filter_, - ap->pre_query_range_, + ap->get_query_range_provider(), ap->est_cost_info_, is_nl_with_extended_range, ObSqlSchemaGuard::is_link_table(get_plan()->get_stmt(), table_id), @@ -2295,7 +2273,7 @@ int ObJoinOrder::get_direction_in_order_by(const ObIArray &order_by, int ObJoinOrder::add_access_filters(AccessPath *path, const ObIArray &index_keys, - const ObIArray &range_exprs, + const ObIArray *range_exprs, PathHelper &helper) { int ret = OB_SUCCESS; @@ -2313,7 +2291,7 @@ int ObJoinOrder::add_access_filters(AccessPath *path, if (ObOptimizerUtil::is_expr_equivalent(deduced_expr_info.deduced_expr_, restrict_infos.at(i), get_plan()->get_equal_sets())) { found = true; - if (ObOptimizerUtil::find_equal_expr(range_exprs, restrict_infos.at(i))) { + if (range_exprs != nullptr && ObOptimizerUtil::find_equal_expr(*range_exprs, restrict_infos.at(i))) { if (OB_FAIL(path->filter_.push_back(restrict_infos.at(i)))) { LOG_WARN("push back error", K(ret)); } else if (OB_FAIL(append(helper.const_param_constraints_, deduced_expr_info.const_param_constraints_))) { @@ -3117,7 +3095,7 @@ int ObJoinOrder::will_use_skip_scan(const uint64_t table_id, int ret = OB_SUCCESS; use_skip_scan = OptSkipScanState::SS_UNSET; IndexInfoEntry *index_info_entry = NULL; - const ObQueryRange *query_range = NULL; + const ObQueryRangeProvider *query_range_provider = NULL; ObQueryCtx *query_ctx = NULL; bool hint_force_skip_scan = false; bool hint_force_no_skip_scan = false; @@ -3133,8 +3111,8 @@ int ObJoinOrder::will_use_skip_scan(const uint64_t table_id, } else if (OB_ISNULL(index_info_entry)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("index info entry should not be null", K(ret)); - } else if (OB_ISNULL(query_range = index_info_entry->get_range_info().get_query_range()) || - !query_range->is_ss_range()) { + } else if (OB_ISNULL(query_range_provider = index_info_entry->get_range_info().get_query_range_provider()) || + !query_range_provider->is_ss_range()) { use_skip_scan = OptSkipScanState::SS_DISABLE; } else if (OB_FAIL(get_plan()->get_log_plan_hint().check_use_skip_scan(table_id, index_id, @@ -3157,7 +3135,7 @@ int ObJoinOrder::will_use_skip_scan(const uint64_t table_id, if (OB_SUCC(ret) && OptSkipScanState::SS_DISABLE != use_skip_scan) { // OptColumnMeta for prefix columns may be not added. It's needed to calculate prefix NDV const ObIArray &column_items = index_info_entry->get_range_info().get_range_columns(); - const int64_t ss_offset = query_range->get_skip_scan_offset(); + const int64_t ss_offset = query_range_provider->get_skip_scan_offset(); const OptSelectivityCtx &ctx = get_plan()->get_selectivity_ctx(); OptTableMeta *table_meta = NULL; if (OB_UNLIKELY(column_items.count() < ss_offset) || @@ -4092,44 +4070,96 @@ int ObJoinOrder::extract_preliminary_query_range(const ObIArray &ran const ObIArray &predicates, ObIArray &expr_constraints, int64_t table_id, - ObQueryRange *&query_range, - int64_t index_id) + ObQueryRangeProvider *&query_range, + int64_t index_id, + int64_t &out_index_prefix) { int ret = OB_SUCCESS; ObOptimizerContext *opt_ctx = NULL; const ParamStore *params = NULL; ObSQLSessionInfo *session_info = NULL; - int64_t index_prefix = -1; + bool enable_better_inlist = false; + bool enable_index_prefix_cost = false; + ObSEArray range_predicates; + ObSEArray total_range_counts; + const LogTableHint *log_table_hint = NULL; + out_index_prefix = -1; if (OB_ISNULL(get_plan()) || OB_ISNULL(opt_ctx = &get_plan()->get_optimizer_context()) || OB_ISNULL(allocator_) || OB_ISNULL(params = opt_ctx->get_params()) || - OB_ISNULL(session_info = opt_ctx->get_session_info())) { + OB_ISNULL(session_info = opt_ctx->get_session_info())|| + OB_ISNULL(get_plan()->get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(get_plan()), K(opt_ctx), K(allocator_), K(params), K(ret)); + } else if (OB_FAIL(check_enable_better_inlist(table_id, enable_better_inlist, enable_index_prefix_cost))) { + LOG_WARN("failed to check better inlist enabled", K(ret)); + } else if (enable_better_inlist && + OB_FAIL(get_candi_range_expr(range_columns, + predicates, + range_predicates))) { + LOG_WARN("failed to get candi range expr", K(ret)); + } else if (!enable_better_inlist && + OB_FAIL(range_predicates.assign(predicates))) { + LOG_WARN("failed to assign exprs", K(ret)); + } else if (OB_FAIL(get_plan()->get_log_plan_hint().get_index_prefix(table_id, + index_id, + out_index_prefix))) { + LOG_WARN("failed to get index prefix", K(table_id), K(index_id), K(out_index_prefix), K(ret)); + } else if (opt_ctx->enable_new_query_range()) { + void *ptr = allocator_->alloc(sizeof(ObPreRangeGraph)); + ObPreRangeGraph *pre_range_graph = NULL; + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for pre range graph", K(ret)); + } else { + pre_range_graph = new(ptr)ObPreRangeGraph(*allocator_); + if (OB_FAIL(pre_range_graph->preliminary_extract_query_range(range_columns, range_predicates, + opt_ctx->get_exec_ctx(), + &expr_constraints, + params, false, true, + out_index_prefix))) { + LOG_WARN("failed to preliminary extract query range", K(ret)); + } else if (FALSE_IT(log_table_hint = get_plan()->get_log_plan_hint().get_index_hint(table_id))) { + } else if (NULL != log_table_hint && log_table_hint->is_use_index_hint()) { + // do nothing + } else if (!enable_index_prefix_cost) { + // do nothing + } else if (OB_FAIL(pre_range_graph->get_total_range_sizes(total_range_counts))) { + LOG_WARN("failed to get total range sizes", K(ret)); + } else if (total_range_counts.empty()) { + // do nothing + } else if (OB_FAIL(get_better_index_prefix(pre_range_graph->get_range_exprs(), + pre_range_graph->get_range_expr_max_offsets(), + total_range_counts, + out_index_prefix))) { + LOG_WARN("failed to get better index prefix", K(ret)); + } else if (-1 == out_index_prefix) { + // do nothing + } else if (OB_FALSE_IT(pre_range_graph->reset())) { + } else if (OB_FAIL(pre_range_graph->preliminary_extract_query_range(range_columns, range_predicates, + opt_ctx->get_exec_ctx(), + &expr_constraints, + params, false, true, + out_index_prefix))) { + LOG_WARN("failed to preliminary extract query range", K(ret)); + } + } + if (OB_SUCC(ret)) { + query_range = pre_range_graph; + } else { + if (NULL != pre_range_graph) { + pre_range_graph->~ObPreRangeGraph(); + pre_range_graph = NULL; + } + } } else { void *tmp_ptr = allocator_->alloc(sizeof(ObQueryRange)); ObQueryRange *tmp_qr = NULL; - ObSEArray range_predicates; - bool enable_better_inlist = false; if (OB_ISNULL(tmp_ptr)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory for query range", K(ret)); - } else if (OB_FAIL(check_enable_better_inlist(table_id, enable_better_inlist))) { - LOG_WARN("failed to check better inlist enabled", K(ret)); - } else if (enable_better_inlist && - OB_FAIL(get_candi_range_expr(range_columns, - predicates, - range_predicates))) { - LOG_WARN("failed to get candi range expr", K(ret)); - } else if (!enable_better_inlist && - OB_FAIL(range_predicates.assign(predicates))) { - LOG_WARN("failed to assign exprs", K(ret)); - } else if (OB_FAIL(get_plan()->get_log_plan_hint().get_index_prefix(table_id, - index_id, - index_prefix))) { - LOG_WARN("failed to get index prefix", K(table_id), K(index_id), K(index_prefix), K(ret)); } else { tmp_qr = new(tmp_ptr)ObQueryRange(*allocator_); const ObDataTypeCastParams dtc_params = @@ -4145,7 +4175,7 @@ int ObJoinOrder::extract_preliminary_query_range(const ObIArray &ran &expr_constraints, params, false, true, is_in_range_optimization_enabled, - index_prefix))) { + out_index_prefix))) { LOG_WARN("failed to preliminary extract query range", K(ret)); } } @@ -4161,10 +4191,14 @@ int ObJoinOrder::extract_preliminary_query_range(const ObIArray &ran return ret; } -int ObJoinOrder::check_enable_better_inlist(int64_t table_id, bool &enable) +int ObJoinOrder::check_enable_better_inlist(int64_t table_id, + bool &enable_better_inlist, + bool &enable_index_prefix_cost) { int ret = OB_SUCCESS; - enable = false; + bool enable = false; + enable_better_inlist = false; + enable_index_prefix_cost = false; ObOptimizerContext *opt_ctx = NULL; ObQueryCtx *query_ctx = NULL; ObSQLSessionInfo *session_info = NULL; @@ -4172,7 +4206,8 @@ int ObJoinOrder::check_enable_better_inlist(int64_t table_id, bool &enable) if (OB_ISNULL(get_plan()) || OB_ISNULL(opt_ctx = &get_plan()->get_optimizer_context()) || OB_ISNULL(session_info = opt_ctx->get_session_info()) || - OB_ISNULL(query_ctx = get_plan()->get_optimizer_context().get_query_ctx())) { + OB_ISNULL(query_ctx = get_plan()->get_optimizer_context().get_query_ctx()) || + OB_ISNULL(get_plan()->get_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(get_plan()), K(opt_ctx), K(session_info), K(query_ctx), K(ret)); } else if (!session_info->is_user_session()) { @@ -4187,13 +4222,22 @@ int ObJoinOrder::check_enable_better_inlist(int64_t table_id, bool &enable) } else if (table_meta->use_default_stat()) { enable = false; } + + if (OB_SUCC(ret) && enable) { + if (ObSQLUtils::is_opt_feature_version_ge_425_or_435( + get_plan()->get_stmt()->get_query_ctx()->optimizer_features_enable_version_)) { + enable_index_prefix_cost = true; + } else { + enable_better_inlist = true; + } + } return ret; } int ObJoinOrder::extract_geo_preliminary_query_range(const ObIArray &range_columns, const ObIArray &predicates, const ColumnIdInfoMap &column_schema_info, - ObQueryRange *&query_range) + ObQueryRangeProvider *&query_range) { int ret = OB_SUCCESS; ObOptimizerContext *opt_ctx = NULL; @@ -4205,6 +4249,30 @@ int ObJoinOrder::extract_geo_preliminary_query_range(const ObIArray ret = OB_INVALID_ARGUMENT; LOG_WARN("get unexpected null", K(get_plan()), K(opt_ctx), K(allocator_), K(params), K(ret)); + } else if (opt_ctx->enable_new_query_range()) { + void *ptr = allocator_->alloc(sizeof(ObPreRangeGraph)); + ObPreRangeGraph *pre_range_graph = NULL; + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for pre range graph", K(ret)); + } else { + pre_range_graph = new(ptr)ObPreRangeGraph(*allocator_); + if (OB_FAIL(pre_range_graph->preliminary_extract_query_range(range_columns, predicates, + opt_ctx->get_exec_ctx(), + nullptr, + params, false, true, + -1, &column_schema_info))) { + LOG_WARN("failed to preliminary extract query range", K(ret)); + } + } + if (OB_SUCC(ret)) { + query_range = pre_range_graph; + } else { + if (NULL != pre_range_graph) { + pre_range_graph->~ObPreRangeGraph(); + pre_range_graph = NULL; + } + } } else { void *tmp_ptr = allocator_->alloc(sizeof(ObQueryRange)); ObQueryRange *tmp_qr = NULL; @@ -4248,7 +4316,7 @@ int ObJoinOrder::extract_geo_preliminary_query_range(const ObIArray int ObJoinOrder::extract_multivalue_preliminary_query_range(const ObIArray &range_columns, const ObIArray &predicates, - ObQueryRange *&query_range) + ObQueryRangeProvider *&query_range) { int ret = OB_SUCCESS; ObOptimizerContext *opt_ctx = NULL; @@ -4260,6 +4328,30 @@ int ObJoinOrder::extract_multivalue_preliminary_query_range(const ObIArrayenable_new_query_range()) { + void *ptr = allocator_->alloc(sizeof(ObPreRangeGraph)); + ObPreRangeGraph *pre_range_graph = NULL; + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for pre range graph", K(ret)); + } else { + pre_range_graph = new(ptr)ObPreRangeGraph(*allocator_); + if (OB_FAIL(pre_range_graph->preliminary_extract_query_range(range_columns, predicates, + opt_ctx->get_exec_ctx(), + nullptr, + params, false, true, + -1, NULL))) { + LOG_WARN("failed to preliminary extract query range", K(ret)); + } + } + if (OB_SUCC(ret)) { + query_range = pre_range_graph; + } else { + if (NULL != pre_range_graph) { + pre_range_graph->~ObPreRangeGraph(); + pre_range_graph = NULL; + } + } } else { void *tmp_ptr = allocator_->alloc(sizeof(ObQueryRange)); ObQueryRange *tmp_qr = NULL; @@ -4428,29 +4520,46 @@ int ObJoinOrder::calculate_range_expr_cost(ObIArray &sorted_pr double &cost) { int ret = OB_SUCCESS; - double range_sel = 1; ObSEArray filters; + if (OB_FAIL(get_range_filter(sorted_predicates, + range_exprs, + filters))) { + LOG_WARN("failed to get range filter", K(ret)); + } else if (OB_FAIL(calculate_range_and_filter_expr_cost(range_exprs, + filters, + range_column_count, + range_count, + cost))) { + LOG_WARN("failed to calculate range expr cost", K(ret)); + } + return ret; +} + +int ObJoinOrder::calculate_range_and_filter_expr_cost(ObIArray &range_exprs, + ObIArray &filter_exprs, + int64_t range_column_count, + int64_t range_count, + double &cost) +{ + int ret = OB_SUCCESS; + double range_sel = 1; if (OB_ISNULL(get_plan())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null plan", K(ret)); - } else if (OB_FAIL(get_range_filter(sorted_predicates, - range_exprs, - filters))) { - LOG_WARN("failed to get range filter", K(ret)); } else if (OB_FAIL(ObOptSelectivity::calculate_selectivity(get_plan()->get_basic_table_metas(), - get_plan()->get_selectivity_ctx(), - range_exprs, - range_sel, - get_plan()->get_predicate_selectivities()))) { + get_plan()->get_selectivity_ctx(), + range_exprs, + range_sel, + get_plan()->get_predicate_selectivities()))) { LOG_WARN("failed to calculate selectivity", K(ret)); } else if (OB_FAIL(ObOptEstCost::calc_range_cost(table_meta_info_, - filters, - range_column_count, - range_count, - range_sel, - cost, - get_plan()->get_optimizer_context()))) { - LOG_WARN("failed to estimate range scan cost", K(ret)); + filter_exprs, + range_column_count, + range_count, + range_sel, + cost, + get_plan()->get_optimizer_context()))) { + LOG_WARN("failed to estimate range scan cost", K(ret)); } else { LOG_TRACE("query range cost:", K(range_column_count), K(range_count), K(range_sel), K(cost)); LOG_TRACE("candi range exprs:", K(range_exprs)); @@ -5940,6 +6049,8 @@ int AccessPath::assign(const AccessPath &other, common::ObIAllocator *allocator) use_skip_scan_ = other.use_skip_scan_; use_column_store_ = other.use_column_store_; is_valid_inner_path_ = other.is_valid_inner_path_; + pre_query_range_ = NULL; + pre_range_graph_ = NULL; can_batch_rescan_ = other.can_batch_rescan_; can_das_dynamic_part_pruning_ = other.can_das_dynamic_part_pruning_; @@ -5954,9 +6065,21 @@ int AccessPath::assign(const AccessPath &other, common::ObIAllocator *allocator) LOG_WARN("Failed to assign re_est_param", K(ret)); } else if (OB_FAIL(est_records_.assign(other.est_records_))) { LOG_WARN("Failed to assign re_est_param", K(ret)); - } else if (NULL == other.pre_query_range_) { - pre_query_range_ = NULL; - } else { + } else if (other.pre_range_graph_ != NULL) { + ObPreRangeGraph *range_graph = static_cast(allocator->alloc(sizeof(ObPreRangeGraph))); + if (OB_ISNULL(range_graph)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memory for pre range graph"); + } else { + range_graph = new(range_graph)ObPreRangeGraph(*allocator); + if (OB_FAIL(range_graph->deep_copy(*other.pre_range_graph_))) { + range_graph->~ObPreRangeGraph(); + range_graph = NULL; + } else { + pre_range_graph_ = range_graph; + } + } + } else if (other.pre_query_range_ != NULL) { ObQueryRange *query_range = static_cast(allocator->alloc(sizeof(ObQueryRange))); if (OB_ISNULL(query_range)) { ret = OB_ALLOCATE_MEMORY_FAILED; @@ -13360,7 +13483,7 @@ int ObJoinOrder::get_simple_index_info(const uint64_t table_id, * table_filters: filters that can be evaluated after index back */ int ObJoinOrder::fill_filters(const ObIArray &all_filters, - const ObQueryRange *query_range, + const ObQueryRangeProvider *query_range_provider, ObCostTableScanInfo &est_cost_info, bool &is_nl_with_extended_range, bool is_link, @@ -13368,7 +13491,7 @@ int ObJoinOrder::fill_filters(const ObIArray &all_filters, { int ret = OB_SUCCESS; is_nl_with_extended_range = false; - if (NULL == query_range) { + if (NULL == query_range_provider) { //如果没有抽出query range,那么所有的filter都是table filter ret = est_cost_info.table_filters_.assign(all_filters); } else { @@ -13379,6 +13502,7 @@ int ObJoinOrder::fill_filters(const ObIArray &all_filters, ObBitSet<> prefix_column_bs; ObBitSet<> ex_prefix_column_bs; ObSEArray index_column_descs; + const ObIArray &unprecise_range_exprs = query_range_provider->get_unprecise_range_exprs(); if (OB_ISNULL(get_plan()) || OB_ISNULL(schema_guard = get_plan()->get_optimizer_context().get_sql_schema_guard())) { ret = OB_ERR_UNEXPECTED; @@ -13407,9 +13531,10 @@ int ObJoinOrder::fill_filters(const ObIArray &all_filters, } // if (OB_SUCC(ret)) { - if (OB_FAIL(est_cost_info.prefix_filters_.assign(query_range->get_range_exprs()))) { + if (OB_FAIL(est_cost_info.prefix_filters_.assign(query_range_provider->get_range_exprs()))) { LOG_WARN("failed to assign exprs", K(ret)); - } else if (use_skip_scan && OB_FAIL(est_cost_info.ss_postfix_range_filters_.assign(query_range->get_ss_range_exprs()))) { + } else if (use_skip_scan && + OB_FAIL(est_cost_info.ss_postfix_range_filters_.assign(query_range_provider->get_ss_range_exprs()))) { LOG_WARN("failed to assign exprs", K(ret)); } } @@ -13481,7 +13606,9 @@ int ObJoinOrder::fill_filters(const ObIArray &all_filters, } else if (!expr_column_bs.is_subset(index_column_bs)) { ret = est_cost_info.table_filters_.push_back(filter); } else if (OB_FAIL(can_extract_unprecise_range(est_cost_info.table_id_, filter, - ex_prefix_column_bs, can_extract))) { + ex_prefix_column_bs, + unprecise_range_exprs, + can_extract))) { LOG_WARN("failed to extract column ids", K(ret)); } else if (can_extract) { ret = est_cost_info.pushdown_prefix_filters_.push_back(filter); @@ -13542,6 +13669,7 @@ int ObJoinOrder::fill_filters(const ObIArray &all_filters, int ObJoinOrder::can_extract_unprecise_range(const uint64_t table_id, const ObRawExpr *filter, const ObBitSet<> &ex_prefix_column_bs, + const ObIArray &unprecise_exprs, bool &can_extract) { int ret = OB_SUCCESS; @@ -13551,6 +13679,9 @@ int ObJoinOrder::can_extract_unprecise_range(const uint64_t table_id, if (OB_ISNULL(filter)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr", K(ret)); + } else if (ObOptimizerUtil::find_equal_expr(unprecise_exprs, filter) && + filter->has_flag(CNT_DYNAMIC_PARAM)) { + can_extract = true; } else if (T_OP_EQ == filter->get_expr_type() || T_OP_NSEQ == filter->get_expr_type()) { const ObRawExpr *l_expr = filter->get_param_expr(0); const ObRawExpr *r_expr = filter->get_param_expr(1); @@ -15082,7 +15213,7 @@ int ObJoinOrder::increase_diverse_path_count(AccessPath *ap) if (OB_ISNULL(ap)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("access path is null", K(ret)); - } else if (NULL == ap->pre_query_range_ || + } else if (NULL == ap->get_query_range_provider() || (ap->get_cost_table_scan_info().ranges_.count() == 1 && ap->get_cost_table_scan_info().ranges_.at(0).is_whole_range())) { // ap is whole range @@ -17509,3 +17640,65 @@ int ObJoinOrder::get_matched_inv_index_tid(ObMatchFunRawExpr *match_expr, } return ret; } + +int ObJoinOrder::get_better_index_prefix(const ObIArray &range_exprs, + const ObIArray &range_expr_max_offsets, + const ObIArray &total_range_counts, + int64_t &better_index_prefix) +{ + int ret = OB_SUCCESS; + ObSEArray used_range_exprs; + ObSEArray used_filters; + double range_sel = 1; + double cost = 1; + double min_cost = DBL_MAX; + int64_t min_cost_offset = -1; + uint64_t min_cost_range_count = 0; + better_index_prefix = -1; + if (OB_UNLIKELY(range_exprs.count() != range_expr_max_offsets.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range exprs", K(ret)); + } else if (OB_ISNULL(get_plan())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null plan", K(ret)); + } + for (int64_t offset = total_range_counts.count() - 1; OB_SUCC(ret) && offset >= 0; --offset) { + used_range_exprs.reuse(); + used_filters.reuse(); + range_sel = 1; + uint64_t range_count = offset == -1 ? 1 : total_range_counts.at(offset); + for (int64_t i = 0; OB_SUCC(ret) && i < range_exprs.count(); ++i) { + if (range_expr_max_offsets.at(i) <= offset) { + if (OB_FAIL(used_range_exprs.push_back(range_exprs.at(i)))) { + LOG_WARN("failed to push back array", K(ret)); + } + } else { + if (OB_FAIL(used_filters.push_back(range_exprs.at(i)))) { + LOG_WARN("failed to push back array", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(calculate_range_and_filter_expr_cost(used_range_exprs, + used_filters, + total_range_counts.count(), + range_count, + cost))) { + LOG_WARN("failed to calculate range and filter expr cost", K(ret)); + } else if (total_range_counts.count() - 1 == offset) { + min_cost_offset = offset; + min_cost = cost; + min_cost_range_count = range_count; + } else if ( cost < min_cost) { + min_cost_offset = offset; + min_cost_range_count = range_count; + } + } + if (OB_SUCC(ret)) { + if (total_range_counts.at(total_range_counts.count() - 1) - min_cost_range_count > 500) { + better_index_prefix = min_cost_offset + 1; + LOG_TRACE("choose better index prefix", K(better_index_prefix)); + } + } + return ret; +} diff --git a/src/sql/optimizer/ob_join_order.h b/src/sql/optimizer/ob_join_order.h index e35436e6b..41ecd73fd 100755 --- a/src/sql/optimizer/ob_join_order.h +++ b/src/sql/optimizer/ob_join_order.h @@ -24,6 +24,7 @@ #include "sql/optimizer/ob_fd_item.h" #include "sql/optimizer/ob_logical_operator.h" #include "sql/optimizer/ob_log_plan.h" +#include "sql/rewrite/ob_query_range_define.h" using oceanbase::common::ObString; namespace test @@ -538,6 +539,7 @@ struct EstimateCostInfo { table_partition_info_(NULL), index_keys_(), pre_query_range_(NULL), + pre_range_graph_(NULL), is_get_(false), order_direction_(direction), is_hash_index_(false), @@ -551,6 +553,7 @@ struct EstimateCostInfo { use_skip_scan_(OptSkipScanState::SS_UNSET), use_column_store_(false), is_valid_inner_path_(false), + index_prefix_(-1), can_batch_rescan_(false), can_das_dynamic_part_pruning_(-1), is_index_merge_(false), @@ -635,6 +638,16 @@ struct EstimateCostInfo { { return 1 == est_cost_info_.ranges_.count() && est_cost_info_.ranges_.at(0).is_false_range(); } + ObQueryRangeProvider *get_query_range_provider() + { + return pre_range_graph_ != nullptr ? static_cast(pre_range_graph_) + : static_cast(pre_query_range_); + } + const ObQueryRangeProvider *get_query_range_provider() const + { + return pre_range_graph_ != nullptr ? static_cast(pre_range_graph_) + : static_cast(pre_query_range_); + } int compute_access_path_batch_rescan(); bool is_rescan_path() const { return est_cost_info_.is_rescan_; } @@ -678,6 +691,7 @@ struct EstimateCostInfo { ObTablePartitionInfo *table_partition_info_; common::ObSEArray index_keys_; // index keys ObQueryRange* pre_query_range_; // pre_query_range for each access path + ObPreRangeGraph* pre_range_graph_; // pre_query_graph for each access path bool is_get_; ObOrderDirection order_direction_;//序的方向(升序or倒序) bool is_hash_index_; // is hash index (virtual table and is index) @@ -692,6 +706,7 @@ struct EstimateCostInfo { bool use_column_store_; // mark this access path is inner path and contribute query range bool is_valid_inner_path_; + int64_t index_prefix_; bool can_batch_rescan_; int64_t can_das_dynamic_part_pruning_; bool is_index_merge_; // whether used for index merge @@ -1766,10 +1781,13 @@ struct NullAwareAntiJoinInfo { const common::ObIArray &predicates, ObIArray &expr_constraints, int64_t table_id, - ObQueryRange* &range, - int64_t index_id); + ObQueryRangeProvider* &range, + int64_t index_id, + int64_t &out_index_prefix); - int check_enable_better_inlist(int64_t table_id, bool &enable); + int check_enable_better_inlist(int64_t table_id, + bool &enable_better_inlist, + bool &enable_index_prefix_cost); int get_candi_range_expr(const ObIArray &range_columns, const ObIArray &predicates, @@ -1781,6 +1799,17 @@ struct NullAwareAntiJoinInfo { int64_t range_count, double &cost); + int calculate_range_and_filter_expr_cost(ObIArray &range_exprs, + ObIArray &filter_exprs, + int64_t range_column_count, + int64_t range_count, + double &cost); + + int get_better_index_prefix(const ObIArray &range_exprs, + const ObIArray &range_expr_max_offsets, + const ObIArray &total_range_counts, + int64_t &better_index_prefix); + int sort_predicate_by_index_column(const ObIArray &range_columns, const ObIArray &predicates, ObIArray &sort_exprs, @@ -1798,11 +1827,11 @@ struct NullAwareAntiJoinInfo { int extract_geo_preliminary_query_range(const ObIArray &range_columns, const ObIArray &predicates, const ColumnIdInfoMap &column_schema_info, - ObQueryRange *&query_range); + ObQueryRangeProvider *&query_range); int extract_multivalue_preliminary_query_range(const ObIArray &range_columns, const ObIArray &predicates, - ObQueryRange *&query_range); + ObQueryRangeProvider *&query_range); int extract_geo_schema_info(const uint64_t table_id, const uint64_t index_id, @@ -2360,7 +2389,7 @@ struct NullAwareAntiJoinInfo { private: int add_access_filters(AccessPath *path, const common::ObIArray &index_keys, - const common::ObIArray &range_exprs, + const common::ObIArray *range_exprs, PathHelper &helper); int set_nl_filters(JoinPath *join_path, @@ -2384,15 +2413,10 @@ struct NullAwareAntiJoinInfo { QueryRangeInfo &range_info, PathHelper &helper); - int check_has_exec_param(const ObQueryRange &query_range, + int check_has_exec_param(const ObQueryRangeProvider &query_range, bool &has_exec_param); - int get_preliminary_prefix_info(ObQueryRange &query_range,QueryRangeInfo &range_info); - - void get_prefix_info(const ObKeyPart *key_part, - int64_t &equal_prefix_count, - int64_t &range_prefix_count, - bool &contain_always_false); + int get_preliminary_prefix_info(ObQueryRangeProvider &query_range,QueryRangeInfo &range_info); // @brief check if an index is relevant to the conditions int is_relevant_index(const uint64_t table_id, @@ -2532,7 +2556,7 @@ struct NullAwareAntiJoinInfo { int revise_output_rows_after_creating_path(PathHelper &helper, ObIArray &access_paths); int fill_filters(const common::ObIArray &all_filters, - const ObQueryRange* query_range, + const ObQueryRangeProvider* query_range, ObCostTableScanInfo &est_scan_cost_info, bool &is_nl_with_extended_range, bool is_link = false, @@ -2541,6 +2565,7 @@ struct NullAwareAntiJoinInfo { int can_extract_unprecise_range(const uint64_t table_id, const ObRawExpr *filter, const ObBitSet<> &ex_prefix_column_bs, + const ObIArray &unprecise_exprs, bool &can_extract); int estimate_rowcount_for_access_path(ObIArray &all_paths, diff --git a/src/sql/optimizer/ob_log_plan.cpp b/src/sql/optimizer/ob_log_plan.cpp index ffd61cb8f..b6f53a446 100644 --- a/src/sql/optimizer/ob_log_plan.cpp +++ b/src/sql/optimizer/ob_log_plan.cpp @@ -2899,8 +2899,10 @@ int ObLogPlan::allocate_access_path(AccessPath *ap, scan->set_session_id(table_schema->get_session_id()); } scan->set_pre_query_range(ap->pre_query_range_); + scan->set_pre_range_graph(ap->pre_range_graph_); scan->set_skip_scan(OptSkipScanState::SS_DISABLE != ap->use_skip_scan_); scan->set_table_type(table_schema->get_table_type()); + scan->set_index_prefix(ap->index_prefix_); if (!ap->is_inner_path_ && OB_FAIL(scan->set_query_ranges(ap->get_cost_table_scan_info().ranges_, ap->get_cost_table_scan_info().ss_ranges_))) { @@ -8920,8 +8922,8 @@ int ObLogPlan::get_subplan_filter_correlated_equal_keys(const ObLogicalOperator LOG_WARN("failed to append filter exprs", K(ret)); } else if (log_op_def::LOG_TABLE_SCAN == top->get_type()) { const ObLogTableScan *table_scan = static_cast(top); - if (NULL != table_scan->get_pre_query_range() && - OB_FAIL(append(filters, table_scan->get_pre_query_range()->get_range_exprs()))) { + if (NULL != table_scan->get_pre_graph() && + OB_FAIL(append(filters, table_scan->get_pre_graph()->get_range_exprs()))) { LOG_WARN("failed to append conditions", K(ret)); } } diff --git a/src/sql/optimizer/ob_log_table_scan.cpp b/src/sql/optimizer/ob_log_table_scan.cpp index ee6238cff..47c25d815 100644 --- a/src/sql/optimizer/ob_log_table_scan.cpp +++ b/src/sql/optimizer/ob_log_table_scan.cpp @@ -42,8 +42,9 @@ const char *ObLogTableScan::get_name() const const char *name = NULL; int ret = OB_SUCCESS; SampleInfo::SampleMethod sample_method = get_sample_info().method_; - if (NULL != pre_query_range_) { - if (OB_FAIL(get_pre_query_range()->is_get(is_get))) { + const ObQueryRangeProvider *pre_range = get_pre_graph(); + if (NULL != pre_range) { + if (OB_FAIL(pre_range->is_get(is_get))) { // is_get always return true LOG_WARN("failed to get is_get", K(ret)); } else if (range_conds_.count() > 0) { @@ -1382,6 +1383,7 @@ int ObLogTableScan::pick_out_query_range_exprs() ObOptimizerContext *opt_ctx = NULL; ObSqlSchemaGuard *schema_guard = NULL; const share::schema::ObTableSchema *index_schema = NULL; + const ObQueryRangeProvider *pre_range = get_pre_graph(); /* * virtual table may have hash index, * for hash index, if it is a get, we should still extract the range condition @@ -1400,8 +1402,8 @@ int ObLogTableScan::pick_out_query_range_exprs() LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(is_table_get(is_get))) { LOG_WARN("failed to check is table get", K(ret)); - } else if ((index_schema->is_ordered() || is_get) && NULL != pre_query_range_) { - const ObIArray &range_exprs = pre_query_range_->get_range_exprs(); + } else if ((index_schema->is_ordered() || is_get) && NULL != pre_range) { + const ObIArray &range_exprs = pre_range->get_range_exprs(); ObArray filter_exprs; if (OB_FAIL(filter_exprs.assign(filter_exprs_))) { LOG_WARN("assign filter exprs failed", K(ret)); @@ -2217,7 +2219,7 @@ int ObLogTableScan::print_range_annotation(char *buf, } if (OB_SUCC(ret) && is_skip_scan()) { - int64_t skip_scan_offset = get_pre_query_range()->get_skip_scan_offset(); + int64_t skip_scan_offset = get_pre_graph()->get_skip_scan_offset(); if (OB_FAIL(BUF_PRINTF("\n prefix_columns_cnt = %ld , skip_scan_range", skip_scan_offset))) { LOG_WARN("BUF_PRINTF fails", K(ret)); } else if (ss_ranges_.empty() && OB_FAIL(BUF_PRINTF("(MIN ; MAX)"))) { @@ -2241,6 +2243,16 @@ int ObLogTableScan::print_range_annotation(char *buf, } } + if (OB_SUCC(ret) && EXPLAIN_EXTENDED == type) { + if (pre_range_graph_ != nullptr && pre_range_graph_->is_fast_nlj_range()) { + if (OB_FAIL(BUF_PRINTF(", "))) { + LOG_WARN("BUF_PRINTF fails", K(ret)); + } else if (OB_FAIL(BUF_PRINTF(" is_fast_range = true"))) { + LOG_WARN("BUF_PRINTF fails", K(ret)); + } + } + } + return ret; } @@ -2295,7 +2307,7 @@ int ObLogTableScan::print_outline_data(PlanText &plan_text) TableItem *table_item = NULL; ObString qb_name; const ObString *index_name = NULL; - int64_t index_prefix = -1; + int64_t index_prefix = index_prefix_; ObItemType index_type = T_INDEX_HINT; const ObDMLStmt *stmt = NULL; if (OB_ISNULL(get_plan()) || OB_ISNULL(stmt = get_plan()->get_stmt())) { @@ -2323,10 +2335,6 @@ int ObLogTableScan::print_outline_data(PlanText &plan_text) } else { index_name = &get_index_name(); } - } else if (OB_FAIL(get_plan()->get_log_plan_hint().get_index_prefix(table_id_, - index_table_id_, - index_prefix))) { - LOG_WARN("failed to get index prefix", K(table_id_), K(index_table_id_), K(index_prefix), K(ret)); } else if (ref_table_id_ == index_table_id_ && index_prefix < 0) { index_type = T_FULL_HINT; index_name = &ObIndexHint::PRIMARY_KEY; @@ -2568,8 +2576,9 @@ int ObLogTableScan::allocate_granule_post(AllocGIContext &ctx) int ObLogTableScan::is_table_get(bool &is_get) const { int ret = OB_SUCCESS; - if (pre_query_range_ != NULL) { - if (OB_FAIL(pre_query_range_->is_get(is_get))) { + const ObQueryRangeProvider *pre_range = get_pre_graph(); + if (pre_range != NULL) { + if (OB_FAIL(pre_range->is_get(is_get))) { LOG_WARN("check query range is table get", K(ret)); } } diff --git a/src/sql/optimizer/ob_log_table_scan.h b/src/sql/optimizer/ob_log_table_scan.h index 1c91f69d0..741475592 100644 --- a/src/sql/optimizer/ob_log_table_scan.h +++ b/src/sql/optimizer/ob_log_table_scan.h @@ -177,6 +177,7 @@ public: for_update_(false), for_update_wait_us_(-1), /* default infinite */ pre_query_range_(NULL), + pre_range_graph_(NULL), part_ids_(NULL), filter_before_index_back_(), table_partition_info_(NULL), @@ -225,6 +226,7 @@ public: multivalue_type_(-1), is_tsc_with_vid_(false), rowkey_vid_tid_(common::OB_INVALID_ID), + index_prefix_(-1), mr_mv_scan_(common::ObQueryFlag::NormalMode) { } @@ -309,6 +311,18 @@ public: inline const ObQueryRange *get_pre_query_range() const { return pre_query_range_; } + inline const ObPreRangeGraph *get_pre_range_graph() const + { return pre_range_graph_; } + + inline const ObQueryRangeProvider *get_pre_graph() const + { + return pre_range_graph_ != nullptr ? static_cast(pre_range_graph_) + : static_cast(pre_query_range_); + } + + inline bool is_new_query_range() const + { return pre_range_graph_ != nullptr; } + /** * Get range columns */ @@ -374,6 +388,9 @@ public: inline void set_pre_query_range(const ObQueryRange *query_range) { pre_query_range_ = query_range; } + inline void set_pre_range_graph(const ObPreRangeGraph *range_graph) + { pre_range_graph_ = range_graph; } + /** * Set range columns */ @@ -494,18 +511,28 @@ public: inline void set_index_name(common::ObString &index_name) { index_name_= index_name; } + inline void set_index_prefix(int64_t index_prefix) + { index_prefix_ = index_prefix; } + inline ObTablePartitionInfo *get_table_partition_info() { return table_partition_info_; } inline const ObTablePartitionInfo *get_table_partition_info() const { return table_partition_info_; } inline void set_table_partition_info(ObTablePartitionInfo *table_partition_info) { table_partition_info_ = table_partition_info; } bool is_index_scan() const { return ref_table_id_ != index_table_id_; } - bool is_table_whole_range_scan() const { return !is_index_scan() && (NULL == pre_query_range_ || - (1 == ranges_.count() && ranges_.at(0).is_whole_range())); } + bool is_table_whole_range_scan() const + { + return !is_index_scan() && + ((NULL == pre_query_range_ && NULL == pre_range_graph_) || + (1 == ranges_.count() && ranges_.at(0).is_whole_range())); + } void set_skip_scan(bool is_skip_scan) { is_skip_scan_ = is_skip_scan; } bool is_skip_scan() const { return is_skip_scan_; } virtual bool is_table_scan() const override { return true; } - bool is_whole_range_scan() const {return NULL == pre_query_range_ - || (1 == ranges_.count() && ranges_.at(0).is_whole_range()); } + bool is_whole_range_scan() const + { + return (NULL == pre_query_range_ && NULL == pre_range_graph_) || + (1 == ranges_.count() && ranges_.at(0).is_whole_range()); + } ObOrderDirection get_scan_direction() const { return scan_direction_; } void set_index_back(bool index_back) { index_back_ = index_back; } bool get_index_back() const { return index_back_; } @@ -766,6 +793,7 @@ protected: // memeber variables // query range after preliminary extract, which will be stored in physical plan // for future use const ObQueryRange *pre_query_range_; + const ObPreRangeGraph *pre_range_graph_; const common::ObIArray *part_ids_; common::ObSEArray range_conds_; @@ -903,6 +931,7 @@ protected: // memeber variables uint64_t rowkey_vid_tid_; // end for table scan with vid + int64_t index_prefix_; common::ObQueryFlag::MRMVScanMode mr_mv_scan_; // used for major refresh mview fast refresh and real-time mview // disallow copy and assign diff --git a/src/sql/optimizer/ob_logical_operator.cpp b/src/sql/optimizer/ob_logical_operator.cpp index 468e3214d..d5650f935 100644 --- a/src/sql/optimizer/ob_logical_operator.cpp +++ b/src/sql/optimizer/ob_logical_operator.cpp @@ -5051,11 +5051,11 @@ int ObLogicalOperator::check_can_extract_query_range_by_rf( // maybe temp table access op, can not extract query range can_extract_query_range = false; } else if (FALSE_IT(scan_op = static_cast(scan_node))) { - } else if (OB_ISNULL(scan_op->get_pre_query_range()) ) { + } else if (OB_ISNULL(scan_op->get_pre_graph()) ) { // for virtual table, the pre_query_range may be null, // can not extract query range by runtime filter can_extract_query_range = false; - } else if (!scan_op->get_pre_query_range()->is_precise_whole_range()) { + } else if (!scan_op->get_pre_graph()->is_precise_whole_range()) { // already has query range which is not whole range, // do not extract query range by runtime filter can_extract_query_range = false; diff --git a/src/sql/optimizer/ob_opt_selectivity.cpp b/src/sql/optimizer/ob_opt_selectivity.cpp index 8318debac..7aa2c48fc 100644 --- a/src/sql/optimizer/ob_opt_selectivity.cpp +++ b/src/sql/optimizer/ob_opt_selectivity.cpp @@ -19,6 +19,7 @@ #include "share/schema/ob_part_mgr_util.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/rewrite/ob_query_range.h" +#include "sql/rewrite/ob_query_range_define.h" #include "sql/optimizer/ob_opt_est_utils.h" #include "sql/optimizer/ob_optimizer.h" #include "sql/optimizer/ob_optimizer_util.h" @@ -1609,7 +1610,7 @@ int ObOptSelectivity::get_column_range_sel(const OptTableMetas &table_metas, const ObDMLStmt *stmt = ctx.get_stmt(); uint64_t tid = col_expr.get_table_id(); uint64_t cid = col_expr.get_column_id(); - ObQueryRange query_range; + ObArenaAllocator allocator("ObSelRange", OB_MALLOC_NORMAL_BLOCK_SIZE, ctx.get_session_info()->get_effective_tenant_id()); ObQueryRangeArray ranges; ObSEArray column_items; bool use_hist = false; @@ -1620,7 +1621,7 @@ int ObOptSelectivity::get_column_range_sel(const OptTableMetas &table_metas, } else if (OB_FAIL(check_column_in_current_level_stmt(stmt, col_expr))) { LOG_WARN("failed to check if column is in current level stmt", K(col_expr), K(ret)); } else if (OB_FAIL(get_column_query_range(ctx, tid, cid, quals, - column_items, query_range, ranges))) { + column_items, allocator, ranges))) { LOG_WARN("failed to get column query range", K(ret)); } else { selectivity = 0.0; @@ -1706,7 +1707,7 @@ int ObOptSelectivity::get_column_range_min_max(const OptSelectivityCtx &ctx, const ObDMLStmt *stmt = ctx.get_stmt(); uint64_t tid = 0; uint64_t cid = 0; - ObQueryRange query_range; + ObArenaAllocator allocator("ObSelRange", OB_MALLOC_NORMAL_BLOCK_SIZE, ctx.get_session_info()->get_effective_tenant_id()); ObQueryRangeArray ranges; ObSEArray column_items; if (OB_ISNULL(stmt) || OB_ISNULL(col_expr) || @@ -1717,7 +1718,7 @@ int ObOptSelectivity::get_column_range_min_max(const OptSelectivityCtx &ctx, } else if (OB_FAIL(check_column_in_current_level_stmt(stmt, *col_expr))) { LOG_WARN("failed to check if column is in current level stmt", KPC(col_expr), K(ret)); } else if (OB_FAIL(get_column_query_range(ctx, tid, cid, quals, - column_items, query_range, ranges))) { + column_items, allocator, ranges))) { LOG_WARN("failed to get column query range", K(ret)); } else if (OB_ISNULL(column_items.at(0).expr_) || OB_UNLIKELY(ranges.empty())) { @@ -2756,50 +2757,63 @@ int ObOptSelectivity::get_column_query_range(const OptSelectivityCtx &ctx, const uint64_t column_id, const ObIArray &quals, ObIArray &column_items, - ObQueryRange &query_range, + ObIAllocator &alloc, ObQueryRangeArray &ranges) { int ret = OB_SUCCESS; const ObLogPlan *log_plan = ctx.get_plan(); const ParamStore *params = ctx.get_params(); ObExecContext *exec_ctx = ctx.get_opt_ctx().get_exec_ctx(); - ObIAllocator &allocator = ctx.get_allocator(); + ObSQLSessionInfo *session_info = ctx.get_session_info(); ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(ctx.get_session_info()); const ColumnItem* column_item = NULL; bool dummy_all_single_value_ranges = true; - bool is_in_range_optimization_enabled = false; - if (OB_ISNULL(log_plan) || OB_ISNULL(exec_ctx) || + if (OB_ISNULL(log_plan) || OB_ISNULL(exec_ctx) || OB_ISNULL(session_info) || OB_ISNULL(column_item = log_plan->get_column_item_by_id(table_id, column_id)) || OB_ISNULL(ctx.get_stmt()) || OB_ISNULL(ctx.get_stmt()->get_query_ctx())) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(ret), K(log_plan), K(exec_ctx), K(column_item)); + LOG_WARN("get unexpected null", K(ret), K(log_plan), K(exec_ctx), K(session_info), K(column_item)); } else if (OB_FAIL(column_items.push_back(*column_item))) { LOG_WARN("failed to push back column item", K(ret)); - } else if (OB_FAIL(ObOptimizerUtil::is_in_range_optimization_enabled(ctx.get_stmt()->get_query_ctx()->get_global_hint(), - ctx.get_session_info(), - is_in_range_optimization_enabled))) { - LOG_WARN("failed to check in range optimization enabled", K(ret)); - } else if (OB_FAIL(query_range.preliminary_extract_query_range(column_items, - quals, - dtc_params, - ctx.get_opt_ctx().get_exec_ctx(), - ctx.get_opt_ctx().get_query_ctx(), - NULL, - params, - false, - true, - is_in_range_optimization_enabled))) { - LOG_WARN("failed to preliminary extract query range", K(ret)); - } else if (!query_range.need_deep_copy()) { - if (OB_FAIL(query_range.direct_get_tablet_ranges(allocator, *exec_ctx, ranges, - dummy_all_single_value_ranges, dtc_params))) { - LOG_WARN("failed to get tablet ranges", K(ret)); + } else if (ctx.get_opt_ctx().enable_new_query_range()) { + ObPreRangeGraph pre_range_graph(alloc); + if (OB_FAIL(pre_range_graph.preliminary_extract_query_range(column_items, quals, exec_ctx, + NULL, params, false, true))) { + LOG_WARN("failed to preliminary extract query range", K(column_items), K(quals)); + } else if (OB_FAIL(pre_range_graph.get_tablet_ranges(alloc, *exec_ctx, ranges, + dummy_all_single_value_ranges, + dtc_params))) { + LOG_WARN("failed to get tablet ranges"); } - } else if (OB_FAIL(query_range.final_extract_query_range(*exec_ctx, dtc_params))) { - LOG_WARN("failed to final extract query range", K(ret)); - } else if (OB_FAIL(query_range.get_tablet_ranges(ranges, dummy_all_single_value_ranges, dtc_params))) { - LOG_WARN("failed to get tablet ranges", K(ret)); - } else { /*do nothing*/ } + } else { + ObQueryRange query_range(alloc); + bool is_in_range_optimization_enabled = false; + if (OB_FAIL(ObOptimizerUtil::is_in_range_optimization_enabled(ctx.get_stmt()->get_query_ctx()->get_global_hint(), + ctx.get_session_info(), + is_in_range_optimization_enabled))) { + LOG_WARN("failed to check in range optimization enabled", K(ret)); + } else if (OB_FAIL(query_range.preliminary_extract_query_range(column_items, + quals, + dtc_params, + ctx.get_opt_ctx().get_exec_ctx(), + ctx.get_opt_ctx().get_query_ctx(), + NULL, + params, + false, + true, + is_in_range_optimization_enabled))) { + LOG_WARN("failed to preliminary extract query range", K(ret)); + } else if (!query_range.need_deep_copy()) { + if (OB_FAIL(query_range.direct_get_tablet_ranges(alloc, *exec_ctx, ranges, + dummy_all_single_value_ranges, dtc_params))) { + LOG_WARN("failed to get tablet ranges", K(ret)); + } + } else if (OB_FAIL(query_range.final_extract_query_range(*exec_ctx, dtc_params))) { + LOG_WARN("failed to final extract query range", K(ret)); + } else if (OB_FAIL(query_range.get_tablet_ranges(ranges, dummy_all_single_value_ranges, dtc_params))) { + LOG_WARN("failed to get tablet ranges", K(ret)); + } else { /*do nothing*/ } + } return ret; } diff --git a/src/sql/optimizer/ob_opt_selectivity.h b/src/sql/optimizer/ob_opt_selectivity.h index 9016bc591..dbf6eb2d4 100644 --- a/src/sql/optimizer/ob_opt_selectivity.h +++ b/src/sql/optimizer/ob_opt_selectivity.h @@ -944,7 +944,7 @@ public: const uint64_t column_id, const ObIArray &quals, ObIArray &column_items, - ObQueryRange &query_range, + ObIAllocator &alloc, ObQueryRangeArray &ranges); // @brief 检测OR中 expr 对于第 index 个子表达式的互斥性, 只检测 c1 = v 的情况, diff --git a/src/sql/optimizer/ob_optimizer.cpp b/src/sql/optimizer/ob_optimizer.cpp index aea2b9c63..ceb3474e4 100644 --- a/src/sql/optimizer/ob_optimizer.cpp +++ b/src/sql/optimizer/ob_optimizer.cpp @@ -679,6 +679,11 @@ int ObOptimizer::extract_opt_ctx_basic_flags(const ObDMLStmt &stmt, ObSQLSession if (!session.is_inner() && stmt.get_query_ctx()->get_injected_random_status()) { ctx_.set_generate_random_plan(true); } + if (session.is_enable_new_query_range() && + ObSQLUtils::is_min_cluster_version_ge_425_or_435() && + ObSQLUtils::is_opt_feature_version_ge_425_or_435(query_ctx->optimizer_features_enable_version_)) { + ctx_.set_enable_new_query_range(true); + } } return ret; } diff --git a/src/sql/optimizer/ob_optimizer_context.h b/src/sql/optimizer/ob_optimizer_context.h index f95dadabb..13b727bb2 100644 --- a/src/sql/optimizer/ob_optimizer_context.h +++ b/src/sql/optimizer/ob_optimizer_context.h @@ -260,6 +260,7 @@ ObOptimizerContext(ObSQLSessionInfo *session_info, use_column_store_replica_(false), push_join_pred_into_view_enabled_(true), table_access_policy_(ObTableAccessPolicy::AUTO), + enable_new_query_range_(false), partition_wise_plan_enabled_(true), enable_px_ordered_coord_(false) { } @@ -684,6 +685,8 @@ ObOptimizerContext(ObSQLSessionInfo *session_info, inline void set_push_join_pred_into_view_enabled(bool enabled) { push_join_pred_into_view_enabled_ = enabled; } inline void set_table_access_policy(ObTableAccessPolicy policy) { table_access_policy_ = policy; } inline ObTableAccessPolicy get_table_acces_policy() const { return table_access_policy_; } + inline void set_enable_new_query_range(bool v) { enable_new_query_range_ = v; } + inline bool enable_new_query_range() const { return enable_new_query_range_; } private: ObSQLSessionInfo *session_info_; ObExecContext *exec_ctx_; @@ -786,6 +789,7 @@ private: bool use_column_store_replica_; bool push_join_pred_into_view_enabled_; ObTableAccessPolicy table_access_policy_; + bool enable_new_query_range_; bool partition_wise_plan_enabled_; bool enable_px_ordered_coord_; }; diff --git a/src/sql/optimizer/ob_optimizer_util.cpp b/src/sql/optimizer/ob_optimizer_util.cpp index 05fb6039b..7fa8b35ba 100644 --- a/src/sql/optimizer/ob_optimizer_util.cpp +++ b/src/sql/optimizer/ob_optimizer_util.cpp @@ -6375,7 +6375,7 @@ bool ObOptimizerUtil::is_lossless_type_conv(const ObExprResType &child_type, con return is_lossless; } -int ObOptimizerUtil::is_lossless_column_cast(const ObRawExpr *expr, bool &is_lossless) +int ObOptimizerUtil::is_lossless_column_cast(const ObRawExpr *expr, bool &is_lossless, bool is_query_range) { int ret = OB_SUCCESS; is_lossless = false; @@ -6427,6 +6427,18 @@ int ObOptimizerUtil::is_lossless_column_cast(const ObRawExpr *expr, bool &is_los ObAccuracy lossless_acc = child_type.get_accuracy(); if (lossless_acc.get_scale() == dst_acc.get_scale()) { is_lossless = true; + } else if (!is_query_range) { + } else if (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale()) { + is_lossless = true; + } else if (dst_acc.get_precision() >= lossless_acc.get_precision() && + dst_acc.get_scale() >= lossless_acc.get_scale()) { + is_lossless = true; + } + } else if (ObDoubleTC == dst_tc && is_query_range) { + ObAccuracy lossless_acc = child_type.get_accuracy(); + if (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale() && + -1 == lossless_acc.get_precision() && -1 == lossless_acc.get_scale()) { + is_lossless = true; } } } else if (ObDateTimeType == child_type.get_type()) { @@ -6445,16 +6457,6 @@ int ObOptimizerUtil::is_lossless_column_cast(const ObRawExpr *expr, bool &is_los } } } else if (ObYearTC == child_tc) { - if (ObNumberTC == dst_tc || ObDecimalIntTC == dst_tc) { - ObAccuracy lossless_acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[ObCompatibilityMode::MYSQL_MODE][child_type.get_type()]; - if (dst_acc.get_precision() - dst_acc.get_scale() >= lossless_acc.get_precision() - lossless_acc.get_scale()) { - is_lossless = true; - } - } else if (ObDoubleTC == dst_tc) { - if (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale()) { - is_lossless = true; - } - } } else if (ObVarcharType == child_type.get_type()) { // varchar, varbinnary } else if (ObCharType == child_type.get_type()) { @@ -6535,6 +6537,13 @@ int ObOptimizerUtil::is_lossless_column_cast(const ObRawExpr *expr, bool &is_los is_lossless = true; } } + } else if (ObDateTimeTC == child_tc) { + if (is_query_range && ObTimestampNanoType == dst_type.get_type()) { + if (dst_type.get_accuracy().get_precision() >= + child_type.get_accuracy().get_precision()) { + is_lossless = true; + } + } } } LOG_DEBUG("lossless column cast", K(child_type), K(child_tc), K(dst_type), K(dst_tc), @@ -6544,7 +6553,8 @@ int ObOptimizerUtil::is_lossless_column_cast(const ObRawExpr *expr, bool &is_los } int ObOptimizerUtil::get_expr_without_lossless_cast(const ObRawExpr* ori_expr, - const ObRawExpr*& expr) + const ObRawExpr*& expr, + bool is_query_range) { int ret = OB_SUCCESS; bool is_lossless = false; @@ -6556,7 +6566,7 @@ int ObOptimizerUtil::get_expr_without_lossless_cast(const ObRawExpr* ori_expr, if (OB_FAIL(get_expr_without_lossless_cast(ori_expr->get_param_expr(2), expr))) { LOG_WARN("failed to check is lossless column cast", K(ret)); } - } else if (OB_FAIL(is_lossless_column_cast(ori_expr, is_lossless))) { + } else if (OB_FAIL(is_lossless_column_cast(ori_expr, is_lossless, is_query_range))) { LOG_WARN("failed to check is lossless column cast", K(ret)); } else if (is_lossless) { expr = ori_expr->get_param_expr(0); @@ -6565,7 +6575,8 @@ int ObOptimizerUtil::get_expr_without_lossless_cast(const ObRawExpr* ori_expr, } int ObOptimizerUtil::get_expr_without_lossless_cast(ObRawExpr* ori_expr, - ObRawExpr*& expr) + ObRawExpr*& expr, + bool is_query_range) { int ret = OB_SUCCESS; bool is_lossless = false; @@ -6573,7 +6584,95 @@ int ObOptimizerUtil::get_expr_without_lossless_cast(ObRawExpr* ori_expr, if (OB_ISNULL(ori_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); - } else if (OB_FAIL(is_lossless_column_cast(ori_expr, is_lossless))) { + } else if (OB_FAIL(is_lossless_column_cast(ori_expr, is_lossless, is_query_range))) { + LOG_WARN("failed to check is lossless column cast", K(ret)); + } else if (is_lossless) { + expr = ori_expr->get_param_expr(0); + } + return ret; +} + +int ObOptimizerUtil::get_column_expr_without_nvl(ObRawExpr* ori_expr, ObRawExpr*& expr) +{ + int ret = OB_SUCCESS; + ObOpRawExpr *op_expr = NULL; + ObRawExpr *l_expr = NULL; + ObRawExpr *r_expr = NULL; + expr = ori_expr; + if (OB_ISNULL(ori_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (T_FUN_SYS_NVL != ori_expr->get_expr_type()) { + // do nothing + } else if (OB_FALSE_IT(op_expr = static_cast(expr))) { + } else if (OB_ISNULL(l_expr = op_expr->get_param_expr(0))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(get_expr_without_lossless_cast(l_expr, l_expr, true))) { + LOG_WARN("get expr without lossless cast", K(ret)); + } else if (l_expr->is_column_ref_expr()) { + expr = l_expr; + } + return ret; +} + +int ObOptimizerUtil::is_lossless_or_unprecise_column_cast(const ObRawExpr *expr, bool &is_lossless) +{ + int ret = OB_SUCCESS; + const ObRawExpr *child_expr = NULL; + is_lossless = false; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (T_FUN_SYS_CAST != expr->get_expr_type()) { + // do nothing + } else if (OB_FAIL(is_lossless_column_cast(expr, is_lossless, true))) { + LOG_WARN("failed to check is lossless column cast", K(ret)); + } else if (is_lossless || + expr->is_const_expr()) { + // do nothing + } else if (OB_ISNULL(child_expr = expr->get_param_expr(0))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else { + ObExprResType child_type = child_expr->get_result_type(); + ObObjTypeClass child_tc = child_type.get_type_class(); + ObExprResType dst_type = expr->get_result_type(); + ObObjTypeClass dst_tc = dst_type.get_type_class(); + ObAccuracy dst_acc = dst_type.get_accuracy(); + if (!is_oracle_mode()) { + if (ObIntTC == child_tc ) { + if (dst_tc == ObDoubleTC && dst_acc.get_precision() == -1 && + dst_acc.get_scale() == -1) { + is_lossless = true; + } + } else if (ObYearTC == child_tc) { + if (ObNumberTC == dst_tc) { + is_lossless = true; + } else if (ObDoubleTC == dst_tc) { + if (-1 == dst_acc.get_precision() && -1 == dst_acc.get_scale()) { + is_lossless = true; + } + } + } else if (ObNumberTC == child_tc) { + if (ObDoubleTC == dst_tc || ObFloatTC == dst_tc) { + is_lossless = true; + } + } + } + } + return ret; +} + +int ObOptimizerUtil::get_expr_without_unprecise_and_lossless_cast(ObRawExpr* ori_expr, ObRawExpr*& expr) +{ + int ret = OB_SUCCESS; + bool is_lossless = false; + expr = ori_expr; + if (OB_ISNULL(ori_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(is_lossless_or_unprecise_column_cast(ori_expr, is_lossless))) { LOG_WARN("failed to check is lossless column cast", K(ret)); } else if (is_lossless) { expr = ori_expr->get_param_expr(0); diff --git a/src/sql/optimizer/ob_optimizer_util.h b/src/sql/optimizer/ob_optimizer_util.h index 719e96c5d..6125cdc96 100644 --- a/src/sql/optimizer/ob_optimizer_util.h +++ b/src/sql/optimizer/ob_optimizer_util.h @@ -1122,13 +1122,17 @@ public: const EqualSets &equal_sets, const ObIArray &const_exprs, bool &is_match); - - static int is_lossless_column_cast(const ObRawExpr *expr, bool &is_lossless); + static int is_lossless_column_cast(const ObRawExpr *expr, bool &is_lossless, bool is_query_range = false); static bool is_lossless_type_conv(const ObExprResType &child_type, const ObExprResType &dst_type); static int is_lossless_column_conv(const ObRawExpr *expr, bool &is_lossless); - static int get_expr_without_lossless_cast(const ObRawExpr* ori_expr, const ObRawExpr*& expr); - static int get_expr_without_lossless_cast(ObRawExpr* ori_expr, ObRawExpr*& expr); - + static int get_expr_without_lossless_cast(const ObRawExpr* ori_expr, const ObRawExpr*& expr, bool is_query_range = false); + static int get_expr_without_lossless_cast(ObRawExpr* ori_expr, ObRawExpr*& expr, bool is_query_range = false); + /** + * This interface is specifically designed for query range, used to retrieve the column c1 that can extract the range from nvl(c1, 1) = 1. + */ + static int get_column_expr_without_nvl(ObRawExpr* ori_expr, ObRawExpr*& expr); + static int get_expr_without_unprecise_and_lossless_cast(ObRawExpr* ori_expr, ObRawExpr*& expr); + static int is_lossless_or_unprecise_column_cast(const ObRawExpr *expr, bool &is_lossless); static int gen_set_target_list(ObIAllocator *allocator, ObSQLSessionInfo *session_info, ObRawExprFactory *expr_factory, diff --git a/src/sql/optimizer/ob_select_log_plan.cpp b/src/sql/optimizer/ob_select_log_plan.cpp index bbe5bf9c7..90802248e 100644 --- a/src/sql/optimizer/ob_select_log_plan.cpp +++ b/src/sql/optimizer/ob_select_log_plan.cpp @@ -7826,38 +7826,60 @@ int ObSelectLogPlan::adjust_late_materialization_plan_structure(ObLogicalOperato if (OB_SUCC(ret)) { const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(optimizer_context_.get_session_info()); - ObQueryRange *query_range = static_cast(get_allocator().alloc(sizeof(ObQueryRange))); const ParamStore *params = get_optimizer_context().get_params(); - if (OB_ISNULL(query_range)) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("failed to allocate memory for query range", K(ret)); - } else if (OB_ISNULL(params)) { + if (OB_ISNULL(params)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); - } else { - query_range = new(query_range)ObQueryRange(get_allocator()); - bool is_in_range_optimization_enabled = false; - if (OB_FAIL(ObOptimizerUtil::is_in_range_optimization_enabled(optimizer_context_.get_global_hint(), - optimizer_context_.get_session_info(), - is_in_range_optimization_enabled))) { - LOG_WARN("failed to check in range optimization enabled", K(ret)); - } else if (OB_FAIL(query_range->preliminary_extract_query_range(range_columns, - join_conditions, - dtc_params, - optimizer_context_.get_exec_ctx(), - optimizer_context_.get_query_ctx(), - NULL, - params, - false, - true, - is_in_range_optimization_enabled))) { - LOG_WARN("failed to preliminary extract query range", K(ret)); - } else if (OB_FAIL(table_scan->set_range_columns(range_columns))) { - LOG_WARN("failed to set range columns", K(ret)); + } else if (OB_FAIL(table_scan->set_range_columns(range_columns))) { + LOG_WARN("failed to set range columns", K(ret)); + } else if (optimizer_context_.enable_new_query_range()) { + ObPreRangeGraph *pre_range_graph = static_cast(get_allocator().alloc(sizeof(ObPreRangeGraph))); + if (OB_ISNULL(pre_range_graph)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for pre range graph", K(ret)); } else { - table_scan->set_pre_query_range(query_range); + pre_range_graph = new(pre_range_graph)ObPreRangeGraph(get_allocator()); + if (OB_FAIL(pre_range_graph->preliminary_extract_query_range(range_columns, + join_conditions, + optimizer_context_.get_exec_ctx(), + NULL, + params, + false, + true))) { + LOG_WARN("failed to preliminary extract query range", K(ret)); + } else { + table_scan->set_pre_range_graph(pre_range_graph); + } + } + } else { + ObQueryRange *query_range = static_cast(get_allocator().alloc(sizeof(ObQueryRange))); + if (OB_ISNULL(query_range)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for query range", K(ret)); + } else { + query_range = new(query_range)ObQueryRange(get_allocator()); + bool is_in_range_optimization_enabled = false; + if (OB_FAIL(ObOptimizerUtil::is_in_range_optimization_enabled(optimizer_context_.get_global_hint(), + optimizer_context_.get_session_info(), + is_in_range_optimization_enabled))) { + LOG_WARN("failed to check in range optimization enabled", K(ret)); + } else if (OB_FAIL(query_range->preliminary_extract_query_range(range_columns, + join_conditions, + dtc_params, + optimizer_context_.get_exec_ctx(), + optimizer_context_.get_query_ctx(), + NULL, + params, + false, + true, + is_in_range_optimization_enabled))) { + LOG_WARN("failed to preliminary extract query range", K(ret)); + } else { + table_scan->set_pre_query_range(query_range); + } } } + } if (OB_SUCC(ret)) { if (OB_FAIL(table_scan->set_table_scan_filters(join_conditions))) { @@ -8202,8 +8224,8 @@ int ObSelectLogPlan::if_index_back_plan_need_late_materialization(ObLogSort *chi } else if (OB_FAIL(append(temp_exprs, table_scan->get_filter_exprs())) || OB_FAIL(append(temp_exprs, table_keys))) { LOG_WARN("failed to append exprs", K(ret)); - } else if (NULL != table_scan->get_pre_query_range() && - OB_FAIL(append(temp_exprs, table_scan->get_pre_query_range()->get_range_exprs()))) { + } else if (NULL != table_scan->get_pre_graph() && + OB_FAIL(append(temp_exprs, table_scan->get_pre_graph()->get_range_exprs()))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_ISNULL(schema_guard = get_optimizer_context().get_sql_schema_guard())) { ret = OB_ERR_UNEXPECTED; @@ -8267,8 +8289,8 @@ int ObSelectLogPlan::if_column_store_plan_need_late_materialization(ObLogSort *c LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(append(temp_exprs, table_scan->get_filter_exprs()))) { LOG_WARN("failed to append exprs", K(ret)); - } else if (NULL != table_scan->get_pre_query_range() && - OB_FAIL(append(temp_exprs, table_scan->get_pre_query_range()->get_range_exprs()))) { + } else if (NULL != table_scan->get_pre_graph() && + OB_FAIL(append(temp_exprs, table_scan->get_pre_graph()->get_range_exprs()))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(temp_exprs, temp_col_exprs))) { LOG_WARN("extract column exprs failed", K(ret)); diff --git a/src/sql/optimizer/ob_table_location.cpp b/src/sql/optimizer/ob_table_location.cpp index 44e04533b..266563eb7 100644 --- a/src/sql/optimizer/ob_table_location.cpp +++ b/src/sql/optimizer/ob_table_location.cpp @@ -383,6 +383,13 @@ ObPartLocCalcNode *ObPartLocCalcNode::create_part_calc_node( } break; } + case ObPartLocCalcNode::PRE_RANGE_GRAPH: { + ptr = allocator.alloc(sizeof(ObPLPreRangeGraphNode)); + if (NULL != ptr) { + ret_node = new(ptr) ObPLPreRangeGraphNode(allocator); + } + break; + } case ObPartLocCalcNode::FUNC_VALUE: { ptr = allocator.alloc(sizeof(ObPLFuncValueNode)); if (NULL != ptr) { @@ -444,6 +451,13 @@ int ObPartLocCalcNode::create_part_calc_node(common::ObIAllocator &allocator, } break; } + case ObPartLocCalcNode::PRE_RANGE_GRAPH: { + ptr = allocator.alloc(sizeof(ObPLPreRangeGraphNode)); + if (NULL != ptr) { + ret_node = new(ptr) ObPLPreRangeGraphNode(allocator); + } + break; + } case ObPartLocCalcNode::FUNC_VALUE: { ptr = allocator.alloc(sizeof(ObPLFuncValueNode)); if (NULL != ptr) { @@ -601,6 +615,29 @@ int ObPLQueryRangeNode::add_part_calc_node(common::ObIArray return calc_nodes.push_back(this); } +int ObPLPreRangeGraphNode::deep_copy( + ObIAllocator &allocator, + ObIArray &calc_nodes, + ObPartLocCalcNode *&other) const +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(other = create_part_calc_node(allocator, calc_nodes, PRE_RANGE_GRAPH))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("Allocate calc node failed", K(ret)); + } else { + ObPLPreRangeGraphNode *node = static_cast(other); + if (OB_FAIL(node->pre_range_graph_.deep_copy(pre_range_graph_))) { + LOG_WARN("Failed to deep copy pre query range", K(ret)); + } + } + return ret; +} + +int ObPLPreRangeGraphNode::add_part_calc_node(common::ObIArray &calc_nodes) +{ + return calc_nodes.push_back(this); +} + int ObPLFuncValueNode::deep_copy( ObIAllocator &allocator, ObIArray &calc_nodes, @@ -1298,12 +1335,16 @@ int ObTableLocation::init( LOG_WARN("fail to record_in_dml_partition_info", K(ret)); } else if (!is_in_hit_) { bool is_in_range_optimization_enabled = false; + bool use_new_query_range = (session_info->is_enable_new_query_range() + && ObSQLUtils::is_opt_feature_version_ge_425_or_435(stmt.get_query_ctx()->optimizer_features_enable_version_) + && ObSQLUtils::is_min_cluster_version_ge_425_or_435()); if (OB_FAIL(ObOptimizerUtil::is_in_range_optimization_enabled(stmt.get_query_ctx()->get_global_hint(), session_info, is_in_range_optimization_enabled))) { LOG_WARN("failed to check in range optimization enabled", K(ret)); } else if (OB_FAIL(record_not_insert_dml_partition_info(stmt, exec_ctx, table_schema, filter_exprs, dtc_params, - is_in_range_optimization_enabled))) { + is_in_range_optimization_enabled, + use_new_query_range))) { LOG_WARN("Fail to record select or update partition info", K(stmt_type_), K(ret)); } else if (OB_FAIL(get_not_insert_dml_part_sort_expr(stmt, sort_exprs))) { LOG_WARN("Failed to get not insert dml sort key with parts", K(ret)); @@ -2059,7 +2100,8 @@ int ObTableLocation::set_location_calc_node(const ObDMLStmt &stmt, ObPartLocCalcNode *&gen_col_node, bool &get_all, bool &is_range_get, - const bool is_in_range_optimization_enabled) + const bool is_in_range_optimization_enabled, + const bool use_new_query_range) { int ret = OB_SUCCESS; ObSEArray part_columns; @@ -2091,20 +2133,28 @@ int ObTableLocation::set_location_calc_node(const ObDMLStmt &stmt, dtc_params, exec_ctx, query_ctx, - is_in_range_optimization_enabled))) { + is_in_range_optimization_enabled, + use_new_query_range))) { LOG_WARN("Failed to get location calc node", K(ret)); } else if (gen_cols.count() > 0) { //analyze information with dependented column of generated column bool always_true =false; - if (OB_FAIL(get_query_range_node(part_level, - gen_cols, - filter_exprs, - always_true, - gen_col_node, - dtc_params, - exec_ctx, - query_ctx, - is_in_range_optimization_enabled))) { + if (use_new_query_range && OB_FAIL(get_pre_range_graph_node(part_level, + gen_cols, + filter_exprs, + always_true, + gen_col_node, + exec_ctx))) { + LOG_WARN("Get query range node error", K(ret)); + } else if (!use_new_query_range && OB_FAIL(get_query_range_node(part_level, + gen_cols, + filter_exprs, + always_true, + gen_col_node, + dtc_params, + exec_ctx, + query_ctx, + is_in_range_optimization_enabled))) { LOG_WARN("Get query range node error", K(ret)); } else if (always_true) { gen_col_node = NULL; @@ -2375,7 +2425,8 @@ int ObTableLocation::record_not_insert_dml_partition_info( const ObTableSchema *table_schema, const ObIArray &filter_exprs, const ObDataTypeCastParams &dtc_params, - const bool is_in_range_optimization_enabled) + const bool is_in_range_optimization_enabled, + const bool use_new_query_range) { int ret = OB_SUCCESS; if (OB_FAIL(set_location_calc_node(stmt, @@ -2390,7 +2441,8 @@ int ObTableLocation::record_not_insert_dml_partition_info( gen_col_node_, part_get_all_, is_part_range_get_, - is_in_range_optimization_enabled))) { + is_in_range_optimization_enabled, + use_new_query_range))) { LOG_WARN("failed to set location calc node for first-level partition", K(ret)); } else if (PARTITION_LEVEL_TWO == part_level_ && OB_FAIL(set_location_calc_node(stmt, @@ -2405,7 +2457,8 @@ int ObTableLocation::record_not_insert_dml_partition_info( sub_gen_col_node_, subpart_get_all_, is_subpart_range_get_, - is_in_range_optimization_enabled))) { + is_in_range_optimization_enabled, + use_new_query_range))) { LOG_WARN("failed to set location calc node for second-level partition", K(ret)); } @@ -2437,6 +2490,10 @@ int ObTableLocation::get_not_insert_dml_part_sort_expr(const ObDMLStmt &stmt, if (static_cast(calc_node_)->pre_query_range_.is_precise_get()) { part_expr = stmt.get_subpart_expr(loc_meta_.table_loc_id_, loc_meta_.ref_table_id_); } + } else if (calc_node_->is_pre_range_graph_node()) { + if (static_cast(calc_node_)->pre_range_graph_.is_precise_get()) { + part_expr = stmt.get_subpart_expr(loc_meta_.table_loc_id_, loc_meta_.ref_table_id_); + } } else { } } } else { } @@ -2490,7 +2547,8 @@ int ObTableLocation::get_location_calc_node(const ObPartitionLevel part_level, const ObDataTypeCastParams &dtc_params, ObExecContext *exec_ctx, ObQueryCtx *query_ctx, - const bool is_in_range_optimization_enabled) + const bool is_in_range_optimization_enabled, + const bool use_new_query_range) { int ret = OB_SUCCESS; uint64_t column_id = OB_INVALID_ID; @@ -2512,22 +2570,40 @@ int ObTableLocation::get_location_calc_node(const ObPartitionLevel part_level, } else if (only_range_node) { bool always_true = false; ObPartLocCalcNode *calc_node = NULL; - if (OB_FAIL(get_query_range_node(part_level, - partition_columns, - filter_exprs, - always_true, - calc_node, - dtc_params, - exec_ctx, - query_ctx, - is_in_range_optimization_enabled))) { - LOG_WARN("Get query range node error", K(ret)); - } else if (always_true) { - get_all = true; + if (use_new_query_range) { + if (OB_FAIL(get_pre_range_graph_node(part_level, + partition_columns, + filter_exprs, + always_true, + calc_node, + exec_ctx))) { + LOG_WARN("Get query range node error", K(ret)); + } else if (always_true) { + get_all = true; + } else { + res_node = calc_node; + if (OB_NOT_NULL(calc_node)) { + is_range_get = static_cast(calc_node)->pre_range_graph_.is_precise_get(); + } + } } else { - res_node = calc_node; - if (OB_NOT_NULL(calc_node)) { - is_range_get = static_cast(calc_node)->pre_query_range_.is_precise_get(); + if (OB_FAIL(get_query_range_node(part_level, + partition_columns, + filter_exprs, + always_true, + calc_node, + dtc_params, + exec_ctx, + query_ctx, + is_in_range_optimization_enabled))) { + LOG_WARN("Get query range node error", K(ret)); + } else if (always_true) { + get_all = true; + } else { + res_node = calc_node; + if (OB_NOT_NULL(calc_node)) { + is_range_get = static_cast(calc_node)->pre_query_range_.is_precise_get(); + } } } } else { @@ -2562,12 +2638,20 @@ int ObTableLocation::get_location_calc_node(const ObPartitionLevel part_level, ObPartLocCalcNode *column_node = NULL; if (normal_filters.count() > 0) { column_always_true = false; - if (OB_FAIL(get_query_range_node(part_level, partition_columns, filter_exprs, column_always_true, - column_node, dtc_params, exec_ctx, query_ctx, - is_in_range_optimization_enabled))) { - LOG_WARN("Failed to get query range node", K(ret)); - } else if (OB_NOT_NULL(column_node)) { - is_column_range_get = static_cast(column_node)->pre_query_range_.is_precise_get(); + if (use_new_query_range) { + if (OB_FAIL(get_pre_range_graph_node(part_level, partition_columns, filter_exprs, + column_always_true, column_node, exec_ctx))) { + LOG_WARN("Failed to get query range node", K(ret)); + } else if (OB_NOT_NULL(column_node)) { + is_column_range_get = static_cast(column_node)->pre_range_graph_.is_precise_get(); + } + } else { + if (OB_FAIL(get_query_range_node(part_level, partition_columns, filter_exprs, column_always_true, + column_node, dtc_params, exec_ctx, query_ctx, is_in_range_optimization_enabled))) { + LOG_WARN("Failed to get query range node", K(ret)); + } else if (OB_NOT_NULL(column_node)) { + is_column_range_get = static_cast(column_node)->pre_query_range_.is_precise_get(); + } } } if (OB_FAIL(ret)) { @@ -2629,6 +2713,41 @@ int ObTableLocation::get_query_range_node(const ObPartitionLevel part_level, return ret; } +int ObTableLocation::get_pre_range_graph_node(const ObPartitionLevel part_level, + const ColumnIArray &partition_columns, + const ObIArray &filter_exprs, + bool &always_true, + ObPartLocCalcNode *&calc_node, + ObExecContext *exec_ctx) +{ + int ret = OB_SUCCESS; + bool phy_rowid_for_table_loc = (part_level == part_level_); + if (filter_exprs.empty()) { + always_true = true; + } else if (OB_ISNULL(calc_node = ObPartLocCalcNode::create_part_calc_node( + allocator_, calc_nodes_, ObPartLocCalcNode::PRE_RANGE_GRAPH))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("Allocate memory failed", K(ret)); + } else { + ObPLPreRangeGraphNode *node = static_cast(calc_node); + if (OB_FAIL(node->pre_range_graph_.preliminary_extract_query_range(partition_columns, + filter_exprs, + exec_ctx, + NULL, + NULL, + phy_rowid_for_table_loc, + false))) { + LOG_WARN("Failed to pre extract query range", K(ret)); + } else if (node->pre_range_graph_.is_precise_whole_range()) { + //pre query range is whole range, indicate that there are no partition condition in filters, + //so you need to get all part ids + always_true = true; + calc_node = NULL; + } + } + return ret; +} + int ObTableLocation::analyze_filter(const ObIArray &partition_columns, const ObRawExpr *partition_expr, uint64_t column_id, @@ -3144,9 +3263,16 @@ int ObTableLocation::calc_partition_ids_by_calc_node(ObExecContext &exec_ctx, if (NULL != gen_col_node && NULL != se_gen_col_expr) { //partition key is generated column and dependent column condition is not empty //so you need to calc partition id by dependent column condition - if (!gen_col_node->is_query_range_node()) { + if (!gen_col_node->is_query_range_node() && !gen_col_node->is_pre_range_graph_node()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column dependented by generated column calc node should be query range node", K(ret)); + } else if (gen_col_node->is_pre_range_graph_node()) { + if (OB_FAIL(calc_pre_range_graph_partition_ids(exec_ctx, tablet_mapper, params, + static_cast(gen_col_node), + gen_tablet_ids, gen_part_ids, gen_col_all_part, dtc_params, + part_ids, se_gen_col_expr))) { + LOG_WARN("Failed to calcl partition ids by gen col node", K(ret)); + } } else if (OB_FAIL(calc_query_range_partition_ids(exec_ctx, tablet_mapper, params, static_cast(gen_col_node), gen_tablet_ids, gen_part_ids, gen_col_all_part, dtc_params, @@ -3242,6 +3368,13 @@ int ObTableLocation::calc_partition_ids_by_calc_node(ObExecContext &exec_ctx, dtc_params, part_ids, NULL))) { LOG_WARN("Failed to calc and partition ids", K(ret)); } + } else if (ObPartLocCalcNode::PRE_RANGE_GRAPH == calc_node->get_node_type()) { + if (OB_FAIL(calc_pre_range_graph_partition_ids(exec_ctx, tablet_mapper, params, + static_cast(calc_node), + tablet_ids, partition_ids, all_part, + dtc_params, part_ids, NULL))) { + LOG_WARN("Failed to calc and partition ids", K(ret)); + } } else if (ObPartLocCalcNode::FUNC_VALUE == calc_node->get_node_type()) { if (OB_FAIL(calc_func_value_partition_ids(exec_ctx, tablet_mapper, params, static_cast(calc_node), @@ -3423,6 +3556,56 @@ int ObTableLocation::calc_query_range_partition_ids(ObExecContext &exec_ctx, return ret; } +int ObTableLocation::calc_pre_range_graph_partition_ids(ObExecContext &exec_ctx, + ObDASTabletMapper &tablet_mapper, + const ParamStore ¶ms, + const ObPLPreRangeGraphNode *calc_node, + ObIArray &tablet_ids, + ObIArray &partition_ids, + bool &all_part, + const ObDataTypeCastParams &dtc_params, + const ObIArray *part_ids, + const ObTempExpr *se_gen_col_expr) const +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(calc_node)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Calc node should not be NULL", K(ret)); + } else { + all_part = false; + ObQueryRangeArray query_ranges; + ObArenaAllocator allocator(CURRENT_CONTEXT->get_malloc_allocator()); + allocator.set_label("CalcQRPartIds"); + bool is_all_single_value_ranges = true; + if (OB_FAIL(calc_node->pre_range_graph_.get_tablet_ranges(allocator, exec_ctx, query_ranges, + is_all_single_value_ranges, dtc_params))) { + LOG_WARN("get tablet ranges failed", K(ret)); + } else if (OB_UNLIKELY(query_ranges.count() == 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Query ranges' count should not be 0", + "query range count", query_ranges.count(), K(ret)); + } else { + bool is_empty = true; + if (OB_FAIL(is_all_ranges_empty(query_ranges, is_empty))) { + LOG_WARN("fail to check all ranges", K(query_ranges)); + } else if (!is_empty) { + if (OB_FAIL(calc_partition_ids_by_ranges(exec_ctx, + tablet_mapper, + query_ranges, + is_all_single_value_ranges, + tablet_ids, + partition_ids, + all_part, + part_ids, + se_gen_col_expr))) { + LOG_WARN("Failed to get partition ids", K(ret), K(loc_meta_.table_loc_id_)); + } + } else { } //do nothing. partition ids will be empty + } + } + return ret; +} + int ObTableLocation::calc_func_value_partition_ids( ObExecContext &exec_ctx, ObDASTabletMapper &tablet_mapper, @@ -4616,6 +4799,7 @@ OB_DEF_DESERIALIZE(ObPLOrNode) OB_SERIALIZE_MEMBER(ObPLFuncValueNode::ParamValuePair, param_idx_, obj_value_); OB_SERIALIZE_MEMBER(ObPartLocCalcNode, node_type_); OB_SERIALIZE_MEMBER((ObPLQueryRangeNode, ObPartLocCalcNode), pre_query_range_); +OB_SERIALIZE_MEMBER((ObPLPreRangeGraphNode, ObPartLocCalcNode), pre_range_graph_); OB_DEF_SERIALIZE(ObPLFuncValueNode) { diff --git a/src/sql/optimizer/ob_table_location.h b/src/sql/optimizer/ob_table_location.h index f17056c77..fd0378ad1 100644 --- a/src/sql/optimizer/ob_table_location.h +++ b/src/sql/optimizer/ob_table_location.h @@ -15,6 +15,7 @@ #include "lib/hash/ob_pointer_hashmap.h" #include "sql/rewrite/ob_query_range.h" +#include "sql/rewrite/ob_query_range_define.h" #include "sql/das/ob_das_define.h" #include "sql/engine/expr/ob_sql_expression.h" #include "sql/engine/expr/ob_sql_expression_factory.h" @@ -128,6 +129,7 @@ public: QUERY_RANGE, FUNC_VALUE, COLUMN_VALUE, + PRE_RANGE_GRAPH }; ObPartLocCalcNode (common::ObIAllocator &allocator): node_type_(INVALID), allocator_(allocator) @@ -142,6 +144,7 @@ public: inline bool is_query_range_node() const { return QUERY_RANGE == node_type_; } inline bool is_func_value_node() const { return FUNC_VALUE == node_type_; } inline bool is_column_value_node() const { return COLUMN_VALUE == node_type_; } + inline bool is_pre_range_graph_node() const { return PRE_RANGE_GRAPH == node_type_; } static ObPartLocCalcNode *create_part_calc_node(common::ObIAllocator &allocator, common::ObIArray &calc_nodes, @@ -219,6 +222,22 @@ public: ObQueryRange pre_query_range_; }; +struct ObPLPreRangeGraphNode : public ObPartLocCalcNode +{ + OB_UNIS_VERSION_V(1); +public: + ObPLPreRangeGraphNode(common::ObIAllocator &allocator) + : ObPartLocCalcNode(allocator), pre_range_graph_(allocator) + { set_node_type(PRE_RANGE_GRAPH); } + virtual ~ObPLPreRangeGraphNode() + { pre_range_graph_.reset(); } + virtual int deep_copy(common::ObIAllocator &allocator, + common::ObIArray &calc_nodes, + ObPartLocCalcNode *&other) const; + virtual int add_part_calc_node(common::ObIArray &calc_nodes); + ObPreRangeGraph pre_range_graph_; +}; + struct ObPLFuncValueNode : public ObPartLocCalcNode { OB_UNIS_VERSION_V(1); @@ -862,6 +881,17 @@ private: const common::ObIArray *part_ids, const ObTempExpr *temp_expr) const; + int calc_pre_range_graph_partition_ids(ObExecContext &exec_ctx, + ObDASTabletMapper &tablet_mapper, + const ParamStore ¶ms, + const ObPLPreRangeGraphNode *calc_node, + ObIArray &tablet_ids, + ObIArray &partition_ids, + bool &all_part, + const ObDataTypeCastParams &dtc_params, + const ObIArray *part_ids, + const ObTempExpr *se_gen_col_expr) const; + int calc_func_value_partition_ids(ObExecContext &exec_ctx, ObDASTabletMapper &tablet_mapper, const ParamStore ¶ms, @@ -953,7 +983,8 @@ private: const share::schema::ObTableSchema *table_schema, const common::ObIArray &filter_exprs, const common::ObDataTypeCastParams &dtc_params, - const bool is_in_range_optimization_enabled); + const bool is_in_range_optimization_enabled, + const bool use_new_query_range); int add_se_value_expr(const ObRawExpr *value_expr, RowDesc &value_row_desc, @@ -983,7 +1014,8 @@ private: const common::ObDataTypeCastParams &dtc_params, ObExecContext *exec_ctx, ObQueryCtx *query_ctx, - const bool is_in_range_optimization_enabled); + const bool is_in_range_optimization_enabled, + const bool use_new_query_range); int analyze_filter(const common::ObIArray &partition_columns, const ObRawExpr *partition_expr, @@ -1005,6 +1037,13 @@ private: ObQueryCtx *query_ctx, const bool is_in_range_optimization_enabled); + int get_pre_range_graph_node(const ObPartitionLevel part_level, + const ColumnIArray &partition_columns, + const ObIArray &filter_exprs, + bool &always_true, + ObPartLocCalcNode *&calc_node, + ObExecContext *exec_ctx); + int extract_eq_op(ObExecContext *exec_ctx, const ObRawExpr *l_expr, const ObRawExpr *r_expr, @@ -1091,7 +1130,8 @@ private: ObPartLocCalcNode *&gen_col_node, bool &get_all, bool &is_range_get, - const bool is_in_range_optimization_enabled); + const bool is_in_range_optimization_enabled, + const bool use_new_query_range); int calc_partition_ids_by_in_expr( ObExecContext &exec_ctx, @@ -1178,7 +1218,6 @@ private: ObTempExpr *se_sub_gen_col_expr_; common::ObFixedArray part_hint_ids_; - ObQueryRange pre_query_range_; // query range for the table scan ObObjType part_col_type_; ObCollationType part_collation_type_; ObObjType subpart_col_type_; diff --git a/src/sql/plan_cache/ob_adaptive_auto_dop.cpp b/src/sql/plan_cache/ob_adaptive_auto_dop.cpp index 99f509703..b064c5481 100644 --- a/src/sql/plan_cache/ob_adaptive_auto_dop.cpp +++ b/src/sql/plan_cache/ob_adaptive_auto_dop.cpp @@ -92,13 +92,13 @@ int ObAdaptiveAutoDop::calculate_tsc_auto_dop(const ObOpSpec &spec, int64_t &tab bool is_oracle_agent_table = share::is_oracle_mapping_real_virtual_table(tsc_spec.get_ref_table_id()); ObQueryRangeArray key_ranges; - const ObQueryRange &query_range = tsc_spec.get_query_range(); + const ObQueryRangeProvider &query_range_provider = tsc_spec.get_query_range_provider(); if (is_oracle_agent_table || cost_tsc_info.get_is_spatial_index()) { // step1: calculate query range. - } else if (query_range.has_range() + } else if (query_range_provider.has_range() && OB_FAIL(ObSQLUtils::extract_pre_query_range( - query_range, ctx_.get_allocator(), ctx_, key_ranges, + query_range_provider, ctx_.get_allocator(), ctx_, key_ranges, ObBasicSessionInfo::create_dtc_params(ctx_.get_my_session())))) { LOG_WARN("failed to extract pre query ranges", K(ret)); // step2: build est tasks. diff --git a/src/sql/resolver/expr/ob_raw_expr.cpp b/src/sql/resolver/expr/ob_raw_expr.cpp index e61d681f7..6c041ce9d 100644 --- a/src/sql/resolver/expr/ob_raw_expr.cpp +++ b/src/sql/resolver/expr/ob_raw_expr.cpp @@ -1646,6 +1646,7 @@ int64_t ObConstRawExpr::to_string(char* buf, const int64_t buf_len) const N_EXPR_INFO, info_, N_REL_ID, rel_ids_, N_VALUE, value_, + "is_dynamic_questionmark", is_dynamic_eval_questionmark_, K_(expr_hash)); if (!literal_prefix_.empty()) { J_COMMA(); diff --git a/src/sql/rewrite/ob_expr_range_converter.cpp b/src/sql/rewrite/ob_expr_range_converter.cpp new file mode 100644 index 000000000..a83515ec7 --- /dev/null +++ b/src/sql/rewrite/ob_expr_range_converter.cpp @@ -0,0 +1,3699 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX SQL_REWRITE +#include "sql/rewrite/ob_expr_range_converter.h" +#include "sql/rewrite/ob_range_graph_generator.h" +#include "lib/timezone/ob_time_convert.h" +#include "lib/container/ob_array_serialization.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/rc/ob_rc.h" +#include "sql/resolver/dml/ob_dml_stmt.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" +#include "sql/engine/expr/ob_expr_like.h" +#include "common/ob_smart_call.h" +#include "sql/optimizer/ob_optimizer_util.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "sql/ob_sql_utils.h" +#include "sql/rewrite/ob_range_generator.h" + +namespace oceanbase +{ +using namespace common; +using namespace share::schema; +namespace sql +{ +static const int64_t RANGE_EXPR_EQUAL = 1 << 1; +static const int64_t RANGE_EXPR_CMP = 1 << 2; +static const int64_t RANGE_EXPR_IN = 1 << 3; +static const int64_t RANGE_EXPR_NO_EQUAL = 1 << 4; +static const int64_t RANGE_EXPR_NOT_IN = 1 << 5; +static const int64_t RANGE_EXPR_OTHER = 1 << 6; + +/** + * TODO list: + * spatial_expr use new query range + * */ + +int ObExprRangeConverter::convert_expr_to_range_node(const ObRawExpr *expr, + ObRangeNode *&range_node, + int64_t expr_depth, + bool &is_precise) +{ + int ret = OB_SUCCESS; + range_node = nullptr; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (expr->is_const_expr()) { + if(OB_FAIL(convert_const_expr(expr, range_node))) { + LOG_WARN("failed to convert const expr"); + } + } else if (T_OP_LIKE == expr->get_expr_type()) { + if(OB_FAIL(convert_like_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert like expr"); + } + } else if (IS_BASIC_CMP_OP(expr->get_expr_type())) { + if (OB_FAIL(convert_basic_cmp_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert basic cmp expr"); + } + } else if (0 == expr_depth && T_OP_NE == expr->get_expr_type()) { + if (OB_FAIL(convert_not_equal_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert not equal expr"); + } + } else if (T_OP_IS == expr->get_expr_type()) { + if (OB_FAIL(convert_is_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert is expr"); + } + } else if (T_OP_BTW == expr->get_expr_type()) { + if (OB_FAIL(convert_between_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert between expr"); + } + } else if (0 == expr_depth && T_OP_NOT_BTW == expr->get_expr_type()) { + if (OB_FAIL(convert_not_between_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert not between expr"); + } + } else if (T_OP_IN == expr->get_expr_type()) { + if (OB_FAIL(convert_in_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert in expr"); + } + } else if (0 == expr_depth && T_OP_NOT_IN == expr->get_expr_type() && + ctx_.enable_not_in_range_) { + if (OB_FAIL(convert_not_in_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert not in expr"); + } + } else if (expr->is_spatial_expr()) { + if (OB_FAIL(convert_geo_expr(expr, expr_depth, range_node))) { + LOG_WARN("failed to convert geo expr"); + } + } else if (expr->is_domain_expr()) { + if (OB_FAIL(convert_domain_expr(expr, expr_depth, range_node))) { + LOG_WARN("extract and_or failed", K(ret)); + } + } else { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true node", KPC(expr)); + } + } + + if (OB_SUCC(ret)) { + is_precise = ctx_.cur_is_precise_; + LOG_TRACE("succeed to convert one expr to range node", KPC(expr), KPC(range_node)); + } + return ret; +} + +//generate node start +int ObExprRangeConverter::alloc_range_node(ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + void *ptr = NULL; + void *key_ptr = NULL; + if (OB_UNLIKELY(allocator_.used() - mem_used_ > ctx_.max_mem_size_)) { + ret = OB_ERR_QUERY_RANGE_MEMORY_EXHAUSTED; + LOG_INFO("use too much memory when extract query range", K(ctx_.max_mem_size_)); + } else if (OB_ISNULL(ptr = allocator_.alloc(sizeof(ObRangeNode))) || + OB_ISNULL(key_ptr = allocator_.alloc(sizeof(int64_t) * ctx_.column_cnt_ * 2))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for range node"); + } else { + range_node = new(ptr) ObRangeNode(allocator_); + range_node->start_keys_ = static_cast(key_ptr); + range_node->end_keys_ = static_cast(key_ptr)+ ctx_.column_cnt_; + range_node->column_cnt_ = ctx_.column_cnt_; + MEMSET(key_ptr, 0, sizeof(int64_t) * ctx_.column_cnt_ * 2); + } + return ret; +} + +int ObExprRangeConverter::generate_always_true_or_false_node(bool is_true, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ctx_.cur_is_precise_ = false; + if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (is_true) { + range_node->always_true_ = true; + for (int64_t i = 0; i < ctx_.column_cnt_; ++i) { + range_node->start_keys_[i] = OB_RANGE_MIN_VALUE; + range_node->end_keys_[i] = OB_RANGE_MAX_VALUE; + } + } else { + range_node->always_false_ = true; + for (int64_t i = 0; i < ctx_.column_cnt_; ++i) { + range_node->start_keys_[i] = OB_RANGE_MAX_VALUE; + range_node->end_keys_[i] = OB_RANGE_MIN_VALUE; + } + } + return ret; +} + +int ObExprRangeConverter::convert_const_expr(const ObRawExpr *expr, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + int64_t start_val = 0; + int64_t end_val = 0; + bool is_valid = false; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(expr)); + } else if (OB_FAIL(check_calculable_expr_valid(expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true node"); + } + } else if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc const range node"); + } else if (OB_FAIL(generate_deduce_const_expr(const_cast(expr), start_val, end_val))) { + LOG_WARN("failed to generate expr for const expr", KPC(expr)); + } else { + range_node->always_false_ = false; + range_node->always_true_ = false; + for (int64_t i = 0; i < ctx_.column_cnt_; ++i) { + range_node->start_keys_[i] = start_val; + range_node->end_keys_[i] = end_val; + } + ctx_.cur_is_precise_ = true; + } + return ret; +} + +int ObExprRangeConverter::generate_deduce_const_expr(ObRawExpr *expr, + int64_t &start_val, + int64_t &end_val) { + int ret = OB_SUCCESS; + ObConstRawExpr *pos_expr = NULL; + ObSysFunRawExpr *start_expr = NULL; + ObSysFunRawExpr *end_expr = NULL; + int64_t is_start = 1; + if (OB_ISNULL(expr) || OB_ISNULL(ctx_.expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(expr), K(ctx_.expr_factory_)); + } else if (OB_FAIL(ctx_.expr_factory_->create_raw_expr(T_FUNC_SYS_INNER_IS_TRUE, start_expr))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_FAIL(ctx_.expr_factory_->create_raw_expr(T_FUNC_SYS_INNER_IS_TRUE, end_expr))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_ISNULL(start_expr) || OB_ISNULL(end_expr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate expr", K(start_expr), K(end_expr)); + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + 1, // const value + pos_expr))) { + LOG_WARN("Failed to build const expr", K(ret)); + } else if (OB_FAIL(start_expr->add_param_expr(expr))) { + LOG_WARN("failed to set param for is true", KPC(expr)); + } else if (OB_FAIL(start_expr->add_param_expr(pos_expr))) { + LOG_WARN("failed to set param for is true", KPC(pos_expr)); + } else if (OB_FAIL(start_expr->formalize(ctx_.session_info_))) { + LOG_WARN("failed to formalize expr"); + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + 0, // const value + pos_expr))) { + LOG_WARN("Failed to build const expr", K(ret)); + } else if (OB_FAIL(end_expr->add_param_expr(expr))) { + LOG_WARN("failed to set param for is true", KPC(expr)); + } else if (OB_FAIL(end_expr->add_param_expr(pos_expr))) { + LOG_WARN("failed to set param for is true", KPC(pos_expr)); + } else if (OB_FAIL(end_expr->formalize(ctx_.session_info_))) { + LOG_WARN("failed to formalize expr"); + } else if (OB_FAIL(get_final_expr_idx(start_expr, nullptr, start_val))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(get_final_expr_idx(end_expr, nullptr, end_val))) { + LOG_WARN("failed to get final expr idx"); + } + return ret; +} + + +int ObExprRangeConverter::convert_basic_cmp_expr(const ObRawExpr *expr, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + const ObRawExpr* l_expr = nullptr; + const ObRawExpr* r_expr = nullptr; + if (OB_ISNULL(expr) || + OB_ISNULL(l_expr = expr->get_param_expr(0)) || + OB_ISNULL(r_expr = expr->get_param_expr(1))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(expr), K(l_expr), K(r_expr)); + } else { + const ObOpRawExpr *op_expr = static_cast(expr); + // (c1, c2) = ((1, 1)) => (c1, c2) = (1, 1) + if (lib::is_oracle_mode() && T_OP_ROW == l_expr->get_expr_type() && + T_OP_ROW == r_expr->get_expr_type() && 1 == r_expr->get_param_count() && + OB_NOT_NULL(r_expr->get_param_expr(0)) && + T_OP_ROW == r_expr->get_param_expr(0)->get_expr_type()) { + r_expr = r_expr->get_param_expr(0); + } + if (OB_FAIL(get_basic_range_node(l_expr, r_expr, + expr->get_expr_type(), + expr->get_result_type(), + expr_depth, + range_node))) { + LOG_WARN("failed to get basic range node"); + } + } + return ret; +} + +int ObExprRangeConverter::get_basic_range_node(const ObRawExpr *l_expr, + const ObRawExpr *r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + range_node = NULL; + ctx_.cur_is_precise_ = false; + bool use_implicit_cast_feature = true; + if (OB_ISNULL(l_expr) || OB_ISNULL(r_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", KP(l_expr), KP(r_expr)); + } else if (OB_UNLIKELY((T_OP_ROW == l_expr->get_expr_type()) != (T_OP_ROW == r_expr->get_expr_type()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("both expr must be or not be row expr", KPC(l_expr), KPC(r_expr)); + } else if (!IS_BASIC_CMP_OP(cmp_type)) { + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true node"); + } + } else if (T_OP_ROW != l_expr->get_expr_type()) { + const ObRawExpr *l_ori_expr = l_expr; + const ObRawExpr *r_ori_expr = r_expr; + + if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(l_expr, + l_expr, + use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(r_expr, + r_expr, + use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if ((l_expr->has_flag(IS_COLUMN) && r_expr->is_const_expr()) || + (l_expr->is_const_expr() && r_expr->has_flag(IS_COLUMN))) { + if (OB_FAIL(gen_column_cmp_node(*l_expr, + *r_expr, + cmp_type, + result_type, + expr_depth, + T_OP_NSEQ == cmp_type, + range_node))) { + LOG_WARN("get column key part failed.", K(ret)); + } + } else if (((l_expr->get_expr_type() == T_FUN_SYS_NVL && r_expr->is_const_expr()) || + (l_expr->is_const_expr() && r_expr->get_expr_type() == T_FUN_SYS_NVL))) { + if (OB_FAIL(get_nvl_cmp_node(*l_expr, + *r_expr, + cmp_type, + result_type, + expr_depth, + range_node))) { + LOG_WARN("failed to get nvl cmp node", K(ret)); + } + } else if ((l_expr->has_flag(IS_ROWID) && r_expr->is_const_expr()) || + (r_expr->has_flag(IS_ROWID) && l_expr->is_const_expr())) { + if (OB_FAIL(get_rowid_node(*l_expr, *r_expr, cmp_type, range_node))) { + LOG_WARN("get rowid key part failed.", K(ret)); + } + } else if (ObSQLUtils::is_min_cluster_version_ge_425_or_435() && + ObSQLUtils::is_opt_feature_version_ge_425_or_435(ctx_.optimizer_features_enable_version_) && + ((l_ori_expr->get_expr_type() == T_FUN_SYS_CAST && r_ori_expr->is_const_expr()) || + (r_ori_expr->get_expr_type() == T_FUN_SYS_CAST && l_ori_expr->is_const_expr()))) { + if (OB_FAIL(get_implicit_cast_range(*l_ori_expr, + *r_ori_expr, + cmp_type, + result_type, + expr_depth, + range_node))) { + LOG_WARN("failed to get implicit cast range", K(ret)); + } + } else { + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true node"); + } + } + } else if (OB_FAIL(get_row_cmp_node(*l_expr, *r_expr, cmp_type, + result_type, expr_depth, range_node))) { + LOG_WARN("get row key part failed.", K(ret)); + } + + return ret; +} + +int ObExprRangeConverter::gen_column_cmp_node(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + bool null_safe, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + range_node = NULL; + ctx_.cur_is_precise_ = true; + const ObColumnRefRawExpr *column_expr = NULL; + const ObRawExpr *const_expr = NULL; + const ObExprCalcType &calc_type = result_type.get_calc_meta(); + ObRangeColumnMeta *column_meta = nullptr; + int64_t key_idx; + int64_t const_val; + bool is_valid = false; + if (OB_LIKELY(l_expr.has_flag(IS_COLUMN))) { + column_expr = static_cast(&l_expr); + const_expr = &r_expr; + } else { + column_expr = static_cast(&r_expr); + const_expr = &l_expr; + cmp_type = get_opposite_compare_type(cmp_type); + } + + bool always_true = true; + if (!is_range_key(column_expr->get_column_id(), key_idx) || + OB_UNLIKELY(!const_expr->is_const_expr())) { + always_true = true; + } else if (OB_ISNULL(column_meta = get_column_meta(key_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (!ObQueryRange::can_be_extract_range(cmp_type, column_meta->column_type_, + calc_type, const_expr->get_result_type().get_type(), + always_true)) { + // do nothing + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(get_final_expr_idx(const_expr, column_meta, const_val))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else { + if (is_oracle_mode() && cmp_type == T_OP_GT && + ((column_meta->column_type_.get_type() == ObCharType && const_expr->get_result_type().get_type() == ObVarcharType) || + (column_meta->column_type_.get_type() == ObNCharType && const_expr->get_result_type().get_type() == ObNVarchar2Type))) { + /* when char compare with varchar, same string may need return due to padding blank. + e.g. c1(char(3)) > '1'(varchar(1)) will return '1 ' */ + cmp_type = T_OP_GE; + } + if (null_safe && OB_FAIL(ctx_.null_safe_value_idxs_.push_back(const_val))) { + LOG_WARN("failed to push back null safe value index", K(const_val)); + //if current expr can be extracted to range, just store the expr + } else if (OB_FAIL(fill_range_node_for_basic_cmp(cmp_type, key_idx, const_val, *range_node))) { + LOG_WARN("get normal cmp keypart failed", K(ret)); + } else if (OB_FAIL(check_expr_precise(*const_expr, calc_type, column_meta->column_type_))) { + LOG_WARN("failed to check expr precise", K(ret)); + } else if (expr_depth == 0 && OB_FAIL(set_column_flags(key_idx, cmp_type))) { + LOG_WARN("failed to set column flags", K(ret)); + } + } + if (OB_SUCC(ret) && nullptr == range_node) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(always_true, range_node))) { + LOG_WARN("failed to generate always true or fasle node", K(always_true)); + } + } + return ret; +} + +int ObExprRangeConverter::gen_row_column_cmp_node(const ObIArray &l_column_exprs, + const ObIArray &r_const_exprs, + ObItemType cmp_type, + const ObIArray &calc_types, + int64_t expr_depth, + int64_t row_dim, + bool null_safe, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ObSEArray key_idxs; + ObSEArray val_idxs; + bool always_true = true; + ctx_.cur_is_precise_ = true; + if (OB_UNLIKELY(l_column_exprs.count() != r_const_exprs.count()) || + OB_UNLIKELY(l_column_exprs.count() != calc_types.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected param count", K(l_column_exprs), K(r_const_exprs), K(calc_types)); + } else if (T_OP_EQ == cmp_type || T_OP_NSEQ == cmp_type) { + ObSEArray ordered_key_idxs; + ObSEArray const_exprs; + ObSEArray column_metas; + int64_t min_offset = ctx_.column_cnt_; + for (int64_t i = 0; OB_SUCC(ret) && i < l_column_exprs.count(); ++i) { + const ObExprCalcType *calc_type = calc_types.at(i); + const ObColumnRefRawExpr* column_expr = l_column_exprs.at(i); + const ObRawExpr* const_expr = r_const_exprs.at(i); + bool cur_always_true = true; + bool is_valid = false; + if (OB_NOT_NULL(column_expr) && OB_NOT_NULL(const_expr) && OB_NOT_NULL(calc_type)) { + int64_t key_idx = -1; + ObRangeColumnMeta *column_meta = nullptr; + if (!is_range_key(column_expr->get_column_id(), key_idx)) { + // do nothing + } else if (ObOptimizerUtil::find_item(key_idxs, key_idx)) { + // this key already exist. e.g. (c1,c1,c2) = (:1,:2,:3) will be trated as (c1,c2) = (:1,:3) + } else if (OB_ISNULL(column_meta = get_column_meta(key_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (!ObQueryRange::can_be_extract_range(cmp_type, column_meta->column_type_, + *calc_type, const_expr->get_result_type().get_type(), + cur_always_true)) { + if (!cur_always_true) { + always_true = false; + } + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(check_expr_precise(*const_expr, *calc_type, column_meta->column_type_))) { + LOG_WARN("failed to check expr precise", K(ret)); + } else if (OB_FAIL(key_idxs.push_back(key_idx))) { + LOG_WARN("failed to push back key idx", K(key_idx)); + } else if (OB_FAIL(const_exprs.push_back(const_expr))) { + LOG_WARN("failed to push back const expr", KPC(const_expr)); + } else if (OB_FAIL(column_metas.push_back(column_meta))) { + LOG_WARN("failed to push back column metas", K(ret)); + } else if (key_idx < min_offset) { + min_offset = key_idx; + } + } + } + for (int64_t i = min_offset; OB_SUCC(ret) && i < ctx_.column_cnt_; ++i) { + int64_t idx = -1; + if (ObOptimizerUtil::find_item(key_idxs, i, &idx)) { + int64_t const_val = -1; + const ObRawExpr* const_expr = const_exprs.at(idx); + const ObRangeColumnMeta *meta = column_metas.at(idx); + if (OB_FAIL(get_final_expr_idx(const_expr, meta, const_val))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(ordered_key_idxs.push_back(i))) { + LOG_WARN("failed to push back key idx", K(key_idxs)); + } else if (OB_FAIL(val_idxs.push_back(const_val))) { + LOG_WARN("failed to push back key idx", K(const_val)); + } else if (null_safe && OB_FAIL(ctx_.null_safe_value_idxs_.push_back(const_val))) { + LOG_WARN("failed to push back null safe value index", K(const_val)); + } else if (expr_depth == 0 && OB_FAIL(set_column_flags(idx, cmp_type))){ + LOG_WARN("failed to set column flags", K(ret)); + } + } else { + // only extract consistent column for row compare + break; + } + } + if (OB_SUCC(ret)) { + if (ordered_key_idxs.count() < row_dim) { + // part of row can't extract range. + ctx_.cur_is_precise_ = false; + } + if (!key_idxs.empty()) { + if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(fill_range_node_for_basic_row_cmp(cmp_type, ordered_key_idxs, val_idxs, *range_node))) { + LOG_WARN("failed to fill range node for basic row cmp"); + } + } + } + } else { + int64_t last_key_idx = -1; + bool check_next = true; + bool is_valid_decimal_int_range_cmp = true; + for (int64_t i = 0; OB_SUCC(ret) && check_next && i < l_column_exprs.count(); ++i) { + const ObExprCalcType *calc_type = calc_types.at(i); + const ObColumnRefRawExpr* column_expr = l_column_exprs.at(i); + const ObRawExpr* const_expr = r_const_exprs.at(i); + bool cur_always_true = true; + bool is_valid = false; + check_next = false; + if (OB_NOT_NULL(column_expr) && OB_NOT_NULL(const_expr) && OB_NOT_NULL(calc_type)) { + int64_t key_idx = -1; + int64_t const_val = -1; + ObRangeColumnMeta *column_meta = nullptr; + if (!is_range_key(column_expr->get_column_id(), key_idx)) { + // do nothing + } else if (last_key_idx != -1 && key_idx != last_key_idx + 1) { + // do nothing + } else if (OB_ISNULL(column_meta = get_column_meta(key_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (const_expr->get_expr_type() == T_FUN_SYS_INNER_ROW_CMP_VALUE && + OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(const_expr, const_expr, true))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (!ObQueryRange::can_be_extract_range(cmp_type, column_meta->column_type_, + *calc_type, const_expr->get_result_type().get_type(), + cur_always_true)) { + if (i == 0 && !cur_always_true) { + always_true = false; + } + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(check_expr_precise(*const_expr, *calc_type, column_meta->column_type_))) { + LOG_WARN("failed to check expr precise", K(ret)); + } else if (OB_FAIL(get_final_expr_idx(const_expr, column_meta, const_val))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(key_idxs.push_back(key_idx))) { + LOG_WARN("failed to push back key idx", K(key_idx)); + } else if (OB_FAIL(val_idxs.push_back(const_val))) { + LOG_WARN("failed to push back key idx", K(const_val)); + } else if (is_oracle_mode() && (cmp_type == T_OP_GT || cmp_type == T_OP_GE) && + ((column_meta->column_type_.get_type() == ObCharType && const_expr->get_result_type().get_type() == ObVarcharType) || + (column_meta->column_type_.get_type() == ObNCharType && const_expr->get_result_type().get_type() == ObNVarchar2Type))) { + /* when char compare with varchar, same string may need return due to padding blank. + e.g. c1(char(3)) > '1'(varchar(1)) will return '1 ' */ + // can not extract query range for next row item + cmp_type = T_OP_GE; + // The logic for c1 <=> null is reused from the original logic and will be converted to c1 >= null and c1 <= null, and it needs to be set to null safe. + } else if (null_safe && OB_FAIL(ctx_.null_safe_value_idxs_.push_back(const_val))) { + LOG_WARN("failed to push back null safe value index", K(const_val)); + } else if (expr_depth == 0 && OB_FAIL(set_column_flags(key_idx, cmp_type))) { + LOG_WARN("failed to set column flags", K(ret)); + } else if (i > 0 && OB_FAIL(ctx_.non_first_in_row_value_idxs_.push_back(const_val))) { + LOG_WARN("failed to push back value idx", K(const_val)); + } else if (i < l_column_exprs.count() - 1 && + OB_NOT_NULL(r_const_exprs.at(i+1)) && + OB_FAIL(check_decimal_int_range_cmp_valid(r_const_exprs.at(i+1), is_valid_decimal_int_range_cmp))) { + LOG_WARN("fail to check can use ori cmp type", K(ret)); + } else { + bool is_lt_with_lob = (cmp_type == T_OP_LT || cmp_type == T_OP_LE) && + (ctx_.final_exprs_flag_.at(const_val) + & OB_FINAL_EXPR_WITH_LOB_TRUNCATE) + == OB_FINAL_EXPR_WITH_LOB_TRUNCATE; + last_key_idx = key_idx; + check_next = !is_lt_with_lob && is_valid_decimal_int_range_cmp; + } + } + } + if (OB_SUCC(ret)) { + if (key_idxs.count() < row_dim) { + ctx_.cur_is_precise_ = false; + if (!is_valid_decimal_int_range_cmp) { + // after single side cast, decimal int already handle range border + } else if (T_OP_LT == cmp_type) { + cmp_type = T_OP_LE; + } else if (T_OP_GT == cmp_type) { + cmp_type = T_OP_GE; + } + } else { + if (T_OP_LE == cmp_type || T_OP_LT == cmp_type) { + ctx_.cur_is_precise_ = lib::is_oracle_mode() ? true : false; + } else { + ctx_.cur_is_precise_ = lib::is_oracle_mode() ? false : true; + } + } + if (!key_idxs.empty()) { + if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(fill_range_node_for_basic_row_cmp(cmp_type, key_idxs, val_idxs, *range_node))) { + LOG_WARN("failed to fill range node for basic row cmp"); + } + } + } + } + if (OB_SUCC(ret) && OB_UNLIKELY(nullptr == range_node)) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(always_true, range_node))) { + LOG_WARN("failed to generate always true or fasle node", K(always_true)); + } + } + return ret; +} + +/** + * convert `c1 is null` to range node +*/ +int ObExprRangeConverter::convert_is_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + const ObRawExpr* l_expr = nullptr; + const ObRawExpr* r_expr = nullptr; + ctx_.cur_is_precise_ = false; + if (OB_ISNULL(expr) || + OB_ISNULL(l_expr = expr->get_param_expr(0)) || + OB_ISNULL(r_expr = expr->get_param_expr(1))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(expr), K(l_expr), K(r_expr)); + } else if (ObNullType == r_expr->get_result_type().get_type()) { + if (OB_FAIL(gen_is_null_range_node(l_expr, expr_depth, range_node))) { + LOG_WARN("failed to gen is null expr", K(ret)); + } + } + if (OB_SUCC(ret) && nullptr == range_node) { + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node"); + } + } + return ret; +} + +int ObExprRangeConverter::gen_is_null_range_node(const ObRawExpr *l_expr, int64_t expr_depth, ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + int64_t key_idx = -1; + range_node = nullptr; + ctx_.cur_is_precise_ = false; + bool use_implicit_cast_feature = true; + if (OB_ISNULL(l_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(l_expr, l_expr, use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (!l_expr->has_flag(IS_COLUMN)) { + // do nothing + } else if (!is_range_key(static_cast(l_expr)->get_column_id(), key_idx)) { + // do nothing + } else if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(fill_range_node_for_basic_cmp(T_OP_NSEQ, key_idx, OB_RANGE_NULL_VALUE, *range_node))) { + LOG_WARN("get normal cmp keypart failed", K(ret)); + } else if (expr_depth == 0 && OB_FAIL(set_column_flags(key_idx, T_OP_IS))) { + LOG_WARN("failed to set column flags", K(ret)); + } else { + ctx_.cur_is_precise_ = true; + } + + if (OB_SUCC(ret) && nullptr == range_node) { + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node"); + } + } + return ret; +} + +/** + * convert `c1 between :0 and :1` to range node +*/ +int ObExprRangeConverter::convert_between_expr(const ObRawExpr *expr, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ObSEArray range_nodes; + const ObRawExpr *expr1 = nullptr; + const ObRawExpr *expr2 = nullptr; + const ObRawExpr *expr3 = nullptr; + ObRangeNode *tmp_node = nullptr; + bool first_is_precise = true; + ctx_.cur_is_precise_ = false; + if (OB_ISNULL(expr) || OB_UNLIKELY(expr->get_param_count() != 3) || + OB_ISNULL(expr1 = expr->get_param_expr(0)) || + OB_ISNULL(expr2 = expr->get_param_expr(1)) || + OB_ISNULL(expr3 = expr->get_param_expr(2))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected expr", KPC(expr), KPC(expr1), KPC(expr2), KPC(expr3)); + } else if (OB_FAIL(get_basic_range_node(expr1, expr2, T_OP_GE, expr->get_result_type(), expr_depth, tmp_node))) { + LOG_WARN("failed tp get basic range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FALSE_IT(first_is_precise = ctx_.cur_is_precise_)) { + } else if (OB_FAIL(get_basic_range_node(expr1, expr3, T_OP_LE, expr->get_result_type(), expr_depth, tmp_node))) { + LOG_WARN("failed tp get basic range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FAIL(ObRangeGraphGenerator::and_range_nodes(range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to and range nodes"); + } else { + ctx_.cur_is_precise_ = first_is_precise && ctx_.cur_is_precise_; + if (ctx_.cur_is_precise_) { + ctx_.refresh_max_offset_ = true; + } + } + return ret; +} + +int ObExprRangeConverter::convert_not_between_expr(const ObRawExpr *expr, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ObSEArray range_nodes; + const ObRawExpr *expr1 = nullptr; + const ObRawExpr *expr2 = nullptr; + const ObRawExpr *expr3 = nullptr; + ObRangeNode *tmp_node = nullptr; + bool first_is_precise = true; + ctx_.cur_is_precise_ = false; + if (OB_ISNULL(expr) || OB_UNLIKELY(expr->get_param_count() != 3) || + OB_ISNULL(expr1 = expr->get_param_expr(0)) || + OB_ISNULL(expr2 = expr->get_param_expr(1)) || + OB_ISNULL(expr3 = expr->get_param_expr(2))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected expr", KPC(expr), KPC(expr1), KPC(expr2), KPC(expr3)); + } else if (OB_FAIL(get_basic_range_node(expr1, expr2, T_OP_LT, expr->get_result_type(), expr_depth + 1, tmp_node))) { + LOG_WARN("failed tp get basic range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FALSE_IT(first_is_precise = ctx_.cur_is_precise_)) { + } else if (OB_FAIL(get_basic_range_node(expr1, expr3, T_OP_GT, expr->get_result_type(), expr_depth + 1, tmp_node))) { + LOG_WARN("failed tp get basic range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FAIL(ObRangeGraphGenerator::or_range_nodes(*this, range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to or range nodes"); + } else { + ctx_.cur_is_precise_ = first_is_precise && ctx_.cur_is_precise_; + if (ctx_.cur_is_precise_) { + ctx_.refresh_max_offset_ = true; + } + } + return ret; +} + +int ObExprRangeConverter::convert_not_equal_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ObSEArray range_nodes; + const ObRawExpr *l_expr = nullptr; + const ObRawExpr *r_expr = nullptr; + ObRangeNode *tmp_node = nullptr; + bool first_is_precise = true; + ctx_.cur_is_precise_ = false; + if (OB_ISNULL(expr) || OB_UNLIKELY(expr->get_param_count() != 2) || + OB_ISNULL(l_expr = expr->get_param_expr(0)) || + OB_ISNULL(r_expr = expr->get_param_expr(1))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected expr", KPC(expr), KPC(l_expr), KPC(r_expr)); + } else if (T_OP_ROW == l_expr->get_expr_type()) { + // do not convert row not equal expr + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node"); + } + } else if (OB_FAIL(get_basic_range_node(l_expr, r_expr, T_OP_LT, expr->get_result_type(), expr_depth, tmp_node))) { + LOG_WARN("failed tp get basic range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FALSE_IT(first_is_precise = ctx_.cur_is_precise_)) { + } else if (OB_FAIL(get_basic_range_node(l_expr, r_expr, T_OP_GT, expr->get_result_type(), expr_depth, tmp_node))) { + LOG_WARN("failed tp get basic range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FAIL(ObRangeGraphGenerator::or_range_nodes(*this, range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to or range nodes"); + } else { + ctx_.cur_is_precise_ = first_is_precise && ctx_.cur_is_precise_; + } + return ret; +} + +int ObExprRangeConverter::convert_like_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + const ObRawExpr *l_expr = nullptr; + const ObRawExpr *pattern_expr = nullptr; + const ObRawExpr *escape_expr = nullptr; + ObRangeNode *tmp_node = nullptr; + bool always_true = true; + ctx_.cur_is_precise_ = false; + bool use_implicit_cast_feature = true; + if (OB_ISNULL(expr) || OB_UNLIKELY(expr->get_param_count() != 3) || + OB_ISNULL(l_expr = expr->get_param_expr(0)) || + OB_ISNULL(pattern_expr = expr->get_param_expr(1)) || + OB_ISNULL(escape_expr = expr->get_param_expr(2))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected expr", KPC(expr), KPC(l_expr), KPC(pattern_expr), KPC(escape_expr)); + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(l_expr, l_expr, use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (l_expr->has_flag(IS_COLUMN) && + pattern_expr->is_const_expr() && + escape_expr->is_const_expr() && + !escape_expr->has_flag(CNT_DYNAMIC_PARAM)) { + const ObColumnRefRawExpr *column_expr = static_cast(l_expr); + const ObExprCalcType &calc_type = expr->get_result_type().get_calc_meta(); + int64_t key_idx = -1; + int64_t start_val_idx = -1; + int64_t end_val_idx = -1; + char escape_ch = 0x00; + bool is_valid = false; + ObRangeColumnMeta *column_meta = nullptr; + if (!is_range_key(column_expr->get_column_id(), key_idx)) { + // do nothing + } else if (OB_ISNULL(column_meta = get_column_meta(key_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (!ObQueryRange::can_be_extract_range(T_OP_LIKE, column_meta->column_type_, + calc_type, pattern_expr->get_result_type().get_type(), + always_true)) { + // do nothing + } else if (OB_FAIL(check_calculable_expr_valid(pattern_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(check_escape_valid(escape_expr, escape_ch, is_valid))) { + LOG_WARN("failed to check escape is valid", KPC(escape_expr)); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(build_decode_like_expr(const_cast(pattern_expr), + const_cast(escape_expr), + escape_ch, column_meta, start_val_idx, end_val_idx))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(fill_range_node_for_like(key_idx, start_val_idx, end_val_idx, *range_node))) { + LOG_WARN("get normal cmp keypart failed", K(ret)); + } else if (OB_FAIL(check_expr_precise(*pattern_expr, calc_type, column_meta->column_type_))) { + LOG_WARN("failed to check expr precise", K(ret)); + } else if (expr_depth == 0 && OB_FAIL(set_column_flags(key_idx, T_OP_LIKE))) { + LOG_WARN("failed to set column flags", K(ret)); + } else if (is_oracle_mode()) { + // NChar like Nchar, Char like Char is not precise due to padding blank characters + ObObjType column_type = column_meta->column_type_.get_type(); + ObObjType const_type = pattern_expr->get_result_type().get_type(); + if ((ObCharType == column_type && ObCharType == const_type) || + (ObNCharType == column_type && ObNCharType == const_type)) { + ctx_.cur_is_precise_ = false; + } + } + } + if (OB_SUCC(ret) && nullptr == range_node) { + if (OB_FAIL(generate_always_true_or_false_node(always_true, range_node))) { + LOG_WARN("failed to generate always true or fasle node"); + } + } + return ret; +} + +int ObExprRangeConverter::check_escape_valid(const ObRawExpr *escape, char &escape_ch, bool &is_valid) +{ + int ret = OB_SUCCESS; + ObObj escape_val; + is_valid = false; + escape_ch = 0x00; + if (OB_FAIL(get_calculable_expr_val(escape, escape_val, is_valid))) { + LOG_WARN("failed to get calculable expr val", KPC(escape)); + } else if (!is_valid) { + // do nothing + } else if (escape_val.is_null()) { + escape_ch = '\\'; + } else if (ObCharset::is_cs_nonascii(escape_val.get_collation_type())) { + ObString escape_str; + ObString escape_dst; + if (OB_FAIL(escape_val.get_string(escape_str))) { + LOG_WARN("failed to get escape string", K(escape), K(ret)); + } else if (OB_FAIL(ObCharset::charset_convert(allocator_, escape_str, escape_val.get_collation_type(), + CS_TYPE_UTF8MB4_GENERAL_CI, escape_dst, true))) { + LOG_WARN("failed to do charset convert", K(ret), K(escape_str)); + } else if (escape_dst.length() > 1) { + is_valid = false; + } else { + escape_ch = (escape_dst.length() == 0) ? 0x00 : *(escape_dst.ptr()); + } + } else if (escape_val.get_string_len() > 1) { + is_valid = false; + } else { + escape_ch = (escape_val.get_string_len() == 0) ? 0x00 : *(escape_val.get_string_ptr()); + } + return ret; +} + +int ObExprRangeConverter::build_decode_like_expr(ObRawExpr *pattern, + ObRawExpr *escape, + char escape_ch, + ObRangeColumnMeta *column_meta, + int64_t &start_val_idx, + int64_t &end_val_idx) +{ + int ret = OB_SUCCESS; + ObRawExpr *decode_like_expr = nullptr; + ObConstRawExpr *pos_expr = NULL; + ObConstRawExpr *column_type_expr = NULL; + ObConstRawExpr *collation_type_expr = NULL; + ObConstRawExpr *column_length_expr = NULL; + ObSysFunRawExpr *start_expr = NULL; + ObSysFunRawExpr *end_expr = NULL; + if (OB_ISNULL(pattern) || OB_ISNULL(escape) || OB_ISNULL(column_meta) || OB_ISNULL(ctx_.expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(pattern), K(escape), K(column_meta), K(ctx_.expr_factory_)); + } else if (OB_FAIL(ctx_.expr_factory_->create_raw_expr(T_FUN_SYS_INNER_DECODE_LIKE, start_expr))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_FAIL(ctx_.expr_factory_->create_raw_expr(T_FUN_SYS_INNER_DECODE_LIKE, end_expr))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_ISNULL(start_expr) || OB_ISNULL(end_expr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate expr", K(start_expr), K(end_expr)); + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + static_cast(column_meta->column_type_.get_type()), + column_type_expr))) { + LOG_WARN("Failed to build const expr", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + static_cast(column_meta->column_type_.get_collation_type()), + collation_type_expr))) { + LOG_WARN("Failed to build const expr", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + column_meta->column_type_.get_accuracy().get_length(), + column_length_expr))) { + LOG_WARN("Failed to build const expr", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + 1, // const value + pos_expr))) { + LOG_WARN("Failed to build const expr", K(ret)); + } else if (OB_FAIL(start_expr->add_param_expr(pattern)) || + OB_FAIL(start_expr->add_param_expr(escape)) || + OB_FAIL(start_expr->add_param_expr(pos_expr)) || + OB_FAIL(start_expr->add_param_expr(column_type_expr)) || + OB_FAIL(start_expr->add_param_expr(collation_type_expr)) || + OB_FAIL(start_expr->add_param_expr(column_length_expr))) { + LOG_WARN("failed to set params for decode like expr", KPC(start_expr)); + } else if (OB_FAIL(start_expr->formalize(ctx_.session_info_))) { + LOG_WARN("failed to formalize expr"); + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + 0, // const value + pos_expr))) { + LOG_WARN("Failed to build const expr", K(ret)); + } else if (OB_FAIL(end_expr->add_param_expr(pattern)) || + OB_FAIL(end_expr->add_param_expr(escape)) || + OB_FAIL(end_expr->add_param_expr(pos_expr)) || + OB_FAIL(end_expr->add_param_expr(column_type_expr)) || + OB_FAIL(end_expr->add_param_expr(collation_type_expr)) || + OB_FAIL(end_expr->add_param_expr(column_length_expr))) { + LOG_WARN("failed to set params for decode like expr", KPC(start_expr)); + } else if (OB_FAIL(end_expr->formalize(ctx_.session_info_))) { + LOG_WARN("failed to formalize expr"); + } else if (OB_FAIL(get_final_expr_idx(start_expr, nullptr, start_val_idx))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(get_final_expr_idx(end_expr, nullptr, end_val_idx))) { + LOG_WARN("failed to get final expr idx"); + } + + //generate constraint if like range is precise + if (OB_SUCC(ret) && ctx_.params_ != nullptr && + !pattern->has_flag(CNT_DYNAMIC_PARAM)) { + ObObj pattern_val; + bool is_valid = false; + if (OB_FAIL(get_calculable_expr_val(pattern, pattern_val, is_valid))) { + LOG_WARN("failed to get calculable expr val", KPC(pattern)); + } else if (!is_valid) { + ctx_.cur_is_precise_ = false; + } else if(pattern_val.is_null()) { + ctx_.cur_is_precise_ = false; + } else if(OB_FAIL(ObQueryRange::is_precise_like_range(pattern_val, + escape_ch, + ctx_.cur_is_precise_))) { + LOG_WARN("failed to jugde whether is precise", K(ret)); + } else if (OB_FAIL(add_precise_constraint(pattern, ctx_.cur_is_precise_))) { + LOG_WARN("failed to add precise constraint", K(ret)); + } else if (OB_FAIL(add_prefix_pattern_constraint(pattern))) { + LOG_WARN("failed to add prefix pattern constraint", K(ret)); + } + } + return ret; +} + + +/** + * convert `c1 in (xxx)` or `(c1,c2) in (xxx)` to range node +*/ +int ObExprRangeConverter::convert_in_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + const ObRawExpr* l_expr = nullptr; + const ObRawExpr* r_expr = nullptr; + ctx_.cur_is_precise_ = true; + bool use_implicit_cast_feature = true; + if (OB_ISNULL(expr) || + OB_ISNULL(l_expr = expr->get_param_expr(0)) || + OB_ISNULL(r_expr = expr->get_param_expr(1))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(expr), K(l_expr), K(r_expr)); + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(l_expr, l_expr, use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (l_expr->get_expr_type() == T_OP_ROW) { + if (OB_FAIL(get_row_in_range_ndoe(*l_expr, *r_expr, expr->get_result_type(), expr_depth, range_node))) { + LOG_WARN("failed to get row in range node"); + } + } else if (l_expr->is_column_ref_expr()) { + if (OB_FAIL(get_single_in_range_node(static_cast(l_expr), + r_expr, expr->get_result_type(), expr_depth, range_node))) { + LOG_WARN("failed to get single in range node"); + } + } else if (l_expr->has_flag(IS_ROWID)) { + if (OB_FAIL(get_single_rowid_in_range_node(*l_expr, *r_expr, range_node))) { + LOG_WARN("failed to get single row in range node", K(ret)); + } + } + + if (OB_SUCC(ret) && nullptr == range_node) { + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node"); + } + } + return ret; +} + +int ObExprRangeConverter::get_single_in_range_node(const ObColumnRefRawExpr *column_expr, + const ObRawExpr *r_expr, + const ObExprResType &res_type, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + bool always_true = false; + ObRangeColumnMeta *column_meta = nullptr; + int64_t key_idx = -1; + ObSEArray val_idxs; + if (OB_ISNULL(column_expr) || OB_ISNULL(r_expr) || + OB_UNLIKELY(r_expr->get_param_count() == 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected param", KPC(column_expr), KPC(r_expr)); + } else if (!is_range_key(column_expr->get_column_id(), key_idx)) { + always_true = true; + } else if ((ctx_.column_flags_[key_idx] & (RANGE_EXPR_EQUAL | RANGE_EXPR_IN)) != 0) { + always_true = true; + } else if (OB_ISNULL(column_meta = get_column_meta(key_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else { + for (int64_t i = 0; OB_SUCC(ret) && !always_true && i < r_expr->get_param_count(); ++i) { + const ObRawExpr *const_expr = r_expr->get_param_expr(i); + bool cur_can_be_extract = true; + bool cur_always_true = true; + bool is_valid = true; + int64_t val_idx = -1; + if (OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (OB_UNLIKELY(!const_expr->is_const_expr())) { + cur_can_be_extract = false; + cur_always_true = true; + } else if (!ObQueryRange::can_be_extract_range(T_OP_EQ, column_meta->column_type_, + res_type.get_row_calc_cmp_types().at(i), + const_expr->get_result_type().get_type(), + cur_always_true)) { + cur_can_be_extract = false; + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + cur_can_be_extract = false; + cur_always_true = true; + } else if (OB_FAIL(get_final_expr_idx(const_expr, column_meta, val_idx))) { + LOG_WARN("failed to get final expr idx", K(ret)); + } else if (OB_FAIL(check_expr_precise(*const_expr, res_type.get_row_calc_cmp_types().at(i), + column_meta->column_type_))) { + LOG_WARN("failed to check expr precise", K(ret)); + } else if (OB_FAIL(val_idxs.push_back(val_idx))) { + LOG_WARN("failed to push back val idx", K(val_idx)); + } + + if (OB_SUCC(ret) && !cur_can_be_extract && cur_always_true) { + // for always false, just no need to add the value to in param + always_true = true; + } + } + } + + if (OB_SUCC(ret) && !always_true) { + InParam *in_param = nullptr; + int64_t param_idx; + if (val_idxs.empty()) { + // c1 in (null, null, null) + if (OB_FAIL(generate_always_true_or_false_node(false, range_node))) { + LOG_WARN("failed to generate always fasle node"); + } + } else if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(get_final_in_array_idx(in_param, param_idx))) { + LOG_WARN("failed to get final in array idx"); + } else if (OB_FAIL(in_param->assign(val_idxs))) { + LOG_WARN("failed to assign in params"); + } else if (OB_FAIL(fill_range_node_for_basic_cmp(T_OP_EQ, key_idx, param_idx, *range_node))) { + LOG_WARN("failed to fill range node for basic cmp"); + } else if (expr_depth == 0 && set_column_flags(key_idx, T_OP_IN)) { + LOG_WARN("failed to set column flags", K(ret)); + } else { + range_node->contain_in_ = true; + range_node->in_param_count_ = val_idxs.count(); + } + } + return ret; +} + +int ObExprRangeConverter::get_row_in_range_ndoe(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + const ObExprResType &res_type, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ObSEArray key_idxs; + ObSEArray val_idxs; + ObSEArray key_offsets; + ObSEArray column_metas; + ObSEArray tmp_key_idxs; + ObSEArray tmp_key_offsets; + ObSEArray tmp_column_metas; + int64_t min_offset = ctx_.column_cnt_; + bool always_true_or_false = true; + bool use_implicit_cast_feature = true; + // 1. get all valid key and offset + for (int64_t i = 0; OB_SUCC(ret) && i < l_expr.get_param_count(); ++i) { + const ObRawExpr* l_param = l_expr.get_param_expr(i); + const ObColumnRefRawExpr* column_expr = nullptr; + ObRangeColumnMeta *column_meta = nullptr; + if (OB_ISNULL(l_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(l_param)); + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(l_param, l_param, use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (l_param->is_column_ref_expr()) { + column_expr = static_cast(l_param); + int64_t key_idx = -1; + if (!is_range_key(column_expr->get_column_id(), key_idx)) { + // do nothing + } else if (ObOptimizerUtil::find_item(key_idxs, key_idx)) { + // this key already exist. e.g. (c1,c1,c2) in ((:1,:2,:3), (:4,:5,:6)) + // will be trated as (c1,c2) in ((:1,:3), (:4,:6)) + } else if (OB_ISNULL(column_meta = get_column_meta(key_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (OB_FAIL(tmp_key_idxs.push_back(key_idx))) { + LOG_WARN("failed to push back key idx", K(key_idx)); + } else if (OB_FAIL(tmp_key_offsets.push_back(i))) { + LOG_WARN("failed to add member to bitmap", K(i)); + } else if (OB_FAIL(tmp_column_metas.push_back(column_meta))) { + LOG_WARN("failed to push back column meta"); + } else if (key_idx < min_offset) { + min_offset = key_idx; + } + } + } + + // 2. get consistent column idx + if (OB_SUCC(ret) && tmp_key_idxs.count() > 0) { + bool need_extract = false; + for (int64_t i = min_offset; OB_SUCC(ret) && i < ctx_.column_cnt_; ++i) { + int64_t idx = -1; + if (ObOptimizerUtil::find_item(tmp_key_idxs, i, &idx)) { + if (OB_FAIL(key_idxs.push_back(i))) { + LOG_WARN("failed to push back key idx", K(tmp_key_idxs)); + } else if (OB_FAIL(key_offsets.push_back(tmp_key_offsets.at(idx)))) { + LOG_WARN("failed to push back key idx", K(tmp_key_offsets), K(idx)); + } else if (OB_FAIL(column_metas.push_back(tmp_column_metas.at(idx)))) { + LOG_WARN("failed to push back key idx", K(tmp_column_metas), K(idx)); + } + } else { + // only extract consistent column for row compare + break; + } + } + for (int64_t i = 0; OB_SUCC(ret) && !need_extract && i < key_idxs.count(); ++i) { + int64_t idx = key_idxs.at(i); + if ((ctx_.column_flags_[idx] & (RANGE_EXPR_EQUAL | RANGE_EXPR_IN)) == 0) { + need_extract = true; + } + } + if (OB_SUCC(ret) && !need_extract) { + key_idxs.reuse(); + } + } + + // 3. get all valid in param + if (OB_SUCC(ret) && key_idxs.count() > 0) { + ObArenaAllocator alloc("ExprRangeAlloc", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObSEArray cur_val_exprs; + ObSEArray all_val_exprs; + const int64_t row_dimension = l_expr.get_param_count(); + int64_t in_param_count = 0; + for (int64_t i = 0; OB_SUCC(ret) && i < key_idxs.count(); ++i) { + void *ptr = alloc.alloc(sizeof(TmpExprArray)); + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for se array"); + } else { + TmpExprArray *val_exprs = new(ptr)TmpExprArray(); + val_exprs->set_attr(ObMemAttr(MTL_ID(), "ExprRangeCvt")); + ret = all_val_exprs.push_back(val_exprs); + } + } + + for (int64_t i = 0; OB_SUCC(ret) && !key_offsets.empty() && i < r_expr.get_param_count(); ++i) { + const ObRawExpr *row_expr = r_expr.get_param_expr(i); + const ObRawExpr *const_expr = nullptr; + bool need_add = true; + cur_val_exprs.reuse(); + if (OB_ISNULL(row_expr) || OB_UNLIKELY(row_expr->get_expr_type() != T_OP_ROW)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected expr", KPC(row_expr)); + } + for (int64_t j = 0; OB_SUCC(ret) && need_add && j < key_offsets.count(); ++j) { + int64_t val_offset = key_offsets.at(j); + ObRangeColumnMeta* column_meta = column_metas.at(j); + bool cur_can_be_extract = true; + bool cur_always_true = true; + bool is_valid = false; + const ObExprCalcType &calc_type = res_type.get_row_calc_cmp_types().at(row_dimension * i + val_offset); + if (OB_UNLIKELY(val_offset >= row_expr->get_param_count()) || + OB_ISNULL(const_expr = row_expr->get_param_expr(val_offset))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected expr", K(val_offset), KPC(const_expr)); + } else if (OB_UNLIKELY(!const_expr->is_const_expr())) { + cur_can_be_extract = false; + cur_always_true = true; + } else if (!ObQueryRange::can_be_extract_range(T_OP_EQ, + column_meta->column_type_, + calc_type, + const_expr->get_result_type().get_type(), + cur_always_true)) { + cur_can_be_extract = false; + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + cur_can_be_extract = false; + cur_always_true = true; + } else if (OB_FAIL(OB_FAIL(cur_val_exprs.push_back(const_expr)))) { + LOG_WARN("failed to push back expr"); + } else if (OB_FAIL(check_expr_precise(*const_expr, calc_type, column_meta->column_type_))) { + LOG_WARN("failed to check expr precise", K(ret)); + } + + if (OB_SUCC(ret) && !cur_can_be_extract) { + if (cur_always_true) { + // current key cannot extract range, remove current and subsequent keys + for (int64_t k = key_offsets.count() - 1; OB_SUCC(ret) && k >= j; --k) { + TmpExprArray *val_exprs = all_val_exprs.at(k); + key_idxs.pop_back(); + key_offsets.pop_back(); + column_metas.pop_back(); + all_val_exprs.pop_back(); + if (OB_ISNULL(val_exprs)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null val exprs"); + } else { + val_exprs->destroy(); + alloc.free(val_exprs); + } + } + } else { + need_add = false; + } + } + } + if (OB_SUCC(ret) && need_add && cur_val_exprs.count() > 0) { + ++in_param_count; + for (int64_t j = 0; OB_SUCC(ret) && j < cur_val_exprs.count(); ++j) { + if (OB_ISNULL(all_val_exprs.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected expr array"); + } else if (OB_FAIL(all_val_exprs.at(j)->push_back(cur_val_exprs.at(j)))) { + LOG_WARN("failed to push back raw expr"); + } + } + } + } + + if (OB_SUCC(ret)) { + if (key_idxs.empty()) { + always_true_or_false = true; + } else if (0 == in_param_count) { + always_true_or_false = false; + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < key_idxs.count(); ++i) { + InParam *in_param = nullptr; + int64_t param_idx; + TmpExprArray *val_exprs = all_val_exprs.at(i); + ObRangeColumnMeta* column_meta = column_metas.at(i); + if (OB_ISNULL(val_exprs) || OB_UNLIKELY(in_param_count != val_exprs->count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null val exprs", KPC(val_exprs), K(in_param_count)); + } else if (OB_FAIL(get_final_in_array_idx(in_param, param_idx))) { + LOG_WARN("failed to get final in array idx"); + } else if (OB_FAIL(val_idxs.push_back(param_idx))) { + LOG_WARN("failed to push back param idx"); + } else if (OB_FAIL(in_param->init(in_param_count))) { + LOG_WARN("failed to init fix array"); + } else if (expr_depth == 0 && OB_FAIL(set_column_flags(key_idxs.at(i), T_OP_IN))) { + LOG_WARN("failed to set column flags"); + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < in_param_count; ++j) { + int64_t val_idx = 0; + if (OB_FAIL(get_final_expr_idx(val_exprs->at(j), column_meta, val_idx))) { + LOG_WARN("failed to get final expr idx", K(ret)); + } else if (OB_FAIL(in_param->push_back(val_idx))) { + LOG_WARN("failed to push back val idx"); + } + } + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(fill_range_node_for_basic_row_cmp(T_OP_EQ, key_idxs, val_idxs, *range_node))) { + LOG_WARN("failed to fill range node for basic cmp"); + } else { + range_node->contain_in_ = true; + range_node->in_param_count_ = in_param_count; + if (key_idxs.count() < l_expr.get_param_count()) { + // part of row can't extract range. + ctx_.cur_is_precise_ = false; + } + } + } + } + } + + // cleanup TmpExprArray anyway + if (!all_val_exprs.empty()) { + for (int64_t i = 0; i < all_val_exprs.count(); ++i) { + TmpExprArray *val_exprs = all_val_exprs.at(i); + if (OB_NOT_NULL(val_exprs)) { + val_exprs->destroy(); + alloc.free(val_exprs); + } + } + } + } + + if (OB_SUCC(ret) && nullptr == range_node) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(always_true_or_false, range_node))) { + LOG_WARN("failed to generate always true or fasle node"); + } + } + return ret; +} + +int ObExprRangeConverter::get_single_rowid_in_range_node(const ObRawExpr &rowid_expr, + const ObRawExpr &row_expr, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ctx_.cur_is_precise_ = true; + uint64_t part_column_id = OB_INVALID_ID; + ObSEArray pk_column_items; + bool is_physical_rowid = false; + bool always_true = false; + ObSEArray val_idxs; + if (OB_FAIL(get_extract_rowid_range_infos(rowid_expr, pk_column_items, + is_physical_rowid, part_column_id))) { + LOG_WARN("failed to get extract rowid range infos"); + } else if (!is_physical_rowid) { + ObSEArray key_idxs; + ObSEArray pk_offsets; + ObSEArray tmp_key_idxs; + ObSEArray tmp_pk_offsets; + TmpExprArray all_valid_exprs; + int64_t min_offset = ctx_.column_cnt_; + for (int64_t i = 0; OB_SUCC(ret) && i < pk_column_items.count(); ++i) { + const ObColumnRefRawExpr *column_expr = pk_column_items.at(i); + int64_t key_idx = 0; + if (!is_range_key(column_expr->get_column_id(), key_idx)) { + // do nothing + } else if (OB_FAIL(tmp_key_idxs.push_back(key_idx))) { + LOG_WARN("failed to push back key idx"); + } else if (OB_FAIL(tmp_pk_offsets.push_back(i))) { + LOG_WARN("failed to push back key idx"); + } else if (key_idx < min_offset) { + min_offset = key_idx; + } + } + + if (OB_SUCC(ret) && tmp_key_idxs.count() > 0) { + for (int64_t i = min_offset; OB_SUCC(ret) && i < ctx_.column_cnt_; ++i) { + int64_t idx = -1; + if (ObOptimizerUtil::find_item(tmp_key_idxs, i, &idx)) { + if (OB_FAIL(key_idxs.push_back(i))) { + LOG_WARN("failed to push back key idx", K(key_idxs)); + } else if (OB_FAIL(pk_offsets.push_back(tmp_pk_offsets.at(idx)))) { + LOG_WARN("failed to push back key idx", K(tmp_pk_offsets), K(idx)); + } + } else { + // only extract consistent column for row compare + break; + } + } + } + + for (int64_t i = 0; OB_SUCC(ret) && !always_true && i < row_expr.get_param_count(); ++i) { + const ObRawExpr *const_expr = row_expr.get_param_expr(i); + bool is_valid = false; + if (OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (OB_UNLIKELY(!const_expr->is_const_expr())) { + always_true = true; + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + always_true = true; + } else if (OB_FAIL(all_valid_exprs.push_back(const_expr))) { + LOG_WARN("failed to push back const expr"); + } + } + if (OB_SUCC(ret)) { + if (key_idxs.empty()) { + always_true = true; + } else if (all_valid_exprs.empty()) { + // rowid in (null, null, null) + if (OB_FAIL(generate_always_true_or_false_node(false, range_node))) { + LOG_WARN("failed to generate always fasle node"); + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < key_idxs.count(); ++i) { + InParam *in_param = nullptr; + int64_t param_idx; + if (OB_FAIL(get_final_in_array_idx(in_param, param_idx))) { + LOG_WARN("failed to get final in array idx"); + } else if (OB_FAIL(val_idxs.push_back(param_idx))) { + LOG_WARN("failed to push back param idx"); + } else if (OB_FAIL(in_param->init(all_valid_exprs.count()))) { + LOG_WARN("failed to init fix array"); + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < all_valid_exprs.count(); ++j) { + int64_t val_idx = 0; + if (OB_FAIL(get_final_expr_idx(all_valid_exprs.at(j), nullptr, val_idx))) { + LOG_WARN("failed to get final expr idx", K(ret)); + } else if (OB_FAIL(in_param->push_back(val_idx))) { + LOG_WARN("failed to push back val idx"); + } else if (OB_FAIL(ctx_.rowid_idxs_.push_back(std::pair(val_idx, pk_offsets.at(i))))) { + LOG_WARN("failed to push back rowid idxs", K(val_idx), K(pk_offsets.at(i))); + } + } + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(fill_range_node_for_basic_row_cmp(T_OP_EQ, key_idxs, val_idxs, *range_node))) { + LOG_WARN("failed to fill range node for basic cmp"); + } else { + range_node->contain_in_ = true; + range_node->in_param_count_ = all_valid_exprs.count(); + } + } + } + } + } else { + // physical rowid + int64_t key_idx = 0; + int64_t const_idx = 0; + if (common::OB_INVALID_ID == part_column_id) { + if (OB_UNLIKELY(pk_column_items.count() != 1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpect pk count for no pk table", K(pk_column_items)); + } else if (ctx_.range_column_map_.count() != 1 || + !is_range_key(pk_column_items.at(0)->get_column_id(), key_idx)) { + // only extract physical rowid range for primary index + always_true = true; + } + } else if (!ctx_.phy_rowid_for_table_loc_ || !is_range_key(part_column_id, key_idx)) { + always_true = true; + } + + for (int64_t i = 0; OB_SUCC(ret) && !always_true && i < row_expr.get_param_count(); ++i) { + const ObRawExpr *const_expr = row_expr.get_param_expr(i); + bool is_valid = false; + int64_t val_idx = -1; + if (OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (OB_UNLIKELY(!const_expr->is_const_expr())) { + always_true = true; + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + always_true = true; + } else if (OB_FAIL(get_final_expr_idx(const_expr, nullptr, val_idx))) { + LOG_WARN("failed to get final expr idx", K(ret)); + } else if (OB_FAIL(ctx_.rowid_idxs_.push_back(std::pair(val_idx, PHYSICAL_ROWID_IDX)))) { + LOG_WARN("failed to push back rowid idxs", K(const_idx), K(PHYSICAL_ROWID_IDX)); + } else if (OB_FAIL(val_idxs.push_back(val_idx))) { + LOG_WARN("failed to push back val idx", K(val_idx)); + } + } + if (OB_SUCC(ret) && !always_true) { + InParam *in_param = nullptr; + int64_t param_idx; + if (val_idxs.empty()) { + // c1 in (null, null, null) + if (OB_FAIL(generate_always_true_or_false_node(false, range_node))) { + LOG_WARN("failed to generate always fasle node"); + } + } else if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(get_final_in_array_idx(in_param, param_idx))) { + LOG_WARN("failed to get final in array idx"); + } else if (OB_FAIL(in_param->assign(val_idxs))) { + LOG_WARN("failed to assign in params"); + } else if (OB_FAIL(fill_range_node_for_basic_cmp(T_OP_EQ, key_idx, param_idx, *range_node))) { + LOG_WARN("failed to fill range node for basic cmp"); + } else { + range_node->contain_in_ = true; + range_node->is_phy_rowid_ = true; + range_node->in_param_count_ = val_idxs.count(); + } + } + } + + if (OB_SUCC(ret) && range_node == nullptr) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true node"); + } + } + return ret; +} + +int ObExprRangeConverter::convert_not_in_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + const ObRawExpr* l_expr = nullptr; + const ObRawExpr* r_expr = nullptr; + ctx_.cur_is_precise_ = false; + bool use_implicit_cast_feature = ObSQLUtils::is_opt_feature_version_ge_425_or_435(ctx_.optimizer_features_enable_version_); + if (OB_ISNULL(expr) || + OB_ISNULL(l_expr = expr->get_param_expr(0)) || + OB_ISNULL(r_expr = expr->get_param_expr(1))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(expr), K(l_expr), K(r_expr)); + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(l_expr, l_expr, use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (l_expr->get_expr_type() == T_OP_ROW || r_expr->get_param_count() > NEW_MAX_NOT_IN_SIZE) { + // do nothing + } else if (l_expr->is_column_ref_expr()) { + if (OB_FAIL(get_single_not_in_range_node(static_cast(l_expr), + r_expr, + expr->get_result_type(), + expr_depth, + range_node))) { + LOG_WARN("failed to get single not in range node", K(ret)); + } + } else if (r_expr->get_param_count() > MAX_NOT_IN_SIZE) { + // do nothing + } else if (l_expr->is_column_ref_expr()) { + ObArenaAllocator alloc("ExprRangeAlloc", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObSEArray and_range_nodes; + ObSEArray or_range_nodes; + bool is_precise = true; + for (int64_t i = 0; OB_SUCC(ret) && i < r_expr->get_param_count(); ++i) { + or_range_nodes.reuse(); + ObRangeNode *tmp_node = nullptr; + ObRangeNode *final_node = nullptr; + const ObRawExpr* const_expr = r_expr->get_param_expr(i); + ObExprResType res_type(alloc); + res_type.set_calc_meta(expr->get_result_type().get_row_calc_cmp_types().at(i)); + if (OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null"); + } else if (!const_expr->is_const_expr()) { + // ignore current node + is_precise = false; + } else if (OB_FAIL(get_basic_range_node(l_expr, const_expr, T_OP_LT, res_type, expr_depth + 1, tmp_node))) { + LOG_WARN("failed tp get basic range node", K(ret)); + } else if (OB_FAIL(or_range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FALSE_IT(is_precise &= ctx_.cur_is_precise_)) { + } else if (OB_FAIL(get_basic_range_node(l_expr, const_expr, T_OP_GT, res_type, expr_depth + 1, tmp_node))) { + LOG_WARN("failed tp get basic range node", K(ret)); + } else if (OB_FAIL(or_range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FALSE_IT(is_precise &= ctx_.cur_is_precise_)) { + } else if (OB_FAIL(ObRangeGraphGenerator::or_range_nodes(*this, or_range_nodes, ctx_.column_cnt_, final_node))) { + LOG_WARN("failed to or range nodes"); + } else if (OB_FAIL(and_range_nodes.push_back(final_node))) { + LOG_WARN("failed to push back range node"); + } + } + if (OB_SUCC(ret) && !and_range_nodes.empty()) { + if (OB_FAIL(ObRangeGraphGenerator::and_range_nodes(and_range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to or range nodes"); + } else { + ctx_.cur_is_precise_ = is_precise; + } + } + } + + if (OB_SUCC(ret) && nullptr == range_node) { + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node"); + } + } + return ret; +} + +int ObExprRangeConverter::get_single_not_in_range_node(const ObColumnRefRawExpr *column_expr, + const ObRawExpr *r_expr, + const ObExprResType &res_type, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ObRangeColumnMeta *column_meta = nullptr; + int64_t key_idx = -1; + ObSEArray val_idxs; + bool is_precise = true; + range_node = nullptr; + ctx_.cur_is_precise_ = true; + bool always_false = false; + if (OB_ISNULL(column_expr) || OB_ISNULL(r_expr) || + OB_UNLIKELY(r_expr->get_param_count() == 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected param", KPC(column_expr), KPC(r_expr)); + } else if (!is_range_key(column_expr->get_column_id(), key_idx)) { + // do nothing + } else if ((ctx_.column_flags_[key_idx] & (RANGE_EXPR_EQUAL | + RANGE_EXPR_IN | + RANGE_EXPR_NOT_IN)) != 0) { + // do nothing + } else if (OB_ISNULL(column_meta = get_column_meta(key_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else { + for (int64_t i = 0; OB_SUCC(ret) && !always_false && i < r_expr->get_param_count(); ++i) { + const ObRawExpr *const_expr = r_expr->get_param_expr(i); + bool cur_always_true = true; + bool is_valid = true; + int64_t val_idx = -1; + + if (OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (OB_UNLIKELY(!const_expr->is_const_expr())) { + is_precise = false; + } else if (!ObQueryRange::can_be_extract_range(T_OP_LT, column_meta->column_type_, + res_type.get_row_calc_cmp_types().at(i), + const_expr->get_result_type().get_type(), + cur_always_true)) { + always_false = !cur_always_true; + is_precise = false; + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + is_precise = false; + } else if (OB_FAIL(get_final_expr_idx(const_expr, column_meta, val_idx))) { + LOG_WARN("failed to get final expr idx", K(ret)); + } else if (OB_FAIL(check_expr_precise(*const_expr, res_type.get_row_calc_cmp_types().at(i), + column_meta->column_type_))) { + LOG_WARN("failed to check expr precise", K(ret)); + } else if (OB_FALSE_IT(is_precise &= ctx_.cur_is_precise_)) { + } else if (OB_FAIL(val_idxs.push_back(val_idx))) { + LOG_WARN("failed to push back val idx", K(val_idx)); + } + } + if (OB_FAIL(ret)) { + } else if (always_false) { + if (OB_FAIL(generate_always_true_or_false_node(always_false, range_node))) { + LOG_WARN("failed to generate always true or fasle node"); + } + } else if (!val_idxs.empty()) { + InParam *in_param = nullptr; + int64_t param_idx; + if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(get_final_in_array_idx(in_param, param_idx))) { + LOG_WARN("failed to get final in array idx"); + } else if (OB_FAIL(in_param->assign(val_idxs))) { + LOG_WARN("failed to assign in params"); + } else if (OB_FAIL(fill_range_node_for_basic_cmp(T_OP_EQ, key_idx, param_idx, *range_node))) { + LOG_WARN("failed to fill range node for basic cmp"); + } else if (expr_depth == 0 && OB_FAIL(set_column_flags(key_idx, T_OP_NOT_IN))) { + LOG_WARN("failed tp set column flags"); + } else { + range_node->is_not_in_node_ = true; + range_node->in_param_count_ = val_idxs.count(); + ctx_.cur_is_precise_ = is_precise; + } + } + } + return ret; +} + +int ObExprRangeConverter::get_calculable_expr_val(const ObRawExpr *expr, + ObObj &val, + bool &is_valid, + const bool ignore_error/*default true*/) +{ + int ret = OB_SUCCESS; + if (expr->has_flag(CNT_DYNAMIC_PARAM)) { + is_valid = true; + } else if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(ctx_.exec_ctx_, + expr, + val, + is_valid, + allocator_, + ignore_error && ctx_.ignore_calc_failure_, + ctx_.expr_constraints_))) { + LOG_WARN("failed to calc const or calculable expr", K(ret)); + } + return ret; +} + +int ObExprRangeConverter::check_calculable_expr_valid(const ObRawExpr *expr, + bool &is_valid, + const bool ignore_error/*default true*/) +{ + int ret = OB_SUCCESS; + ObObj val; + if (expr->has_flag(CNT_DYNAMIC_PARAM)) { + is_valid = true; + } else if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(ctx_.exec_ctx_, + expr, + val, + is_valid, + allocator_, + ignore_error && ctx_.ignore_calc_failure_, + ctx_.expr_constraints_))) { + LOG_WARN("failed to calc const or calculable expr", K(ret)); + } + return ret; +} + +int ObExprRangeConverter::add_precise_constraint(const ObRawExpr *expr, bool is_precise) +{ + int ret = OB_SUCCESS; + PreCalcExprExpectResult expect_result = is_precise ? PreCalcExprExpectResult::PRE_CALC_PRECISE : + PreCalcExprExpectResult::PRE_CALC_NOT_PRECISE; + ObExprConstraint cons(const_cast(expr), expect_result); + if (NULL == ctx_.expr_constraints_) { + // do nothing + } else if (OB_FAIL(add_var_to_array_no_dup(*ctx_.expr_constraints_, cons))) { + LOG_WARN("failed to add precise constraint", K(ret)); + } + return ret; +} + +// TODO:@yibo.tyf. This constraint seems like useless +int ObExprRangeConverter::add_prefix_pattern_constraint(const ObRawExpr *expr) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObRawExprUtils::get_real_expr_without_cast(expr, expr))) { + LOG_WARN("fail to get real expr", K(ret)); + } else if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (T_FUN_SYS_PREFIX_PATTERN == expr->get_expr_type()) { + ObExprConstraint cons(const_cast(expr), PreCalcExprExpectResult::PRE_CALC_RESULT_NOT_NULL); + if (NULL == ctx_.expr_constraints_) { + // do nothing + } else if (OB_FAIL(add_var_to_array_no_dup(*ctx_.expr_constraints_, cons))) { + LOG_WARN("failed to add precise constraint", K(ret)); + } + } + return ret; +} + +int ObExprRangeConverter::fill_range_node_for_basic_cmp(ObItemType cmp_type, + const int64_t key_idx, + const int64_t val_idx, + ObRangeNode &range_node) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(key_idx >= ctx_.column_cnt_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected column idx", K(key_idx), K(ctx_.column_cnt_)); + } else { + range_node.min_offset_ = key_idx; + range_node.max_offset_ = key_idx; + bool need_set_flag = (key_idx == ctx_.column_cnt_ - 1); + for (int64_t i = 0; i < key_idx; ++i) { + range_node.start_keys_[i] = OB_RANGE_EMPTY_VALUE; + range_node.end_keys_[i] = OB_RANGE_EMPTY_VALUE; + } + if (T_OP_EQ == cmp_type || T_OP_NSEQ == cmp_type) { + range_node.start_keys_[key_idx] = val_idx; + range_node.end_keys_[key_idx] = val_idx; + if (need_set_flag) { + range_node.include_start_ = true; + range_node.include_end_ = true; + } else { + for (int64_t i = key_idx + 1; i < ctx_.column_cnt_; ++i) { + range_node.start_keys_[i] = OB_RANGE_MIN_VALUE; + range_node.end_keys_[i] = OB_RANGE_MAX_VALUE; + } + } + } else if (T_OP_LE == cmp_type || T_OP_LT == cmp_type) { + // (c1, c2, c3) + // c1 < 10 => (min, min, min; 10, min, min) + // c1 <= 10 => (min, min, min; 10, max, max) + // c2 < 10 => (ept, min, min; ept, 10, min) + // c2 <= 10 => (ept, min, min; ept, 10, max) + // c3 < 10 => (ept, ept, min; ept, ept, 10) + // c3 <= 10 => (ept, ept, min; ept, ept, 10] + range_node.start_keys_[key_idx] = lib::is_oracle_mode() ? OB_RANGE_MIN_VALUE : OB_RANGE_NULL_VALUE; + range_node.end_keys_[key_idx] = val_idx; + if (need_set_flag) { + range_node.include_start_ = false; + range_node.include_end_ = (T_OP_LE == cmp_type || + (ctx_.final_exprs_flag_.at(val_idx) + & OB_FINAL_EXPR_WITH_LOB_TRUNCATE) + == OB_FINAL_EXPR_WITH_LOB_TRUNCATE); + } else { + for (int64_t i = key_idx + 1; i < ctx_.column_cnt_; ++i) { + range_node.start_keys_[i] = lib::is_oracle_mode() ? OB_RANGE_MIN_VALUE : OB_RANGE_MAX_VALUE; + range_node.end_keys_[i] = (T_OP_LE == cmp_type || + (ctx_.final_exprs_flag_.at(val_idx) + & OB_FINAL_EXPR_WITH_LOB_TRUNCATE) + == OB_FINAL_EXPR_WITH_LOB_TRUNCATE) ? OB_RANGE_MAX_VALUE : OB_RANGE_MIN_VALUE; + } + } + } else if (T_OP_GE == cmp_type || T_OP_GT == cmp_type) { + // (c1, c2, c3) + // c1 > 10 => (10, max, max; max, max, max) + // c1 >= 10 => (10, min, min; max, max, max) + // c2 > 10 => (ept, 10, max; ept, max, max) + // c2 >= 10 => (ept, 10, min; ept, max, max) + // c3 > 10 => (ept, ept, 10; ept, ept, max) + // c3 >= 10 => [ept, ept, 10; ept, ept, max) + range_node.start_keys_[key_idx] = val_idx; + range_node.end_keys_[key_idx] = lib::is_oracle_mode() ? OB_RANGE_NULL_VALUE : OB_RANGE_MAX_VALUE; + if (need_set_flag) { + range_node.include_start_ = (T_OP_GE == cmp_type); + range_node.include_end_ = false; + } else { + for (int64_t i = key_idx + 1; i < ctx_.column_cnt_; ++i) { + range_node.start_keys_[i] = (T_OP_GE == cmp_type) ? OB_RANGE_MIN_VALUE : OB_RANGE_MAX_VALUE; + range_node.end_keys_[i] = lib::is_oracle_mode() ? OB_RANGE_MIN_VALUE : OB_RANGE_MAX_VALUE; + } + } + } + } + return ret; +} + +/** + * T_OP_EQ/T_OP_NSEQ doesn't require key_idx strict increasing + * T_OP_LE/T_OP_LT/T_OP_GE/T_OP_GT require key_idx strict increasing +*/ +int ObExprRangeConverter::fill_range_node_for_basic_row_cmp(ObItemType cmp_type, + const ObIArray &key_idxs, + const ObIArray &val_idxs, + ObRangeNode &range_node) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(key_idxs.count() != val_idxs.count()) || + OB_UNLIKELY(key_idxs.count() <= 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected count", K(key_idxs.count()), K(val_idxs.count())); + } else if (T_OP_EQ == cmp_type || T_OP_NSEQ == cmp_type) { + range_node.min_offset_ = key_idxs.at(0); + range_node.max_offset_ = key_idxs.at(0); + for (int64_t i = 0; i < ctx_.column_cnt_; ++i) { + range_node.start_keys_[i] = OB_RANGE_MIN_VALUE; + range_node.end_keys_[i] = OB_RANGE_MAX_VALUE; + } + for (int64_t i = 0; i < key_idxs.count(); ++i) { + int64_t key_idx = key_idxs.at(i); + int64_t val_idx = val_idxs.at(i); + OB_ASSERT(key_idx < ctx_.column_cnt_); + range_node.start_keys_[key_idx] = val_idx; + range_node.end_keys_[key_idx] = val_idx; + if (key_idx < range_node.min_offset_) { + range_node.min_offset_ = key_idx; + } else if (key_idx > range_node.max_offset_) { + range_node.max_offset_ = key_idx; + } + } + for (int64_t i = 0; i < ctx_.column_cnt_; ++i) { + if (OB_RANGE_MIN_VALUE == range_node.start_keys_[i]) { + range_node.start_keys_[i] = OB_RANGE_EMPTY_VALUE; + range_node.end_keys_[i] = OB_RANGE_EMPTY_VALUE; + } else { + break; + } + } + if (range_node.start_keys_[ctx_.column_cnt_ - 1] != OB_RANGE_MIN_VALUE) { + range_node.include_start_ = true; + range_node.include_end_ = true; + } + } else { + range_node.min_offset_ = key_idxs.at(0); + range_node.max_offset_ = key_idxs.at(key_idxs.count() - 1); + for (int64_t i = 0; i < key_idxs.count(); ++i) { + int64_t key_idx = key_idxs.at(i); + int64_t val_idx = val_idxs.at(i); + if (OB_UNLIKELY(key_idx >= ctx_.column_cnt_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected column idx", K(key_idx), K(ctx_.column_cnt_)); + } else { + bool need_set_flag = (key_idx == ctx_.column_cnt_ - 1); + bool need_include_end = false; + if (0 == i) { + for (int64_t j = 0; j < key_idx; ++j) { + range_node.start_keys_[j] = OB_RANGE_EMPTY_VALUE; + range_node.end_keys_[j] = OB_RANGE_EMPTY_VALUE; + } + } + if (T_OP_LE == cmp_type || T_OP_LT == cmp_type) { + // (c1, c2, c3, c4) + // (c1,c3) < (10,10) => (min, min, min, min; 10, max, 10, min) + // (c1,c3) <= (10,10) => (min, min, min, min; 10, max, 10, max) + // (c2,c3) < (10,10) => (ept, min, min, min; ept, 10, 10, min) + // (c2,c3) <= (10,10) => (ept, min, min, min; ept, 10, 10, max) + // (c3,c4) < (10,10) => (ept, ept, min, min; ept, ept, 10, 10) + // (c3,c4) <= (10,10) => (ept, ept, min, min; ept, ept, 10, 10] + /** + * (c1,c2) <= (10, 10) + * oracle 精确 + * (min, min, min; 10, 10, max) + * mysql 非精确 + * (null, max, max, 10, 10, max) + * + * (c1,c2) < (10, 10) + * oracle 精确 + * (min, min, min; 10, 10, min) + * mysql 非精确 + * (null, max, max, 10, 10, min) + */ + if (0 == i) { + if (lib::is_oracle_mode()) { + range_node.start_keys_[key_idx] = OB_RANGE_MIN_VALUE; + } else { + range_node.start_keys_[key_idx] = OB_RANGE_NULL_VALUE; + } + } else { + if (lib::is_oracle_mode()) { + range_node.start_keys_[key_idx] = OB_RANGE_MIN_VALUE; + } else { + range_node.start_keys_[key_idx] = OB_RANGE_MAX_VALUE; + } + } + range_node.end_keys_[key_idx] = val_idx; + if (key_idxs.count() - 1 == i) { + need_include_end = (ctx_.final_exprs_flag_.at(val_idx) + & OB_FINAL_EXPR_WITH_LOB_TRUNCATE) + == OB_FINAL_EXPR_WITH_LOB_TRUNCATE; + for (int64_t j = key_idx + 1; j < ctx_.column_cnt_; ++j) { + range_node.start_keys_[j] = lib::is_oracle_mode() ? OB_RANGE_MIN_VALUE : OB_RANGE_MAX_VALUE; + range_node.end_keys_[j] = (T_OP_LE == cmp_type || need_include_end) ? OB_RANGE_MAX_VALUE : OB_RANGE_MIN_VALUE; + } + } + if (need_set_flag) { + range_node.include_start_ = false; + range_node.include_end_ = (T_OP_LE == cmp_type || need_include_end); + } + } else if (T_OP_GE == cmp_type || T_OP_GT == cmp_type) { + // (c1, c2, c3) + // (c1,c3) > (10,10) => (10, min, 10, max; max, max, max, max) + // (c1,c3) >= (10,10) => (10, min, 10, min; max, max, max, max) + // (c2,c3) > (10,10) => (ept, 10, 10, max; ept, max, max, max) + // (c2,c3) >= (10,10) => (ept, 10, 10, min; ept, max, max, max) + // (c3,c3) > (10,10) => (ept, ept, 10, 10; ept, ept, max, max) + // (c3,c3) >= (10,10) => [ept, ept, 10, 10; ept, ept, max, max) + /** + * (c1,c2) >= (10, 10) + * oracle 非精确 + * (10, 10, min; null, min, min) + * mysql 精确 + * (10, 10, min; max, max, max) + * + * (c1,c2) > (10, 10) + * oracle 非精确 + * (10, 10, max; null, min, min) + * mysql 精确 + * (10, 10, max; max, max, max) + */ + range_node.start_keys_[key_idx] = val_idx; + if (0 == i) { + if (lib::is_oracle_mode()) { + range_node.end_keys_[key_idx] = OB_RANGE_NULL_VALUE; + } else { + range_node.end_keys_[key_idx] = OB_RANGE_MAX_VALUE; + } + } else { + if (lib::is_oracle_mode()) { + range_node.end_keys_[key_idx] = OB_RANGE_MIN_VALUE; + } else { + range_node.end_keys_[key_idx] = OB_RANGE_MAX_VALUE; + } + } + if (key_idxs.count() - 1 == i) { + for (int64_t j = key_idx + 1; j < ctx_.column_cnt_; ++j) { + range_node.start_keys_[j] = (T_OP_GE == cmp_type) ? OB_RANGE_MIN_VALUE : OB_RANGE_MAX_VALUE; + range_node.end_keys_[j] = lib::is_oracle_mode() ? OB_RANGE_MIN_VALUE : OB_RANGE_MAX_VALUE; + } + } + if (need_set_flag) { + range_node.include_start_ = (T_OP_GE == cmp_type); + range_node.include_end_ = false; + } + } + } + } + } + return ret; +} + +int ObExprRangeConverter::fill_range_node_for_like(const int64_t key_idx, + const int64_t start_val_idx, + const int64_t end_val_idx, + ObRangeNode &range_node) const +{ + int ret = OB_SUCCESS; + OB_ASSERT(key_idx < ctx_.column_cnt_); + range_node.min_offset_ = key_idx; + range_node.max_offset_ = key_idx; + bool need_set_flag = (key_idx == ctx_.column_cnt_ - 1); + for (int64_t i = 0; i < key_idx; ++i) { + range_node.start_keys_[i] = OB_RANGE_EMPTY_VALUE; + range_node.end_keys_[i] = OB_RANGE_EMPTY_VALUE; + } + range_node.start_keys_[key_idx] = start_val_idx; + range_node.end_keys_[key_idx] = end_val_idx; + if (need_set_flag) { + range_node.include_start_ = true; + range_node.include_end_ = true; + } else { + for (int64_t i = key_idx + 1; i < ctx_.column_cnt_; ++i) { + range_node.start_keys_[i] = OB_RANGE_MIN_VALUE; + range_node.end_keys_[i] = OB_RANGE_MAX_VALUE; + } + } + return ret; +} + +int ObExprRangeConverter::check_expr_precise(const ObRawExpr &const_expr, + const ObExprCalcType &calc_type, + const ObExprResType &column_res_type) +{ + int ret = OB_SUCCESS; + if (column_res_type.is_string_type() && calc_type.is_string_type()) { + if (CS_TYPE_UTF8MB4_GENERAL_CI == column_res_type.get_collation_type() + && CS_TYPE_UTF8MB4_GENERAL_CI != calc_type.get_collation_type()) { + // we will set collation type of value to column's collation type, + // however, if general bin transform to general ci, + // the result may be N:1, the range may be amplified and turn to inprecise + ctx_.cur_is_precise_ = false; + } + } + if (is_oracle_mode()) { + // c1 char(5), c2 varchar(5) 对于值'abc', c1 = 'abc ', c2 = 'abc' + // in oracle mode, 'abc ' is not equals to 'abc', but the range of c1 = cast('abc' as varchar2(5)) + // is extracted as (abc ; abc), this is because that storage layer does not padding emptycharacter, + // as a result, by using the range above, value 'abc ' is selected, which is incorrect. + // to avoid this, set the range to be not precise + const ObObjType &column_type = column_res_type.get_type(); + const ObObjType &const_type = const_expr.get_result_type().get_type(); + if ((ObCharType == column_type && ObVarcharType == const_type) || + (ObNCharType == column_type && ObNVarchar2Type == const_type)) { + ctx_.cur_is_precise_ = false; + } + } + return ret; +} + +int ObExprRangeConverter::get_rowid_node(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + range_node = nullptr; + ctx_.cur_is_precise_ = true; + const ObRawExpr *const_expr = NULL; + const ObRawExpr *rowid_expr = NULL; + uint64_t part_column_id = OB_INVALID_ID; + ObSEArray pk_column_items; + bool is_physical_rowid = false; + bool is_valid = false; + + if (OB_LIKELY(r_expr.is_const_expr())) { + rowid_expr = &l_expr; + const_expr = &r_expr; + } else { + rowid_expr = &r_expr; + const_expr = &l_expr; + cmp_type = get_opposite_compare_type(cmp_type); + } + + if (OB_FAIL(get_extract_rowid_range_infos(*rowid_expr, pk_column_items, + is_physical_rowid, part_column_id))) { + LOG_WARN("failed to get extract rowid range infos"); + } else if (OB_FAIL(check_calculable_expr_valid(const_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + // do nothing + } else if (!is_physical_rowid) { + ObSEArray key_idxs; + ObSEArray val_idxs; + if (T_OP_EQ == cmp_type || T_OP_NSEQ == cmp_type) { + ObSEArray tmp_key_idxs; + ObSEArray pk_idxs; + int64_t min_offset = ctx_.column_cnt_; + for (int64_t i = 0; OB_SUCC(ret) && i < pk_column_items.count(); ++i) { + const ObColumnRefRawExpr *column_expr = pk_column_items.at(i); + int64_t key_idx = 0; + if (is_range_key(column_expr->get_column_id(), key_idx)) {; + if (OB_FAIL(tmp_key_idxs.push_back(key_idx))) { + LOG_WARN("failed to push back key idx"); + } else if (OB_FAIL(pk_idxs.push_back(i))) { + LOG_WARN("failed to push back pk idx"); + } else if (key_idx < min_offset) { + min_offset = key_idx; + } + } + } + for (int64_t i = min_offset; OB_SUCC(ret) && i < ctx_.column_cnt_; ++i) { + int64_t idx = -1; + int64_t const_idx = 0; + if (ObOptimizerUtil::find_item(tmp_key_idxs, i, &idx)) { + if (OB_FAIL(key_idxs.push_back(i))) { + LOG_WARN("failed to push back key idx", K(key_idxs)); + } else if (OB_FAIL(get_final_expr_idx(const_expr, nullptr, const_idx))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(val_idxs.push_back(const_idx))) { + LOG_WARN("failed to push back val idx"); + } else if (OB_FAIL(ctx_.rowid_idxs_.push_back(std::pair(const_idx, pk_idxs.at(idx))))) { + LOG_WARN("failed to push back rowid idxs", K(const_idx), K(idx)); + } + } else { + // only extract consistent column for row compare + break; + } + } + } else { + int64_t last_key_idx = -1; + bool check_next = true; + for (int64_t i = 0; OB_SUCC(ret) && check_next && i < pk_column_items.count(); ++i) { + const ObColumnRefRawExpr *column_expr = pk_column_items.at(i); + int64_t key_idx = 0; + int64_t const_idx = 0; + check_next = false; + if (!is_range_key(column_expr->get_column_id(), key_idx)) { + // do nothing + } else if (last_key_idx != -1 && last_key_idx + 1 != key_idx) { + // do nothing + } else if (OB_FAIL(get_final_expr_idx(const_expr, nullptr, const_idx))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(key_idxs.push_back(key_idx))) { + LOG_WARN("failed to push back key idx"); + } else if (OB_FAIL(val_idxs.push_back(const_idx))) { + LOG_WARN("failed to push back val idx"); + } else if (OB_FAIL(ctx_.rowid_idxs_.push_back(std::pair(const_idx, i)))) { + LOG_WARN("failed to push back rowid idxs", K(const_idx), K(i)); + } else { + bool is_lt_with_lob = (cmp_type == T_OP_LT || cmp_type == T_OP_LE) && + (ctx_.final_exprs_flag_.at(const_idx) + & OB_FINAL_EXPR_WITH_LOB_TRUNCATE) + == OB_FINAL_EXPR_WITH_LOB_TRUNCATE; + check_next = !is_lt_with_lob; + last_key_idx = key_idx; + } + } + } + if (OB_SUCC(ret) && key_idxs.count() > 0) { + if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(fill_range_node_for_basic_row_cmp(cmp_type, key_idxs, val_idxs, *range_node))) { + LOG_WARN("failed to get normal row cmp keypart"); + } + } + } else { + // physical rowid + int64_t key_idx = 0; + int64_t const_idx = 0; + bool always_true = false; + if (common::OB_INVALID_ID == part_column_id) { + if (OB_UNLIKELY(pk_column_items.count() != 1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpect pk count for no pk table", K(pk_column_items)); + } else if (ctx_.range_column_map_.count() != 1 || + !is_range_key(pk_column_items.at(0)->get_column_id(), key_idx)) { + // only extract physical rowid range for primary index + always_true = true; + } + } else if (!ctx_.phy_rowid_for_table_loc_ || !is_range_key(part_column_id, key_idx)) { + always_true = true; + } + + if (OB_FAIL(ret) || always_true) { + // do nothing + } else if (OB_FAIL(get_final_expr_idx(const_expr, nullptr, const_idx))) { + LOG_WARN("failed to get final expr idx"); + } else if (OB_FAIL(ctx_.rowid_idxs_.push_back(std::pair(const_idx, PHYSICAL_ROWID_IDX)))) { + LOG_WARN("failed to push back rowid idxs", K(const_idx), K(PHYSICAL_ROWID_IDX)); + } else if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc common range node"); + } else if (OB_FAIL(fill_range_node_for_basic_cmp(cmp_type, key_idx, const_idx, *range_node))) { + LOG_WARN("failed to get normal row cmp keypart"); + } else { + range_node->is_phy_rowid_ = true; + } + } + + if (OB_SUCC(ret) && range_node == nullptr) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true node"); + } + } + return ret; +} + +int ObExprRangeConverter::get_extract_rowid_range_infos(const ObRawExpr &calc_urowid_expr, + ObIArray &pk_columns, + bool &is_physical_rowid, + uint64_t &part_column_id) +{ + int ret = OB_SUCCESS; + is_physical_rowid = false; + part_column_id = common::OB_INVALID_ID; + for (int64_t i = 0; OB_SUCC(ret) && i < calc_urowid_expr.get_param_count(); ++i) { + const ObRawExpr *param_expr = calc_urowid_expr.get_param_expr(i); + if (OB_ISNULL(param_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (param_expr->has_flag(IS_COLUMN)) { + const ObColumnRefRawExpr * col_expr = static_cast(param_expr); + // pk_vals may store generated col which is partition key but not primary key + if (!col_expr->is_rowkey_column()) { + /*do nothing*/ + } else if (OB_FAIL(pk_columns.push_back(col_expr))) { + LOG_WARN("push back pk_column item failed"); + } + } else if (param_expr->get_expr_type() == T_FUN_SYS_CALC_TABLET_ID) { + is_physical_rowid = true; + ObSEArray column_exprs; + if (!ctx_.phy_rowid_for_table_loc_) { + // do nothing + } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(param_expr, column_exprs))) { + LOG_WARN("get column exprs error", KPC(param_expr)); + } else { + bool find = false; + for (int64_t j = 0; OB_SUCC(ret) && !find && j < column_exprs.count(); ++j) { + ObColumnRefRawExpr *col_expr = NULL; + if (OB_ISNULL(col_expr = static_cast(column_exprs.at(j)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(col_expr)); + } else { + int64_t key_idx = 0; + if (is_range_key(col_expr->get_column_id(), key_idx)) { + find = true; + part_column_id = col_expr->get_column_id(); + } + } + } + } + } + } + LOG_TRACE("get extract rowid range infos", K(is_physical_rowid), K(part_column_id), + K(pk_columns), K(calc_urowid_expr)); + + return ret; +} + +// final info start +int ObExprRangeConverter::get_final_expr_idx(const ObRawExpr *expr, + const ObRangeColumnMeta *column_meta, + int64_t &idx) +{ + int ret = OB_SUCCESS; + const ObRawExpr *wrap_const_expr = expr; + bool can_be_range_get = true; + idx = ctx_.final_exprs_.count(); + if (nullptr != column_meta && nullptr != expr && + OB_FAIL(check_can_use_range_get(*expr, *column_meta))) { + LOG_WARN("failed to check can be use range get", K(ret)); + } else if (nullptr != column_meta && + OB_FAIL(try_wrap_lob_with_substr(expr, column_meta, wrap_const_expr))) { + LOG_WARN("failed to wrap lob with substr", K(ret)); + } else if (OB_FAIL(ctx_.final_exprs_.push_back(wrap_const_expr))) { + LOG_WARN("failed to push back final expr"); + } else if (OB_FAIL(ctx_.final_exprs_flag_.push_back(expr == wrap_const_expr ? 0 + : OB_FINAL_EXPR_WITH_LOB_TRUNCATE))) { + LOG_WARN("failed to push back final expr flag"); + } + return ret; +} + +// in array index start from -1 to INT64_MIN +int ObExprRangeConverter::get_final_in_array_idx(InParam *&in_param, int64_t &idx) +{ + int ret = OB_SUCCESS; + idx = -(ctx_.in_params_.count() + 1); + void *ptr = nullptr; + if (OB_UNLIKELY(allocator_.used() - mem_used_ > ctx_.max_mem_size_)) { + ret = OB_ERR_QUERY_RANGE_MEMORY_EXHAUSTED; + LOG_INFO("use too much memory when extract query range", K(ctx_.max_mem_size_)); + } else if (OB_ISNULL(ptr = allocator_.alloc(sizeof(InParam)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory for InParam failed"); + } else { + in_param = new(ptr) InParam(); + in_param->set_allocator(&allocator_); + if (OB_FAIL(ctx_.in_params_.push_back(in_param))) { + LOG_WARN("failed to push back final expr"); + } + } + return ret; +} + +bool ObExprRangeConverter::is_range_key(const uint64_t column_id, int64_t &key_idx) +{ + bool is_key = false; + int ret = ctx_.range_column_map_.get_refactored(column_id, key_idx); + if (OB_SUCCESS == ret) { + is_key = true; + if (ctx_.index_prefix_ > -1 && key_idx >= ctx_.index_prefix_) { + is_key = false; + } + } else if (OB_HASH_NOT_EXIST == ret) { + is_key = false; + } else { + LOG_WARN_RET(OB_ERR_UNEXPECTED, "failed to get key_idx from range column map", K(column_id)); + } + return is_key; +} + +ObRangeColumnMeta* ObExprRangeConverter::get_column_meta(int64_t idx) +{ + ObRangeColumnMeta* column_meta = nullptr; + if (idx >=0 && idx < ctx_.column_metas_.count()) { + column_meta = ctx_.column_metas_.at(idx); + } + return column_meta; +} + +int ObExprRangeConverter::get_nvl_cmp_node(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + range_node = NULL; + ctx_.cur_is_precise_ = true; + bool always_true = true; + bool is_precise = true; + bool second_is_precise = true; + const ObOpRawExpr *nvl_expr = NULL; + const ObRawExpr *const_expr = NULL; + const ObRawExpr *nvl_first_expr = NULL; + const ObRawExpr *nvl_second_expr = NULL; + ObRawExpr *cmp_second_expr = NULL; + ObRangeNode *cmp_range_node = NULL; + ObRangeNode *cmp_second_node = NULL; + ObRangeNode *is_null_node = NULL; + ObRangeNode *null_and_node = NULL; + ObSEArray range_nodes; + bool use_implicit_cast_feature = true; + if (OB_LIKELY(l_expr.get_expr_type() == T_FUN_SYS_NVL && + r_expr.is_const_expr())) { + nvl_expr = static_cast(&l_expr); + const_expr = &r_expr; + } else if (OB_LIKELY(r_expr.get_expr_type() == T_FUN_SYS_NVL && + l_expr.is_const_expr())) { + nvl_expr = static_cast(&r_expr); + const_expr = &l_expr; + cmp_type = get_opposite_compare_type(cmp_type); + } + + if (OB_ISNULL(nvl_expr) || OB_ISNULL(const_expr)) { + // do nothing + } else if (OB_UNLIKELY(nvl_expr->get_param_count() != 2) || + OB_ISNULL(nvl_first_expr = nvl_expr->get_param_expr(0)) || + OB_ISNULL(nvl_second_expr = nvl_expr->get_param_expr(1)) || + OB_ISNULL(ctx_.expr_factory_) || + OB_ISNULL(ctx_.session_info_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected nvl expr", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(nvl_first_expr, + nvl_first_expr, + use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (!nvl_first_expr->is_column_ref_expr()) { + // do nothing + } else if (OB_FAIL(gen_column_cmp_node(*nvl_first_expr, + *const_expr, + cmp_type, + result_type, + expr_depth + 1, + T_OP_NSEQ == cmp_type, + cmp_range_node))) { + LOG_WARN("failed to gen column cmp node", K(ret)); + } else if (OB_FALSE_IT(is_precise &= ctx_.cur_is_precise_)) { + } else if (OB_FAIL(ObRawExprUtils::create_double_op_expr(*ctx_.expr_factory_, + ctx_.session_info_, + cmp_type, + cmp_second_expr, + nvl_second_expr, + const_expr))) { + LOG_WARN("failed to create double op expr", K(ret)); + } else if (OB_ISNULL(cmp_second_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null expr", K(cmp_second_expr)); + } else if (OB_FAIL(convert_expr_to_range_node(cmp_second_expr, + cmp_second_node, + 0, + second_is_precise))) { + LOG_WARN("failed to convert expr to range node", K(ret)); + } else if (OB_FALSE_IT(is_precise &= second_is_precise)) { + } else if (OB_FAIL(gen_is_null_range_node(nvl_first_expr, + expr_depth + 1, + is_null_node))) { + LOG_WARN("failed to gen is null expr", K(ret)); + } else if (OB_FALSE_IT(is_precise &= ctx_.cur_is_precise_)) { + } else if (OB_FAIL(range_nodes.push_back(cmp_second_node))) { + LOG_WARN("failed to push back or range nodes", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(is_null_node))) { + LOG_WARN("failed to push back or range nodes", K(ret)); + } else if (OB_FAIL(ObRangeGraphGenerator::and_range_nodes(range_nodes, + ctx_.column_cnt_, + null_and_node))) { + LOG_WARN("failed to and range nodes"); + } else if (OB_FALSE_IT(range_nodes.reuse())) { + } else if (OB_FAIL(range_nodes.push_back(cmp_range_node))) { + LOG_WARN("failed to push back range nodes", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(null_and_node))) { + LOG_WARN("failed to push back range nodes", K(ret)); + } else if (OB_FAIL(ObRangeGraphGenerator::or_range_nodes(*this, + range_nodes, + ctx_.column_cnt_, + range_node))) { + LOG_WARN("failed to or range nodes"); + } else { + ctx_.cur_is_precise_ = is_precise; + ctx_.refresh_max_offset_ = true; + } + + if (OB_SUCC(ret) && nullptr == range_node) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(always_true, range_node))) { + LOG_WARN("failed to generate always true or fasle node", K(always_true)); + } + } + return ret; +} + +int64_t ObExprRangeConverter::get_expr_category(ObItemType type) +{ + int64_t catagory = RANGE_EXPR_OTHER; + if (T_OP_EQ == type || + T_OP_NSEQ == type || + T_OP_IS == type) { + catagory = RANGE_EXPR_EQUAL; + } else if (IS_BASIC_CMP_OP(type)) { + catagory = RANGE_EXPR_CMP; + } else if (T_OP_IN == type) { + catagory = RANGE_EXPR_IN; + } else if (T_OP_NE == type || + T_OP_NOT_BTW == type) { + catagory = RANGE_EXPR_NO_EQUAL; + } else if (T_OP_NOT_IN == type) { + catagory = RANGE_EXPR_NOT_IN; + } else { + catagory = RANGE_EXPR_OTHER; + } + return catagory; +} + +struct RangeExprCategoryCmp +{ + + inline bool operator()(ObRawExpr *left, ObRawExpr *right) + { + bool bret = false; + if (left != nullptr && right != nullptr) { + int64_t l_catagory = ObExprRangeConverter::get_expr_category(left->get_expr_type()); + int64_t r_catagory = ObExprRangeConverter::get_expr_category(right->get_expr_type()); + if (l_catagory == r_catagory && + (l_catagory == RANGE_EXPR_IN || + r_catagory == RANGE_EXPR_NOT_IN)) { + if (left->get_param_expr(1) != nullptr & + right->get_param_expr(1) != nullptr) { + bret = left->get_param_expr(1)->get_param_count() < + right->get_param_expr(1)->get_param_count(); + } + } else { + bret = l_catagory < r_catagory; + } + } + return bret; + } +}; + +int ObExprRangeConverter::sort_range_exprs(const ObIArray &range_exprs, + ObIArray &out_range_exprs) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(out_range_exprs.assign(range_exprs))) { + LOG_WARN("failed to assign range exprs", K(ret)); + } else if (!range_exprs.empty()) { + lib::ob_sort(&out_range_exprs.at(0), &out_range_exprs.at(0) + out_range_exprs.count(), + RangeExprCategoryCmp()); + } + return ret; +} + +int ObExprRangeConverter::try_wrap_lob_with_substr(const ObRawExpr *expr, + const ObRangeColumnMeta *column_meta, + const ObRawExpr *&out_expr) +{ + int ret = OB_SUCCESS; + ObOpRawExpr *substr_expr = NULL; + ObConstRawExpr *pos_expr = NULL; + ObConstRawExpr *truncated_len_expr = NULL; + int64_t truncated_str_len = 0; + out_expr = expr; + if (OB_ISNULL(expr) || + OB_ISNULL(column_meta)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(expr), K(column_meta)); + } else if (!expr->get_result_type().is_lob_storage() || + !column_meta->column_type_.is_string_type() || + column_meta->column_type_.get_accuracy().get_length() < 0) { + // do nothing + } else if (OB_FAIL(ctx_.expr_factory_->create_raw_expr(T_FUN_SYS_SUBSTR, substr_expr))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_ISNULL(substr_expr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate expr", K(substr_expr)); + } else if (OB_FALSE_IT(truncated_str_len = + column_meta->column_type_.get_accuracy().get_length() + 1)) { + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + 1, // const value + pos_expr))) { + LOG_WARN("Failed to build const expr", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_.expr_factory_, + ObIntType, + truncated_str_len, + truncated_len_expr))) { + LOG_WARN("failed to build const int expr", K(ret)); + } else if (OB_FAIL(substr_expr->add_param_expr(const_cast(expr)))) { + LOG_WARN("failed to set param for substr", KPC(expr)); + } else if (OB_FAIL(substr_expr->add_param_expr(pos_expr))) { + LOG_WARN("failed to set param for substr", KPC(pos_expr)); + } else if (OB_FAIL(substr_expr->add_param_expr(truncated_len_expr))) { + LOG_WARN("failed to set param for substr"); + } else if (OB_FAIL(substr_expr->formalize(ctx_.session_info_))) { + LOG_WARN("failed to formalize expr"); + } else { + out_expr = substr_expr; + ctx_.cur_is_precise_ = false; + } + return ret; +} + +int ObExprRangeConverter::set_column_flags(int64_t key_idx, ObItemType type) +{ + int ret = OB_SUCCESS; + int64_t catagory = get_expr_category(type); + if (OB_UNLIKELY(key_idx >= ctx_.column_flags_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected key idx", K(ret)); + } else { + ctx_.column_flags_[key_idx] |= catagory; + } + return ret; +} + +int ObExprRangeConverter::get_domain_extra_item(const common::ObDomainOpType op_type, + const ObRawExpr *expr, + const ObConstRawExpr *&extra_item) +{ + int ret = OB_SUCCESS; + extra_item = NULL; + if (op_type == ObDomainOpType::T_GEO_DWITHIN || + op_type == ObDomainOpType::T_GEO_RELATE) { + if (expr->get_param_count() != 3) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid param num", K(expr->get_param_count())); + } else { + extra_item = static_cast(expr->get_param_expr(2)); + if (OB_ISNULL(extra_item)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid param val", K(ret)); + } + } + } + return ret; +} + +int ObExprRangeConverter::fill_range_node_for_geo_node(const int64_t key_idx, + common::ObDomainOpType geo_type, + uint32_t srid, + const int64_t start_val_idx, + const int64_t end_val_idx, + ObRangeNode &range_node) const +{ + int ret = OB_SUCCESS; + OB_ASSERT(key_idx < ctx_.column_cnt_); + range_node.min_offset_ = key_idx; + range_node.max_offset_ = key_idx; + + range_node.domain_extra_.domain_releation_type_ = (int32_t)geo_type; + range_node.is_domain_node_ = 1; + + range_node.include_start_ = true; + range_node.include_end_ = true; + range_node.domain_extra_.srid_ = srid; + + for (int64_t i = 0; i < key_idx; ++i) { + range_node.start_keys_[i] = OB_RANGE_EMPTY_VALUE; + range_node.end_keys_[i] = OB_RANGE_EMPTY_VALUE; + } + + range_node.start_keys_[key_idx] = start_val_idx; + range_node.end_keys_[key_idx] = end_val_idx; + + for (int64_t i = key_idx + 1; i < ctx_.column_cnt_; ++i) { + range_node.start_keys_[i] = OB_RANGE_MIN_VALUE; + range_node.end_keys_[i] = OB_RANGE_MAX_VALUE; + } + return ret; +} + +int ObExprRangeConverter::convert_geo_expr(const ObRawExpr *geo_expr, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + UNUSED(expr_depth); + if (OB_ISNULL(geo_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else { + const ObRawExpr *expr = ObRawExprUtils::skip_inner_added_expr(geo_expr); + const ObRawExpr *l_expr = expr->get_param_expr(0); + const ObRawExpr *r_expr = expr->get_param_expr(1); + common::ObDomainOpType op_type; + const ObConstRawExpr *extra_item = NULL; + const ObRawExpr *const_item = NULL; + const ObColumnRefRawExpr *column_item = NULL; + if (OB_ISNULL(l_expr) || OB_ISNULL(r_expr) || + OB_ISNULL(ctx_.geo_column_id_map_)) { + // do nothing + } else if (l_expr->has_flag(CNT_COLUMN) && r_expr->has_flag(CNT_COLUMN)) { + // do nothing + } else if (l_expr->has_flag(IS_DYNAMIC_PARAM) && r_expr->has_flag(IS_DYNAMIC_PARAM)) { + // do nothing + } else if (!l_expr->has_flag(CNT_COLUMN) && !r_expr->has_flag(CNT_COLUMN)) { + // do nothing + } else { + op_type = ObQueryRange::get_geo_relation(expr->get_expr_type()); + if (OB_UNLIKELY(r_expr->has_flag(CNT_COLUMN))) { + column_item = ObRawExprUtils::get_column_ref_expr_recursively(r_expr); + const_item = l_expr; + } else if (l_expr->has_flag(CNT_COLUMN)) { + column_item = ObRawExprUtils::get_column_ref_expr_recursively(l_expr); + const_item = r_expr; + op_type = (ObDomainOpType::T_GEO_COVERS == op_type ? ObDomainOpType::T_GEO_COVEREDBY : + (ObDomainOpType::T_GEO_COVEREDBY == op_type ? ObDomainOpType::T_GEO_COVERS : op_type)); + } + + if (OB_ISNULL(column_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to find column item", K(ret), KPC(r_expr), KPC(l_expr)); + } else if (column_item->get_data_type() != ObObjType::ObGeometryType) { + // do nothing + } else if (OB_FAIL(get_domain_extra_item(op_type, expr, extra_item))) { + LOG_WARN("failed to get dwithin item", K(ret)); + } else if (OB_FAIL(get_geo_range_node(column_item, + op_type, + const_item, + extra_item, + range_node))) { + LOG_WARN("failed to get geo range node", K(ret)); + } else if (nullptr != range_node) { + ctx_.contail_geo_filters_ = true; + } + } + } + + if (OB_SUCC(ret) && nullptr == range_node) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node", K(ret)); + } + } + return ret; +} + +int ObExprRangeConverter::get_geo_range_node(const ObColumnRefRawExpr *column_expr, + common::ObDomainOpType geo_type, + const ObRawExpr* wkb_expr, + const ObRawExpr *distance_expr, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + bool is_cellid_col = false; + ObGeoColumnInfo column_info; + int64_t key_idx = -1; + int64_t wkb_val = -1; + int64_t distance_val = -1; + bool is_valid = false; + range_node = NULL; + bool is_geo_type = ObRangeGenerator::is_geo_type(geo_type); + if (OB_ISNULL(column_expr) || + OB_ISNULL(wkb_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(ctx_.geo_column_id_map_), K(column_expr), + K(wkb_expr), K(lbt())); + } else { + if (is_geo_type) { + if (OB_ISNULL(ctx_.geo_column_id_map_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ctx_.geo_column_id_map_)); + } else if (OB_FAIL(ctx_.geo_column_id_map_->get_refactored(column_expr->get_column_id(), + column_info))) { + if (OB_NOT_INIT == ret || OB_HASH_NOT_EXIST == ret) { + ret = OB_SUCCESS; + } else { + LOG_WARN("failed to get from geo column id map", K(ret)); + } + } else { + is_cellid_col = true; + } + } else { + column_info.srid_ = 0; + column_info.cellid_columnId_ = column_expr->get_column_id(); + } + + if (OB_SUCC(ret)) { + uint64_t column_id = is_cellid_col ? column_info.cellid_columnId_ : column_expr->get_column_id(); + bool can_extract_range = false; + if (!is_range_key(column_id, key_idx)) { + // do nothing + } else if (OB_FAIL(check_calculable_expr_valid(wkb_expr, is_valid))) { + LOG_WARN("failed to get calculable expr val"); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(get_final_expr_idx(wkb_expr, nullptr, wkb_val))) { + LOG_WARN("failed to get final expr idx"); + } else if (geo_type == ObDomainOpType::T_GEO_DWITHIN || + geo_type == ObDomainOpType::T_GEO_RELATE) { + if (OB_ISNULL(distance_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(check_calculable_expr_valid(distance_expr, is_valid))) { + LOG_WARN("failed to check calculable expr valid", K(ret)); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(get_final_expr_idx(distance_expr, nullptr, distance_val))) { + LOG_WARN("failed to get final expr idx", K(ret)); + } else { + can_extract_range = true; + } + } else { + can_extract_range = true; + } + + if (OB_FAIL(ret)) { + } else if (!can_extract_range) { + // do nothing + } else if (OB_FAIL(alloc_range_node(range_node))) { + LOG_WARN("failed to alloc range node", K(ret)); + } else if (OB_FAIL(fill_range_node_for_geo_node(key_idx, + geo_type, + column_info.srid_, + wkb_val, + distance_val, + *range_node))) { + LOG_WARN("failed to fill range node for geo node", K(ret)); + } else { + ctx_.cur_is_precise_ = false; + } + } + + } + return ret; +} + +int ObExprRangeConverter::get_implicit_cast_range(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + const ObRawExpr *inner_expr = nullptr; + const ObRawExpr *const_expr = nullptr; + int64_t key_idx = 0; + bool can_extract = false; + if (l_expr.get_expr_type() == T_FUN_SYS_CAST && r_expr.is_const_expr()) { + inner_expr = l_expr.get_param_expr(0); + const_expr = &r_expr; + } else if (r_expr.get_expr_type() == T_FUN_SYS_CAST && l_expr.is_const_expr()) { + inner_expr = r_expr.get_param_expr(0); + const_expr = &l_expr; + cmp_type = get_opposite_compare_type(cmp_type); + } + + if (OB_SUCC(ret) && OB_NOT_NULL(inner_expr)) { + if (!inner_expr->has_flag(IS_COLUMN)) { + // do nothing + } else if (!is_range_key(static_cast(inner_expr)->get_column_id(), + key_idx)) { + // do nothing + } else if (OB_FAIL(can_extract_implicit_cast_range(*static_cast(inner_expr), + *const_expr, + can_extract))) { + LOG_WARN("failed to check can extract implicit range", K(ret)); + } else if (!can_extract) { + // do nothing + } else if (OB_FAIL(gen_implicit_cast_range(static_cast(inner_expr), + const_expr, + cmp_type, + result_type, + expr_depth, + range_node))) { + LOG_WARN("failed to get implicit range", K(ret)); + } + } + + if (OB_SUCC(ret) && nullptr == range_node) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node", K(ret)); + } + } + return ret; +} + +int ObExprRangeConverter::gen_implicit_cast_range(const ObColumnRefRawExpr *column_expr, + const ObRawExpr *const_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + const ObRawExpr *start_expr = nullptr; + const ObRawExpr *end_expr = nullptr; + ObSEArray range_nodes; + ObArenaAllocator alloc("ExprRangeAlloc", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObExprResType calc_type(alloc); + if (OB_ISNULL(column_expr) || + OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexptected null", K(ret), K(column_expr), K(const_expr)); + } else if (T_OP_EQ == cmp_type || T_OP_NSEQ == cmp_type) { + ObRangeNode *start_range = nullptr; + ObRangeNode *end_range = nullptr; + bool is_precise = true; + if (OB_FAIL(build_implicit_cast_range_expr(column_expr, + const_expr, + cmp_type, + true, + start_expr))) { + LOG_WARN("failed to build double to int expr", K(ret)); + } else if (OB_FAIL(build_implicit_cast_range_expr(column_expr, + const_expr, + cmp_type, + false, + end_expr))) { + LOG_WARN("failed to build double to int expr", K(ret)); + } else if (OB_FALSE_IT(calc_type.set_calc_meta(start_expr->get_result_type().get_obj_meta()))) { + } else if (OB_FAIL(gen_column_cmp_node(*column_expr, + *start_expr, + T_OP_GE, + calc_type, + expr_depth, + T_OP_NSEQ == cmp_type, + start_range))) { + LOG_WARN("failed to get basic range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(start_range))) { + LOG_WARN("failed to push back and range nodes", K(ret)); + } else if (OB_FAIL(gen_column_cmp_node(*column_expr, + *end_expr, + T_OP_LE, + calc_type, + expr_depth, + T_OP_NSEQ == cmp_type, + end_range))) { + LOG_WARN("failed to get basic range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(end_range))) { + LOG_WARN("failed to push back and range node", K(ret)); + } else if (OB_FAIL(ObRangeGraphGenerator::and_range_nodes(range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to and range nodes"); + } else if (OB_FAIL(set_extract_implicit_is_precise(*column_expr, + *const_expr, + cmp_type, + is_precise))) { + LOG_WARN("failed to set extract implicit is precise", K(ret)); + } else if (!is_precise) { + ctx_.cur_is_precise_ = false; + } + } else if (T_OP_GT == cmp_type || + T_OP_GE == cmp_type || + T_OP_LT == cmp_type || + T_OP_LE == cmp_type) { + if (T_OP_GT == cmp_type) { + cmp_type = T_OP_GE; + } else if (T_OP_LT == cmp_type) { + cmp_type = T_OP_LE; + } + if (OB_FAIL(build_implicit_cast_range_expr(column_expr, + const_expr, + cmp_type, + T_OP_GE == cmp_type, + start_expr))) { + LOG_WARN("failed to build double to int expr", K(ret)); + } else if (OB_FALSE_IT(calc_type.set_calc_meta(start_expr->get_result_type().get_obj_meta()))) { + } else if (OB_FAIL(gen_column_cmp_node(*column_expr, + *start_expr, + cmp_type, + calc_type, + expr_depth, + false, + range_node))) { + LOG_WARN("failed to get basic range node", K(ret)); + } else { + ctx_.cur_is_precise_ = false; + } + } + return ret; +} + +int ObExprRangeConverter::build_double_to_int_expr(const ObRawExpr *double_expr, + bool is_start, + ObItemType cmp_type, + bool is_unsigned, + bool is_decimal, + const ObRawExpr *&out_expr) +{ + int ret = OB_SUCCESS; + ObSysFunRawExpr *inner_double_to_int = NULL; + out_expr = NULL; + int64_t extra = 0; + bool is_equal = cmp_type == T_OP_EQ || cmp_type == T_OP_NSEQ; + if (OB_ISNULL(double_expr) || OB_ISNULL(ctx_.expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(double_expr), K(ctx_.expr_factory_)); + } else if (OB_FAIL(ctx_.expr_factory_->create_raw_expr(T_FUN_SYS_INNER_DOUBLE_TO_INT, + inner_double_to_int))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_ISNULL(inner_double_to_int)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate expr", K(out_expr)); + } else if (is_start && OB_FALSE_IT(extra |= 1)) { + } else if (is_equal && OB_FALSE_IT(extra |= 2)) { + } else if (is_unsigned && OB_FALSE_IT(extra |= 4)) { + } else if (is_decimal && OB_FALSE_IT(extra |= 8)) { + } else if (OB_FAIL(inner_double_to_int->add_param_expr(const_cast(double_expr)))) { + LOG_WARN("failed to add param expr", K(ret)); + } else if (OB_FALSE_IT(inner_double_to_int->set_extra(extra))) { + } else if (OB_FAIL(inner_double_to_int->formalize(ctx_.session_info_))) { + LOG_WARN("failed to formalize expr"); + } else { + out_expr = inner_double_to_int; + } + return ret; +} + +int ObExprRangeConverter::get_row_cmp_node(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + if(OB_UNLIKELY(l_expr.get_param_count() != r_expr.get_param_count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected param count", K(l_expr), K(r_expr)); + } else { + ObSEArray column_exprs; + ObSEArray const_exprs; + ObSEArray calc_types; + ObSEArray implicit_cast_idxs; + bool can_reverse = true; + bool is_reverse = false; + bool use_implicit_cast_feature = true; + for (int64_t i = 0; OB_SUCC(ret) && i < l_expr.get_param_count(); ++i) { + const ObRawExpr* l_param = l_expr.get_param_expr(i); + const ObRawExpr* r_param = r_expr.get_param_expr(i); + const ObExprCalcType* calc_type = &result_type.get_row_calc_cmp_types().at(i); + const ObColumnRefRawExpr* column_expr = nullptr; + const ObRawExpr* const_expr = nullptr; + bool is_implicit_cast = false; + if (OB_ISNULL(l_param) || OB_ISNULL(r_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(l_param), K(r_param)); + } else if (l_param->get_expr_type() != T_FUN_SYS_INNER_ROW_CMP_VALUE && + OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(l_param, l_param, use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (r_param->get_expr_type() != T_FUN_SYS_INNER_ROW_CMP_VALUE && + OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(r_param, r_param, use_implicit_cast_feature))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (l_param->has_flag(IS_COLUMN) && r_param->is_const_expr()) { + if (T_OP_EQ == cmp_type && T_OP_NSEQ == cmp_type) { + column_expr = static_cast(l_param); + const_expr = r_param; + } else if (can_reverse) { + can_reverse = false; + column_expr = static_cast(l_param); + const_expr = r_param; + } else if (!is_reverse) { + column_expr = static_cast(l_param); + const_expr = r_param; + } + } else if (r_param->has_flag(IS_COLUMN) && l_param->is_const_expr()) { + if (T_OP_EQ == cmp_type && T_OP_NSEQ == cmp_type) { + column_expr = static_cast(r_param); + const_expr = l_param; + } else if (can_reverse) { + can_reverse = false; + is_reverse = true; + column_expr = static_cast(r_param); + const_expr = l_param; + cmp_type = get_opposite_compare_type(cmp_type); + } else if (is_reverse) { + column_expr = static_cast(r_param); + const_expr = l_param; + } + } else if (!(ObSQLUtils::is_min_cluster_version_ge_425_or_435() && + ObSQLUtils::is_opt_feature_version_ge_425_or_435(ctx_.optimizer_features_enable_version_))) { + // do nothing + } else if (OB_FALSE_IT(l_param = l_expr.get_param_expr(i)) || + OB_FALSE_IT(r_param = r_expr.get_param_expr(i))) { + } else if (l_param->get_expr_type() == T_FUN_SYS_CAST && r_param->is_const_expr()) { + l_param = l_param->get_param_expr(0); + bool can_extract = false; + if (!l_param->has_flag(IS_COLUMN)) { + // do nothing + } else if (OB_FAIL(can_extract_implicit_cast_range(*static_cast(l_param), + *r_param, + can_extract))) { + LOG_WARN("failed to check can extract implicit cast range", K(ret)); + } else if (can_extract) { + is_implicit_cast = true; + if (T_OP_EQ == cmp_type && T_OP_NSEQ == cmp_type) { + column_expr = static_cast(l_param); + const_expr = r_param; + } else if (can_reverse) { + can_reverse = false; + column_expr = static_cast(l_param); + const_expr = r_param; + } else if (!is_reverse) { + column_expr = static_cast(l_param); + const_expr = r_param; + } else { + is_implicit_cast = false; + } + } + } else if (r_param->get_expr_type() == T_FUN_SYS_CAST && l_param->is_const_expr()) { + bool can_extract = false; + r_param = r_param->get_param_expr(0); + if (!r_param->has_flag(IS_COLUMN)) { + // do nothing + } else if (OB_FAIL(can_extract_implicit_cast_range(*static_cast(r_param), + *l_param, + can_extract))) { + LOG_WARN("failed to check can extract implicit cast range", K(ret)); + } else if (can_extract) { + is_implicit_cast = true; + if (T_OP_EQ == cmp_type && T_OP_NSEQ == cmp_type) { + column_expr = static_cast(r_param); + const_expr = l_param; + } else if (can_reverse) { + can_reverse = false; + is_reverse = true; + column_expr = static_cast(r_param); + const_expr = l_param; + cmp_type = get_opposite_compare_type(cmp_type); + } else if (is_reverse) { + column_expr = static_cast(r_param); + const_expr = l_param; + } else { + is_implicit_cast = false; + } + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(column_exprs.push_back(column_expr))) { + LOG_WARN("failed to push back array"); + } else if (OB_FAIL(const_exprs.push_back(const_expr))) { + LOG_WARN("failed to push back array"); + } else if (OB_FAIL(calc_types.push_back(calc_type))) { + LOG_WARN("failed to push back array"); + } else if (is_implicit_cast && OB_FAIL(implicit_cast_idxs.push_back(i))) { + LOG_WARN("failed to push back array"); + } + } + } + if (OB_FAIL(ret)) { + } else if (implicit_cast_idxs.empty()) { + if (OB_FAIL(gen_row_column_cmp_node(column_exprs, + const_exprs, + cmp_type, + calc_types, + expr_depth, + l_expr.get_param_count(), + T_OP_NSEQ == cmp_type, + range_node))) { + LOG_WARN("failed to gen row column cmp node", K(ret)); + } + } else { + if (OB_FAIL(gen_row_implicit_cast_range(column_exprs, + const_exprs, + cmp_type, + calc_types, + implicit_cast_idxs, + expr_depth, + l_expr.get_param_count(), + range_node))) { + LOG_WARN("failed to get row real to int range", K(ret)); + } + } + } + return ret; +} + +int ObExprRangeConverter::gen_row_implicit_cast_range(const ObIArray &column_exprs, + const ObIArray &const_exprs, + ObItemType cmp_type, + const ObIArray &calc_types, + ObIArray &implicit_cast_idxs, + int64_t expr_depth, + int64_t row_dim, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + ObSEArray ordered_column_exprs; + ObSEArray ordered_const_exprs; + ObSEArray ordered_calc_types; + ObSEArray range_nodes; + ObArenaAllocator alloc("ExprRangeAlloc", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + if (OB_UNLIKELY(column_exprs.count() != const_exprs.count()) || + OB_UNLIKELY(column_exprs.count() != calc_types.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected param count", K(column_exprs), K(const_exprs), K(calc_types)); + } else if (T_OP_EQ == cmp_type || T_OP_NSEQ == cmp_type) { + ObSEArray key_idxs; + ObSEArray val_idxs; + ObSEArray cast_idxs; + ObSEArray cast_origin_const_exprs; + ObSEArray cast_calc_types; + bool cur_is_precise = true; + int64_t key_idx = -1; + int64_t min_offset = ctx_.column_cnt_; + for (int64_t i = 0; OB_SUCC(ret) && i < column_exprs.count(); ++i) { + const ObColumnRefRawExpr* column_expr = column_exprs.at(i); + if (OB_NOT_NULL(column_expr)) { + if (!is_range_key(column_expr->get_column_id(), key_idx)) { + // do nothing + } else if (ObOptimizerUtil::find_item(key_idxs, key_idx)) { + // do nothing + } else if (OB_FAIL(key_idxs.push_back(key_idx))) { + LOG_WARN("failed to push back key idx", K(ret)); + } else if (OB_FAIL(val_idxs.push_back(i))) { + LOG_WARN("failed to push back val idx", K(ret)); + } else if (key_idx < min_offset) { + min_offset = key_idx; + } + } + } + for (int64_t i = min_offset; OB_SUCC(ret) && i < ctx_.column_cnt_; ++i) { + int64_t idx = -1; + if (ObOptimizerUtil::find_item(key_idxs, i, &idx)) { + int64_t val_idx = val_idxs.at(idx); + bool is_precise = true; + if (OB_FAIL(ordered_column_exprs.push_back(column_exprs.at(val_idx)))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_FAIL(ordered_const_exprs.push_back(const_exprs.at(val_idx)))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_FAIL(ordered_calc_types.push_back(calc_types.at(val_idx)))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (ObOptimizerUtil::find_item(implicit_cast_idxs, val_idx)) { + ObExprResType *res_type = nullptr; + if (OB_FAIL(set_extract_implicit_is_precise(*column_exprs.at(val_idx), + *const_exprs.at(val_idx), + cmp_type, + is_precise))) { + LOG_WARN("failed to set extract implicit is precise", K(ret)); + } else if (OB_FAIL(cast_idxs.push_back(ordered_const_exprs.count() - 1))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_FAIL(cast_origin_const_exprs.push_back(const_exprs.at(val_idx)))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_ISNULL(res_type = (ObExprResType*) alloc.alloc(sizeof(ObExprResType)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc res type", K(ret)); + } else { + res_type = new(res_type) ObExprResType(alloc); + if (OB_FAIL(cast_calc_types.push_back(res_type))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (!is_precise) { + cur_is_precise = false; + } + } + } + } else { + break; + } + } + if (OB_FAIL(ret)) { + } else if (ordered_column_exprs.empty()) { + // do nothing + } else if (cast_idxs.empty()) { + if (OB_FAIL(gen_row_column_cmp_node(ordered_column_exprs, + ordered_const_exprs, + cmp_type, + ordered_calc_types, + expr_depth, + row_dim, + T_OP_NSEQ == cmp_type, + range_node))) { + LOG_WARN("failed to gen row column cmp node", K(ret)); + } + } else { + ObRangeNode *start_range = nullptr; + ObRangeNode *end_range = nullptr; + for (int64_t i = 0; OB_SUCC(ret) && i < cast_idxs.count(); ++i) { + int64_t ordered_idx = cast_idxs.at(i); + const ObRawExpr *out_expr = nullptr; + if (OB_FAIL(build_implicit_cast_range_expr(ordered_column_exprs.at(ordered_idx), + cast_origin_const_exprs.at(i), + cmp_type, + true, + out_expr))) { + LOG_WARN("failed to build implicit cast range expr", K(ret)); + } else { + cast_calc_types.at(i)->set_calc_meta(out_expr->get_result_type().get_obj_meta()); + ordered_calc_types.at(ordered_idx) = &cast_calc_types.at(i)->get_calc_meta(); + ordered_const_exprs.at(ordered_idx) = out_expr; + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(gen_row_column_cmp_node(ordered_column_exprs, + ordered_const_exprs, + T_OP_GE, + ordered_calc_types, + expr_depth, + row_dim, + T_OP_NSEQ == cmp_type, + start_range))) { + LOG_WARN("failed to gen row column cmp node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(start_range))) { + LOG_WARN("failed to push back array", K(ret)); + } + + for (int64_t i = 0; OB_SUCC(ret) && i < cast_idxs.count(); ++i) { + int64_t ordered_idx = cast_idxs.at(i); + const ObRawExpr *out_expr = nullptr; + if (OB_FAIL(build_implicit_cast_range_expr(ordered_column_exprs.at(ordered_idx), + cast_origin_const_exprs.at(i), + cmp_type, + false, + out_expr))) { + LOG_WARN("failed to build implicit cast range expr", K(ret)); + } else { + cast_calc_types.at(i)->set_calc_meta(out_expr->get_result_type().get_obj_meta()); + ordered_calc_types.at(ordered_idx) = &cast_calc_types.at(i)->get_calc_meta(); + ordered_const_exprs.at(ordered_idx) = out_expr; + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(gen_row_column_cmp_node(ordered_column_exprs, + ordered_const_exprs, + T_OP_LE, + ordered_calc_types, + expr_depth, + row_dim, + T_OP_NSEQ == cmp_type, + end_range))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(end_range))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_FAIL(ObRangeGraphGenerator::and_range_nodes(range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to and range nodes"); + } else if (!cur_is_precise) { + ctx_.cur_is_precise_ = false; + } + } + + for (int64_t i = 0; i < cast_calc_types.count(); ++i) { + if (OB_NOT_NULL(cast_calc_types.at(i))) { + cast_calc_types.at(i)->~ObExprResType(); + } + } + } else if (T_OP_GT == cmp_type || + T_OP_GE == cmp_type || + T_OP_LT == cmp_type || + T_OP_LE == cmp_type) { + bool is_start = false; + bool check_next = true; + ObSEArray cache_calc_types; + if (!implicit_cast_idxs.empty()) { + if (T_OP_GT == cmp_type) { + cmp_type = T_OP_GE; + } else if (T_OP_LT == cmp_type) { + cmp_type = T_OP_LE; + } + } + is_start = (T_OP_GE == cmp_type); + for (int64_t i = 0; OB_SUCC(ret) && check_next && i < column_exprs.count(); ++i) { + const ObRawExpr *out_expr = nullptr; + ObExprResType *res_type = nullptr; + if (OB_ISNULL(column_exprs.at(i)) || OB_ISNULL(const_exprs.at(i)) || + OB_ISNULL(calc_types.at(i))) { + check_next = false; + } else if (OB_FAIL(ordered_column_exprs.push_back(column_exprs.at(i)))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_FAIL(ordered_const_exprs.push_back(const_exprs.at(i)))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_FAIL(ordered_calc_types.push_back(calc_types.at(i)))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (ObOptimizerUtil::find_item(implicit_cast_idxs, i)) { + if (OB_FAIL(build_implicit_cast_range_expr(column_exprs.at(i), + const_exprs.at(i), + cmp_type, + is_start, + out_expr))) { + LOG_WARN("failed to build implicit cast range expr", K(ret)); + } else if (OB_ISNULL(res_type = (ObExprResType*) alloc.alloc(sizeof(ObExprResType)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc res type", K(ret)); + } else { + res_type = new(res_type) ObExprResType(alloc); + res_type->set_calc_meta(out_expr->get_result_type().get_obj_meta()); + ordered_calc_types.at(i) = &res_type->get_calc_meta(); + ordered_const_exprs.at(i) = out_expr; + if (OB_FAIL(cache_calc_types.push_back(res_type))) { + LOG_WARN("failed to push back array", K(ret)); + } + } + } + } + if (OB_SUCC(ret) && OB_FAIL(gen_row_column_cmp_node(ordered_column_exprs, + ordered_const_exprs, + cmp_type, + ordered_calc_types, + expr_depth, + row_dim, + false, + range_node))) { + LOG_WARN("faield to gen row column cmp node", K(ret)); + } else { + ctx_.cur_is_precise_ = false; + } + + for (int64_t i = 0; i < cache_calc_types.count(); ++i) { + if (OB_NOT_NULL(cache_calc_types.at(i))) { + cache_calc_types.at(i)->~ObExprResType(); + } + } + } + if (OB_SUCC(ret) && OB_UNLIKELY(nullptr == range_node)) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node", K(ret)); + } + } + return ret; +} + +int ObExprRangeConverter::build_decimal_to_year_expr(const ObRawExpr *decimal_expr, + bool is_start, + ObItemType cmp_type, + const ObRawExpr *&out_expr) +{ + int ret = OB_SUCCESS; + ObSysFunRawExpr *inner_decimal_to_year = NULL; + out_expr = NULL; + int64_t extra = 0; + bool is_equal = cmp_type == T_OP_EQ || cmp_type == T_OP_NSEQ; + if (OB_ISNULL(decimal_expr) || OB_ISNULL(ctx_.expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(decimal_expr), K(ctx_.expr_factory_)); + } else if (OB_FAIL(ctx_.expr_factory_->create_raw_expr(T_FUN_SYS_INNER_DECIMAL_TO_YEAR, + inner_decimal_to_year))) { + LOG_WARN("failed to create a new expr", K(ret)); + } else if (OB_ISNULL(inner_decimal_to_year)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate expr", K(out_expr)); + } else if (is_start && OB_FALSE_IT(extra |= 1)) { + } else if (is_equal && OB_FALSE_IT(extra |= 2)) { + } else if (OB_FAIL(inner_decimal_to_year->add_param_expr(const_cast(decimal_expr)))) { + LOG_WARN("failed to add param expr", K(ret)); + } else if (OB_FALSE_IT(inner_decimal_to_year->set_extra(extra))) { + } else if (OB_FAIL(inner_decimal_to_year->formalize(ctx_.session_info_))) { + LOG_WARN("failed to formalize expr"); + } else { + out_expr = inner_decimal_to_year; + } + return ret; +} + +int ObExprRangeConverter::build_implicit_cast_range_expr(const ObColumnRefRawExpr *column_expr, + const ObRawExpr *const_expr, + ObItemType cmp_type, + bool is_start, + const ObRawExpr *&out_expr) +{ + int ret = OB_SUCCESS; + ObObjTypeClass column_tc = ObNullTC; + ObObjTypeClass const_tc = ObNullTC; + if (OB_ISNULL(column_expr) || + OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(column_expr), K(const_expr)); + } else { + column_tc = column_expr->get_result_type().get_type_class(); + const_tc = const_expr->get_result_type().get_type_class(); + if (ObIntTC == column_tc && + (const_tc == ObDoubleTC || const_tc == ObFloatTC)) { + if (OB_FAIL(build_double_to_int_expr(const_expr, + is_start, + cmp_type, + false, + false, + out_expr))) { + LOG_WARN("failed to build double to int expr", K(ret)); + } + } else if (ObUIntTC == column_tc && + (const_tc == ObDoubleTC || const_tc == ObFloatTC)) { + if (OB_FAIL(build_double_to_int_expr(const_expr, + is_start, + cmp_type, + true, + false, + out_expr))) { + LOG_WARN("failed to build double to int expr", K(ret)); + } + } else if (ObNumberTC == column_tc && + (const_tc == ObDoubleTC || const_tc == ObFloatTC)) { + if (OB_FAIL(build_double_to_int_expr(const_expr, + is_start, + cmp_type, + false, + true, + out_expr))) { + LOG_WARN("failed to build double to int expr", K(ret)); + } + } else if (ObYearTC == column_tc && + (const_tc == ObNumberTC || const_tc == ObIntTC || const_tc == ObDecimalIntTC)) { + if (OB_FAIL(build_decimal_to_year_expr(const_expr, + is_start, + cmp_type, + out_expr))) { + LOG_WARN("failed to build decimal to year expr", K(ret)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("not support implicit cast range extract", K(ret), K(column_tc), K(const_tc)); + } + } + return ret; +} + +int ObExprRangeConverter::can_extract_implicit_cast_range(const ObColumnRefRawExpr &column_expr, + const ObRawExpr &const_expr, + bool &can_extract) +{ + int ret = OB_SUCCESS; + ObObjTypeClass column_tc = column_expr.get_result_type().get_type_class(); + ObObjTypeClass const_tc = const_expr.get_result_type().get_type_class(); + can_extract = false; + if (lib::is_oracle_mode()) { + can_extract = false; + } else if ((ObIntTC == column_tc || ObUIntTC == column_tc) && + (const_tc == ObDoubleTC || const_tc == ObFloatTC)) { + can_extract = true; + } else if (ObNumberTC == column_tc && + (const_tc == ObDoubleTC || const_tc == ObFloatTC)) { + can_extract = true; + } else if (ObYearTC == column_tc && + (const_tc == ObNumberTC || const_tc == ObIntTC || const_tc == ObDecimalIntTC)) { + can_extract = true; + } + return ret; +} + +int ObExprRangeConverter::check_can_use_range_get(const ObRawExpr &const_expr, + const ObRangeColumnMeta &column_meta) +{ + int ret = OB_SUCCESS; + ObObjTypeClass child_tc = column_meta.column_type_.get_type_class(); + const ObExprResType &dst_type = const_expr.get_result_type(); + ObObjTypeClass dst_tc = dst_type.get_type_class(); + ObAccuracy dst_acc = dst_type.get_accuracy(); + if ((ObFloatTC == child_tc || ObDoubleTC == child_tc) && + (ObFloatTC == dst_tc || ObDoubleTC == dst_tc)) { + ObAccuracy lossless_acc = column_meta.column_type_.get_accuracy(); + if (!(child_tc == dst_tc && + dst_acc.get_scale() == lossless_acc.get_scale())) { + ctx_.can_range_get_ = false; + } + } + return ret; +} + +int ObExprRangeConverter::set_extract_implicit_is_precise(const ObColumnRefRawExpr &column_expr, + const ObRawExpr &const_expr, + ObItemType cmp_type, + bool &is_precise) +{ + int ret = OB_SUCCESS; + ObObjTypeClass column_tc = column_expr.get_result_type().get_type_class(); + ObObjTypeClass const_tc = const_expr.get_result_type().get_type_class(); + is_precise = true; + if (lib::is_oracle_mode()) { + // do nothing + } else if (cmp_type == T_OP_EQ || cmp_type == T_OP_NSEQ) { + if (ObNumberTC == column_tc && + (const_tc == ObDoubleTC || const_tc == ObFloatTC)) { + is_precise = false; + } + } else { + is_precise = false; + } + return ret; +} + +int ObExprRangeConverter::convert_domain_expr(const ObRawExpr *domain_expr, + int64_t expr_depth, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + range_node = NULL; + const ObRawExpr *expr = NULL; + bool need_extract = false; + common::ObDomainOpType op_type = ObDomainOpType::T_DOMAIN_OP_END; + if (OB_ISNULL(domain_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FALSE_IT(expr = ObRawExprUtils::skip_inner_added_expr(domain_expr))) { + } else if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(need_extract_domain_range(*static_cast(expr), + need_extract))) { + LOG_WARN("failed to check need extract domain range", K(ret)); + } else if (!need_extract) { + // do nothing + } else { + common::ObDomainOpType op_type = ObQueryRange::get_domain_op_type(expr->get_expr_type()); + const ObRawExpr *l_expr = expr->get_param_expr(0); + const ObRawExpr *r_expr = expr->get_param_expr(1); + const ObRawExpr *const_param = nullptr; + const ObColumnRefRawExpr *column_param = nullptr; + ObRangeColumnMeta *column_meta = nullptr; + int64_t key_idx; + bool always_true = true; + if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(l_expr, l_expr))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(r_expr, r_expr))) { + LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (OB_UNLIKELY(r_expr->has_flag(CNT_COLUMN))) { + column_param = ObRawExprUtils::get_column_ref_expr_recursively(r_expr); + const_param = l_expr; + } else if (l_expr->has_flag(CNT_COLUMN)) { + column_param = ObRawExprUtils::get_column_ref_expr_recursively(l_expr); + const_param = r_expr; + } + + if (OB_SUCC(ret) && OB_NOT_NULL(column_param) && OB_NOT_NULL(const_param)) { + if (!is_range_key(column_param->get_column_id(), key_idx) || + OB_UNLIKELY(!const_param->is_const_expr())) { + // do nothing + } else if (OB_ISNULL(column_meta = get_column_meta(key_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (!ObQueryRange::can_domain_be_extract_range(op_type, column_meta->column_type_, + column_param->get_result_type().get_obj_meta(), + const_param->get_result_type().get_type(), + always_true)) { + // do nothing + } else if (OB_FAIL(get_geo_range_node(column_param, + op_type, + const_param, + NULL, + range_node))) { + LOG_WARN("failed to get geo range node", K(ret)); + } else { + ctx_.cur_is_precise_ = false; + } + } + } + + if (OB_SUCC(ret) && nullptr == range_node) { + ctx_.cur_is_precise_ = false; + if (OB_FAIL(generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate always true or fasle node", K(ret)); + } + } + return ret; +} + +int ObExprRangeConverter::need_extract_domain_range(const ObOpRawExpr &domain_expr, + bool& need_extract) +{ + int ret = OB_SUCCESS; + need_extract = false; + const ObRawExpr *l_expr = domain_expr.get_param_expr(0); + const ObRawExpr *r_expr = domain_expr.get_param_expr(1); + if (OB_ISNULL(l_expr) || OB_ISNULL(r_expr)) { + need_extract = false; + } else if (l_expr->has_flag(IS_COLUMN) && r_expr->has_flag(IS_COLUMN)) { + need_extract = false; + } else if (l_expr->has_flag(IS_DYNAMIC_PARAM) && r_expr->has_flag(IS_DYNAMIC_PARAM)) { + need_extract = false; + } else if (!l_expr->has_flag(CNT_COLUMN) && !r_expr->has_flag(CNT_COLUMN)) { + need_extract = false; + }else { + need_extract = true; + } + return ret; +} + +int ObExprRangeConverter::check_decimal_int_range_cmp_valid(const ObRawExpr *const_expr, + bool &is_valid) +{ + int ret = OB_SUCCESS; + is_valid = true; + if (OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null const expr", KP(const_expr)); + } else if (const_expr->has_flag(CNT_DYNAMIC_PARAM)) { + // do nothing + } else if (T_FUN_SYS_INNER_ROW_CMP_VALUE == const_expr->get_expr_type()) { + ObObj const_val; + bool obj_valid = false; + if (OB_FAIL(get_calculable_expr_val(const_expr, const_val, obj_valid))) { + LOG_WARN("failed to get calculable expr val", K(ret)); + } else if (obj_valid && (const_val.is_min_value() || const_val.is_max_value())) { + // if const val is min/max value, it means the previous expr value range is expanding, + // use origin cmp type to calc row range. + is_valid = false; + } + } + return ret; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/rewrite/ob_expr_range_converter.h b/src/sql/rewrite/ob_expr_range_converter.h new file mode 100644 index 000000000..c74acef30 --- /dev/null +++ b/src/sql/rewrite/ob_expr_range_converter.h @@ -0,0 +1,230 @@ +/** + * 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_REWRITE_OB_RANGE_NODE_GENERATOR_H_ +#define OCEANBASE_SQL_REWRITE_OB_RANGE_NODE_GENERATOR_H_ + +#include "sql/rewrite/ob_query_range_define.h" + + + +namespace oceanbase +{ +namespace sql +{ + +typedef ObSEArray TmpExprArray; + +class ObExprRangeConverter +{ +public: + ObExprRangeConverter(ObIAllocator &allocator, ObQueryRangeCtx &ctx) + : allocator_(allocator), + ctx_(ctx), + mem_used_(allocator.used()) + {} + + int convert_expr_to_range_node(const ObRawExpr *expr, + ObRangeNode *&range_node, + int64_t expr_depth, + bool &is_precise); + int generate_always_true_or_false_node(bool is_true, ObRangeNode *&range_node); + int convert_const_expr(const ObRawExpr *expr, ObRangeNode *&range_node); + int convert_basic_cmp_expr(const ObRawExpr *expr, + int64_t expr_depth, + ObRangeNode *&range_node); + int get_basic_range_node(const ObRawExpr *l_expr, + const ObRawExpr *r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node); + int convert_is_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + + int convert_between_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + int convert_not_between_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + int convert_not_equal_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + int convert_like_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + int convert_in_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + + + int fill_range_node_for_basic_cmp(ObItemType cmp_type, + const int64_t key_idx, + const int64_t val_idx, + ObRangeNode &range_node) const; + int fill_range_node_for_basic_row_cmp(ObItemType cmp_type, + const ObIArray &key_idxs, + const ObIArray &val_idxs, + ObRangeNode &range_node) const; + int fill_range_node_for_like(const int64_t key_idx, + const int64_t start_val_idx, + const int64_t end_val_idx, + ObRangeNode &range_node) const; + + int check_expr_precise(const ObRawExpr &const_expr, + const ObExprCalcType &calc_type, + const ObExprResType &column_res_type); + + inline int64_t get_mem_used() const { return mem_used_; } + + static int64_t get_expr_category(ObItemType type); + + int sort_range_exprs(const ObIArray &range_exprs, + ObIArray &out_range_exprs); +private: + ObExprRangeConverter(); + int alloc_range_node(ObRangeNode *&range_node); + int generate_deduce_const_expr(ObRawExpr *expr, int64_t &start_val, int64_t &end_val); + int gen_column_cmp_node(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + bool null_safe, + ObRangeNode *&range_node); + int gen_row_column_cmp_node(const ObIArray &l_exprs, + const ObIArray &r_exprs, + ObItemType cmp_type, + const ObIArray &calc_types, + int64_t expr_depth, + int64_t row_dim, + bool null_safe, + ObRangeNode *&range_node); + int get_rowid_node(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + ObRangeNode *&range_node); + int get_extract_rowid_range_infos(const ObRawExpr &calc_urowid_expr, + ObIArray &pk_columns, + bool &is_physical_rowid, + uint64_t &part_column_id); + int get_single_in_range_node(const ObColumnRefRawExpr *column_expr, + const ObRawExpr *r_expr, + const ObExprResType &res_type, + int64_t expr_depth, + ObRangeNode *&range_node); + int get_row_in_range_ndoe(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + const ObExprResType &res_type, + int64_t expr_depth, + ObRangeNode *&range_node); + int get_single_rowid_in_range_node(const ObRawExpr &rowid_expr, + const ObRawExpr &row_expr, + ObRangeNode *&range_node); + int convert_not_in_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + int get_single_not_in_range_node(const ObColumnRefRawExpr *column_expr, + const ObRawExpr *r_expr, + const ObExprResType &res_type, + int64_t expr_depth, + ObRangeNode *&range_node); + int get_nvl_cmp_node(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node); + int gen_is_null_range_node(const ObRawExpr *l_expr, int64_t expr_depth, ObRangeNode *&range_node); + + int check_escape_valid(const ObRawExpr *escape, char &escape_ch, bool &is_valid); + int build_decode_like_expr(ObRawExpr *pattern, ObRawExpr *escape, char escape_ch, + ObRangeColumnMeta *column_meta, int64_t &start_val_idx, int64_t &end_val_idx); + int get_calculable_expr_val(const ObRawExpr *expr, ObObj &val, bool &is_valid, const bool ignore_error = true); + int check_calculable_expr_valid(const ObRawExpr *expr, bool &is_valid, const bool ignore_error = true); + int add_precise_constraint(const ObRawExpr *expr, bool is_precise); + int add_prefix_pattern_constraint(const ObRawExpr *expr); + int get_final_expr_idx(const ObRawExpr *expr, + const ObRangeColumnMeta *column_meta, + int64_t &idx); + int get_final_in_array_idx(InParam *&in_param, int64_t &idx); + bool is_range_key(const uint64_t column_id, int64_t &key_idx); + ObRangeColumnMeta* get_column_meta(int64_t idx); + int try_wrap_lob_with_substr(const ObRawExpr *expr, + const ObRangeColumnMeta *column_meta, + const ObRawExpr *&out_expr); + int set_column_flags(int64_t key_idx, ObItemType type); + static int get_domain_extra_item(const common::ObDomainOpType op_type, + const ObRawExpr *expr, + const ObConstRawExpr *&extra_item); + int convert_geo_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + int get_geo_range_node(const ObColumnRefRawExpr *column_expr, + common::ObDomainOpType geo_type, + const ObRawExpr* wkb_expr, + const ObRawExpr *distance_expr, + ObRangeNode *&range_node); + int fill_range_node_for_geo_node(const int64_t key_idx, + common::ObDomainOpType geo_type, + uint32_t srid, + const int64_t start_val_idx, + const int64_t end_val_idx, + ObRangeNode &range_node) const; + int get_implicit_cast_range(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node); + int gen_implicit_cast_range(const ObColumnRefRawExpr *column_expr, + const ObRawExpr *const_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node); + int build_double_to_int_expr(const ObRawExpr *double_expr, + bool is_start, + ObItemType cmp_type, + bool is_unsigned, + bool is_decimal, + const ObRawExpr *&out_expr); + int get_row_cmp_node(const ObRawExpr &l_expr, + const ObRawExpr &r_expr, + ObItemType cmp_type, + const ObExprResType &result_type, + int64_t expr_depth, + ObRangeNode *&range_node); + int gen_row_implicit_cast_range(const ObIArray &column_exprs, + const ObIArray &const_exprs, + ObItemType cmp_type, + const ObIArray &calc_types, + ObIArray &implicit_cast_idxs, + int64_t expr_depth, + int64_t row_dim, + ObRangeNode *&range_node); + int build_decimal_to_year_expr(const ObRawExpr *decimal_expr, + bool is_start, + ObItemType cmp_type, + const ObRawExpr *&out_expr); + + int build_implicit_cast_range_expr(const ObColumnRefRawExpr *column_expr, + const ObRawExpr *const_expr, + ObItemType cmp_type, + bool is_start, + const ObRawExpr *&out_expr); + int can_extract_implicit_cast_range(const ObColumnRefRawExpr &column_expr, + const ObRawExpr &const_expr, + bool &can_extract); + int check_can_use_range_get(const ObRawExpr &const_expr, + const ObRangeColumnMeta &column_meta); + int set_extract_implicit_is_precise(const ObColumnRefRawExpr &column_expr, + const ObRawExpr &const_expr, + ObItemType cmp_type, + bool &is_precise); + int convert_domain_expr(const ObRawExpr *expr, int64_t expr_depth, ObRangeNode *&range_node); + int need_extract_domain_range(const ObOpRawExpr &domain_expr, bool& need_extract); + int check_decimal_int_range_cmp_valid(const ObRawExpr *const_expr, bool &is_valid); +private: + ObIAllocator &allocator_; + ObQueryRangeCtx &ctx_; + const int64_t mem_used_; +}; + +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_REWRITE_OB_QUERY_RANGE_DEFINE_H_ diff --git a/src/sql/rewrite/ob_query_range.cpp b/src/sql/rewrite/ob_query_range.cpp index 2b6ffe37e..2409060d4 100644 --- a/src/sql/rewrite/ob_query_range.cpp +++ b/src/sql/rewrite/ob_query_range.cpp @@ -79,6 +79,7 @@ ObQueryRange::ObQueryRange() key_part_store_(allocator_), range_exprs_(allocator_), ss_range_exprs_(allocator_), + unprecise_range_exprs_(allocator_), mbr_filters_(allocator_), has_exec_param_(false), is_equal_and_(false), @@ -104,6 +105,7 @@ ObQueryRange::ObQueryRange(ObIAllocator &alloc) key_part_store_(allocator_), range_exprs_(allocator_), ss_range_exprs_(allocator_), + unprecise_range_exprs_(allocator_), mbr_filters_(allocator_), has_exec_param_(false), is_equal_and_(false), @@ -147,6 +149,7 @@ void ObQueryRange::reset() table_graph_.reset(); range_exprs_.reset(); ss_range_exprs_.reset(); + unprecise_range_exprs_.reset(); inner_allocator_.reset(); has_exec_param_ = false; is_equal_and_ = false; @@ -1302,6 +1305,7 @@ int ObQueryRange::fill_range_exprs(const int64_t max_precise_pos, } else { ObSEArray range_exprs; ObSEArray ss_range_exprs; + ObSEArray unprecise_range_exprs; bool precise = true; bool ss_precise = true; for (int64_t i = 0; OB_SUCC(ret) && i < query_range_ctx_->precise_range_exprs_.count(); ++i) { @@ -1330,6 +1334,8 @@ int ObQueryRange::fill_range_exprs(const int64_t max_precise_pos, LOG_WARN("failed to assign range exprs", K(ret)); } else if (OB_FAIL(ss_range_exprs_.assign(ss_range_exprs))) { LOG_WARN("failed to assign skip scan range exprs", K(ret)); + } else if (OB_FAIL(unprecise_range_exprs_.assign(unprecise_range_exprs))) { + LOG_WARN("failed to assign unprecise range exprs", K(ret)); } else { LOG_DEBUG("finish fill range exprs", K(max_precise_pos), K(range_exprs)); LOG_DEBUG("finish fill skip scan range exprs", K(ss_offset), K(ss_max_precise_pos), K(ss_range_exprs)); @@ -7518,6 +7524,25 @@ int ObQueryRange::get_tablet_ranges(common::ObIAllocator &allocator, return ret; } +int ObQueryRange::get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params, + ObIArray &mbr_filters) const +{ + int ret = OB_SUCCESS; + UNUSED(mbr_filters); + if (OB_FAIL(get_tablet_ranges(allocator, + exec_ctx, + ranges, + all_single_value_ranges, + dtc_params))) { + LOG_WARN("failed to get tablet ranges", K(ret)); + } + return ret; +} + int ObQueryRange::get_ss_tablet_ranges(common::ObIAllocator &allocator, ObExecContext &exec_ctx, ObQueryRangeArray &ss_ranges, @@ -7543,6 +7568,26 @@ int ObQueryRange::get_ss_tablet_ranges(common::ObIAllocator &allocator, return ret; } +int ObQueryRange::get_fast_nlj_tablet_ranges(ObFastFinalNLJRangeCtx &fast_nlj_range_ctx, + common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + const ParamStore ¶m_store, + void *range_buffer, + ObQueryRangeArray &ranges, + const common::ObDataTypeCastParams &dtc_params) const +{ + int ret = OB_NOT_SUPPORTED; + UNUSED(fast_nlj_range_ctx); + UNUSED(allocator); + UNUSED(exec_ctx); + UNUSED(param_store); + UNUSED(range_buffer); + UNUSED(ranges); + UNUSED(dtc_params); + LOG_WARN("old qeury range not support this interface"); + return ret; +} + int ObQueryRange::ObSearchState::tailor_final_range(int64_t column_count) { int ret = OB_SUCCESS; @@ -9121,6 +9166,8 @@ OB_NOINLINE int ObQueryRange::deep_copy(const ObQueryRange &other, LOG_WARN("assign range exprs failed", K(ret)); } else if (OB_FAIL(ss_range_exprs_.assign(other.ss_range_exprs_))) { LOG_WARN("assign range exprs failed", K(ret)); + } else if (OB_FAIL(unprecise_range_exprs_.assign(other.unprecise_range_exprs_))) { + LOG_WARN("assign unprecise range exprs failed", K(ret)); } else if (OB_FAIL(table_graph_.assign(other_graph))) { LOG_WARN("Deep copy range columns failed", K(ret)); } else if (OB_FAIL(equal_offs_.assign(other.equal_offs_))) { @@ -9737,7 +9784,7 @@ DEF_TO_STRING(ObQueryRange::ObRangeExprItem) return pos; } -common::ObDomainOpType ObQueryRange::get_geo_relation(ObItemType type) const +common::ObDomainOpType ObQueryRange::get_geo_relation(ObItemType type) { common::ObDomainOpType rel_type = common::ObDomainOpType::T_INVALID; switch (type) { @@ -9760,6 +9807,14 @@ common::ObDomainOpType ObQueryRange::get_geo_relation(ObItemType type) const rel_type = common::ObDomainOpType::T_GEO_COVEREDBY; break; } + case T_FUN_SYS_ST_CROSSES : { + rel_type = common::ObDomainOpType::T_GEO_INTERSECTS; + break; + } + case T_FUN_SYS_ST_OVERLAPS : { + rel_type = common::ObDomainOpType::T_GEO_INTERSECTS; + break; + } case T_FUN_SYS_SDO_RELATE : { rel_type = common::ObDomainOpType::T_GEO_RELATE; break; @@ -9770,7 +9825,7 @@ common::ObDomainOpType ObQueryRange::get_geo_relation(ObItemType type) const return rel_type; } -common::ObDomainOpType ObQueryRange::get_domain_op_type(ObItemType type) const +common::ObDomainOpType ObQueryRange::get_domain_op_type(ObItemType type) { common::ObDomainOpType rel_type = common::ObDomainOpType::T_INVALID; switch (type) { @@ -10271,7 +10326,6 @@ int ObQueryRange::get_geo_range(const common::ObObj &wkb, const common::ObDomain } } } - return ret; } @@ -10294,5 +10348,57 @@ int ObQueryRange::set_columnId_map(uint64_t columnId, const ObGeoColumnInfo &col return ret; } +int ObQueryRange::get_prefix_info(int64_t &equal_prefix_count, + int64_t &range_prefix_count, + bool &contain_always_false) const +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(get_table_grapth().key_part_head_)) { + ret = OB_NOT_INIT; + LOG_WARN("table_graph.key_part_head_ is not inited.", K(ret)); + } else { + inner_get_prefix_info(get_table_grapth().key_part_head_, + equal_prefix_count, + range_prefix_count, + contain_always_false); + } + return ret; +} + +void ObQueryRange::inner_get_prefix_info(const ObKeyPart *key_part, + int64_t &equal_prefix_count, + int64_t &range_prefix_count, + bool &contain_always_false) const +{ + if (OB_NOT_NULL(key_part)) { + equal_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; + range_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; + for ( /*do nothing*/ ; NULL != key_part; key_part = key_part->or_next_) { + int64_t cur_equal_prefix_count = 0; + int64_t cur_range_prefix_count = 0; + if (key_part->is_equal_condition()) { + inner_get_prefix_info(key_part->and_next_, + cur_equal_prefix_count, + cur_range_prefix_count, + contain_always_false); + ++cur_equal_prefix_count; + ++cur_range_prefix_count; + } else if (key_part->is_range_condition()) { + ++cur_range_prefix_count; + } else if (key_part->is_always_false()) { + contain_always_false = true; + } + equal_prefix_count = std::min(cur_equal_prefix_count, equal_prefix_count); + range_prefix_count = std::min(cur_range_prefix_count, range_prefix_count); + } + } +} + +int ObQueryRange::get_total_range_sizes(common::ObIArray &total_range_sizes) const +{ + UNUSED(total_range_sizes); + return OB_SUCCESS; +} + } // namespace sql } // namespace oceanbase diff --git a/src/sql/rewrite/ob_query_range.h b/src/sql/rewrite/ob_query_range.h index 40d3d28ee..4242018f9 100644 --- a/src/sql/rewrite/ob_query_range.h +++ b/src/sql/rewrite/ob_query_range.h @@ -376,6 +376,8 @@ public: void reset(); + virtual inline bool is_new_query_range() const { return false; } + // preliminary_extract_query_range will preliminary extract query range // from query conditions, which is only occurred in generating the physical plan. // During this stage, some consts are not really known, for example, @@ -440,15 +442,28 @@ public: ObQueryRangeArray &ranges, bool &all_single_value_ranges, const common::ObDataTypeCastParams &dtc_params) const; - int get_ss_tablet_ranges(common::ObIAllocator &allocator, - ObExecContext &exec_ctx, - ObQueryRangeArray &ss_ranges, - const ObDataTypeCastParams &dtc_params) const; - int get_tablet_ranges(common::ObIAllocator &allocator, - ObExecContext &exec_ctx, - ObQueryRangeArray &ranges, - bool &all_single_value_ranges, - const common::ObDataTypeCastParams &dtc_params) const; + virtual int get_ss_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ss_ranges, + const ObDataTypeCastParams &dtc_params) const; + virtual int get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params) const; + virtual int get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params, + ObIArray &mbr_filters) const; + virtual int get_fast_nlj_tablet_ranges(ObFastFinalNLJRangeCtx &fast_nlj_range_ctx, + common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + const ParamStore ¶m_store, + void *range_buffer, + ObQueryRangeArray &ranges, + const common::ObDataTypeCastParams &dtc_params) const; // deep copy query range except the pointer of phy_plan_ int deep_copy(const ObQueryRange &other, const bool copy_for_final = false); // necessary condition: @@ -458,7 +473,7 @@ public: // or maybe all ranges are get-conditions after final extraction. // USE only in test. - bool is_precise_whole_range() const + virtual bool is_precise_whole_range() const { bool bret = false; if (NULL == table_graph_.key_part_head_) { @@ -470,13 +485,14 @@ public: } return bret; } - int is_get(bool &is_get) const; + virtual int is_get(bool &is_get) const; int is_get(int64_t column_count, bool &is_get) const; - bool is_precise_get() const { return table_graph_.is_precise_get_; } - common::ObDomainOpType get_geo_relation(ObItemType type) const; - common::ObDomainOpType get_domain_op_type(ObItemType type) const; - const common::ObIArray &get_range_exprs() const { return range_exprs_; } - const common::ObIArray &get_ss_range_exprs() const { return ss_range_exprs_; } + virtual bool is_precise_get() const { return table_graph_.is_precise_get_; } + static common::ObDomainOpType get_geo_relation(ObItemType type); + static common::ObDomainOpType get_domain_op_type(ObItemType type); + virtual const common::ObIArray &get_range_exprs() const { return range_exprs_; } + virtual const common::ObIArray &get_ss_range_exprs() const { return ss_range_exprs_; } + virtual const common::ObIArray &get_unprecise_range_exprs() const { return unprecise_range_exprs_; } int check_graph_type(ObKeyPart &key_part_head); int check_skip_scan_range(ObKeyPart *key_part_head, const bool is_standard_range, @@ -484,15 +500,15 @@ public: ObKeyPart *&ss_head, int64_t &skip_scan_offset, int64_t &ss_max_precise_pos); - int reset_skip_scan_range(); + virtual int reset_skip_scan_range(); bool is_precise_get(const ObKeyPart &key_part_head, int64_t &max_precise_pos, bool ignore_head = false); int fill_range_exprs(const int64_t max_precise_pos, const int64_t ss_offset, const int64_t ss_max_precise_pos); - bool is_ss_range() const { return table_graph_.skip_scan_offset_ > -1; } - int64_t get_skip_scan_offset() const { return table_graph_.skip_scan_offset_; } + virtual bool is_ss_range() const { return table_graph_.skip_scan_offset_ > -1; } + virtual int64_t get_skip_scan_offset() const { return table_graph_.skip_scan_offset_; } static bool can_be_extract_range(ObItemType cmp_type, const ObExprResType &col_type, const ObExprCalcType &res_type, common::ObObjType data_type, @@ -505,8 +521,8 @@ public: // need copy from ObTableScan operator to physical operator context to extract query range bool need_deep_copy() const { return !table_graph_.is_standard_range_; } - inline bool has_range() const { return column_count_ > 0; } - inline int64_t get_column_count() const { return column_count_; } + virtual inline bool has_range() const { return column_count_ > 0; } + virtual inline int64_t get_column_count() const { return column_count_; } const ObRangeGraph &get_table_grapth() const { return table_graph_; } int get_result_value(common::ObObj &val, ObExecContext &exec_ctx, ObIAllocator *allocator) const; int get_result_value_with_rowid(const ObKeyPart &key_part, @@ -514,7 +530,7 @@ public: ObExecContext &exec_ctx, bool &is_inconsistent_rowid, ObIAllocator *allocator = NULL) const; - bool inline has_exec_param() const { return has_exec_param_; } + virtual bool inline has_exec_param() const { return has_exec_param_; } bool inline get_is_equal_and() const { return is_equal_and_; } void inline set_is_equal_and(int64_t is_equal_and) { is_equal_and_ = is_equal_and; } const common::ObIArray &get_raw_equal_offs() const { return equal_offs_; } @@ -528,7 +544,15 @@ public: int set_columnId_map(uint64_t columnId, const ObGeoColumnInfo &column_info); MbrFilterArray &ut_get_mbr_filter() { return mbr_filters_; } ColumnIdInfoMap &ut_get_columnId_map() { return columnId_map_; } - bool is_contain_geo_filters() const { return contain_geo_filters_; } + virtual bool is_contain_geo_filters() const { return contain_geo_filters_; } + virtual int get_prefix_info(int64_t &equal_prefix_count, + int64_t &range_prefix_count, + bool &contain_always_false) const; + void inner_get_prefix_info(const ObKeyPart *key_part, + int64_t &equal_prefix_count, + int64_t &range_prefix_count, + bool &contain_always_false) const; + virtual bool is_fast_nlj_range() const { return false; } private: int init_query_range_ctx(common::ObIAllocator &allocator, @@ -1002,11 +1026,12 @@ private: int check_inner_row_cmp_type(const ObRawExpr *l_expr, const ObRawExpr *r_expr, bool &use_ori_cmp_type); + + virtual int get_total_range_sizes(common::ObIArray &total_range_sizes) const; private: static const int64_t RANGE_BUCKET_SIZE = 1000; static const int64_t MAX_RANGE_SIZE_OLD = 10000; static const int64_t MAX_RANGE_SIZE_NEW = 100000; - static const int64_t MAX_NOT_IN_SIZE = 10; //do not extract range for not in row over this size static const int64_t MAX_JSON_ARRAY_CHANGE_TO_OR_SIZE = 10; typedef common::ObObjStore KeyPartStore; private: @@ -1028,6 +1053,7 @@ private: //this flag used by optimizer, so don't need to serialize it common::ObFixedArray range_exprs_; common::ObFixedArray ss_range_exprs_; + common::ObFixedArray unprecise_range_exprs_; MbrFilterArray mbr_filters_; bool has_exec_param_; bool is_equal_and_; diff --git a/src/sql/rewrite/ob_query_range_define.cpp b/src/sql/rewrite/ob_query_range_define.cpp new file mode 100644 index 000000000..7f3a5aac5 --- /dev/null +++ b/src/sql/rewrite/ob_query_range_define.cpp @@ -0,0 +1,1119 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX SQL_REWRITE + +#include "sql/rewrite/ob_query_range_define.h" +#include "sql/rewrite/ob_expr_range_converter.h" +#include "sql/rewrite/ob_range_graph_generator.h" +#include "sql/rewrite/ob_range_generator.h" +#include "sql/engine/ob_exec_context.h" + +namespace oceanbase { +using namespace common; +namespace sql { + +void ObRangeNode::reset() +{ + flags_ = 0; + column_cnt_ = 0; + start_keys_ = nullptr; + end_keys_ = nullptr; + min_offset_ = -1; + max_offset_ = -1; + in_param_count_ = 0; + node_id_ = -1; + or_next_ = nullptr; + and_next_ = nullptr; +} + +int ObRangeNode::deep_copy(const ObRangeNode &other) +{ + int ret = OB_SUCCESS; + flags_ = other.flags_; + column_cnt_= other.column_cnt_; + min_offset_= other.min_offset_; + max_offset_= other.max_offset_; + in_param_count_= other.in_param_count_; + node_id_= other.node_id_; + start_keys_ = static_cast(allocator_.alloc(sizeof(int64_t) * column_cnt_ * 2)); + if (OB_ISNULL(start_keys_)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memory for range node keys"); + } else { + end_keys_ = start_keys_ + column_cnt_; + MEMCPY(start_keys_, other.start_keys_, sizeof(int64_t) * column_cnt_); + MEMCPY(end_keys_, other.end_keys_, sizeof(int64_t) * column_cnt_); + } + // do not copy or/and next + or_next_ = nullptr; + and_next_ = nullptr; + return ret; +} + +void ObRangeNode::set_always_true() +{ + flags_ = 0; + always_true_ = true; + min_offset_ = -1; + max_offset_ = -1; + in_param_count_ = 0; + node_id_ = -1; + or_next_ = nullptr; + and_next_ = nullptr; + for (int64_t i = 0; i < column_cnt_; ++i) { + start_keys_[i] = OB_RANGE_MIN_VALUE; + end_keys_[i] = OB_RANGE_MAX_VALUE; + } +} + +void ObRangeNode::set_always_false() +{ + flags_ = 0; + always_false_ = true; + min_offset_ = -1; + max_offset_ = -1; + in_param_count_ = 0; + node_id_ = -1; + or_next_ = nullptr; + and_next_ = nullptr; + for (int64_t i = 0; i < column_cnt_; ++i) { + start_keys_[i] = OB_RANGE_MAX_VALUE; + end_keys_[i] = OB_RANGE_MIN_VALUE; + } +} + +OB_DEF_SERIALIZE(ObRangeNode) +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(flags_); + OB_UNIS_ENCODE(column_cnt_); + for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt_; ++i) { + OB_UNIS_ENCODE(start_keys_[i]); + OB_UNIS_ENCODE(end_keys_[i]); + } + OB_UNIS_ENCODE(min_offset_); + OB_UNIS_ENCODE(max_offset_); + OB_UNIS_ENCODE(in_param_count_); + OB_UNIS_ENCODE(node_id_); + return ret; +} + +OB_DEF_DESERIALIZE(ObRangeNode) +{ + int ret = OB_SUCCESS; + OB_UNIS_DECODE(flags_); + OB_UNIS_DECODE(column_cnt_); + void *ptr = NULL; + if (OB_ISNULL(ptr = allocator_.alloc(sizeof(int64_t) * column_cnt_ * 2))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("alloc memory failed"); + } else { + start_keys_ = static_cast(ptr); + end_keys_ = start_keys_ + column_cnt_; + for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt_; ++i) { + OB_UNIS_DECODE(start_keys_[i]); + OB_UNIS_DECODE(end_keys_[i]); + } + OB_UNIS_DECODE(min_offset_); + OB_UNIS_DECODE(max_offset_); + OB_UNIS_DECODE(in_param_count_); + OB_UNIS_DECODE(node_id_); + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObRangeNode) +{ + int64_t len = 0; + OB_UNIS_ADD_LEN(flags_); + OB_UNIS_ADD_LEN(column_cnt_); + // start keys and end keys + for (int64_t i = 0; i < column_cnt_; ++i) { + OB_UNIS_ADD_LEN(start_keys_[i]); + OB_UNIS_ADD_LEN(end_keys_[i]); + } + OB_UNIS_ADD_LEN(min_offset_); + OB_UNIS_ADD_LEN(max_offset_); + OB_UNIS_ADD_LEN(in_param_count_); + OB_UNIS_ADD_LEN(node_id_); + return len; +} + +DEF_TO_STRING(ObRangeNode) +{ + int64_t pos = 0; + J_OBJ_START(); + // print parameters + J_KV(K_(always_true), + K_(always_false), + K_(min_offset), + K_(max_offset), + K_(column_cnt), + K_(include_start), + K_(include_end), + K_(contain_in), + K_(is_domain_node), + K_(node_id)); + // print range + J_COMMA(); + BUF_PRINTF("range:"); + J_ARRAY_START(); + for (int64_t i = 0; i < column_cnt_; ++i) { + BUF_PRINTO(start_keys_[i]); + if (i == column_cnt_ - 1) { + BUF_PRINTF("; "); + } else { + J_COMMA(); + } + } + for (int64_t i = 0; i < column_cnt_; ++i) { + BUF_PRINTO(end_keys_[i]); + if (i < column_cnt_ - 1) { + J_COMMA(); + } + } + J_ARRAY_END(); + // print node connection relation + J_COMMA(); + J_KV(KP(this), + KP_(or_next), + KP_(and_next)); + J_OBJ_END(); + return pos; +} + +OB_DEF_SERIALIZE(ObRangeMap) +{ + int ret = OB_SUCCESS; + int64_t cnt = expr_final_infos_.count(); + OB_UNIS_ENCODE(cnt); + for (int64_t i = 0; OB_SUCC(ret) && i < cnt; ++i) { + OB_UNIS_ENCODE(expr_final_infos_.at(i).flags_); + if (expr_final_infos_.at(i).is_param_) { + OB_UNIS_ENCODE(expr_final_infos_.at(i).param_idx_); + } else if (expr_final_infos_.at(i).is_const_) { + OB_UNIS_ENCODE(*expr_final_infos_.at(i).const_val_); + } else if (expr_final_infos_.at(i).is_expr_) { + OB_UNIS_ENCODE(*expr_final_infos_.at(i).temp_expr_); + } + } + cnt = in_params_.count(); + OB_UNIS_ENCODE(cnt); + for (int64_t i = 0; OB_SUCC(ret) && i < cnt; ++i) { + InParam* param = in_params_.at(i); + if (OB_ISNULL(param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null"); + } else { + OB_UNIS_ENCODE(param->count()); + for (int64_t j = 0; OB_SUCC(ret) && j < param->count(); ++j) { + OB_UNIS_ENCODE(param->at(j)); + } + } + } + return ret; +} + +OB_DEF_DESERIALIZE(ObRangeMap) +{ + int ret = OB_SUCCESS; + expr_final_infos_.reset(); + int64_t cnt = 0; + OB_UNIS_DECODE(cnt); + if (OB_SUCC(ret)) { + if (OB_FAIL(expr_final_infos_.prepare_allocate(cnt))) { + LOG_WARN("failed to prepare allocate expr final info", K(cnt)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < cnt; ++i) { + OB_UNIS_DECODE(expr_final_infos_.at(i).flags_); + if (expr_final_infos_.at(i).is_param_) { + OB_UNIS_DECODE(expr_final_infos_.at(i).param_idx_); + } else if (expr_final_infos_.at(i).is_const_) { + ObObj *obj_val = nullptr; + void *ptr = allocator_.alloc(sizeof(ObObj)); + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memeory for ObObj"); + } else { + obj_val = new(ptr)ObObj(); + OB_UNIS_DECODE(*obj_val); + if (OB_SUCC(ret)) { + expr_final_infos_.at(i).const_val_ = obj_val; + } + } + } else if (expr_final_infos_.at(i).is_expr_) { + ObTempExpr *temp_expr = nullptr; + void *ptr = allocator_.alloc(sizeof(ObTempExpr)); + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memeory for temp expr"); + } else { + temp_expr = new(ptr)ObTempExpr(allocator_); + OB_UNIS_DECODE(*temp_expr); + if (OB_SUCC(ret)) { + expr_final_infos_.at(i).temp_expr_ = temp_expr; + } + } + } + } + OB_UNIS_DECODE(cnt); + if (OB_SUCC(ret)) { + if (OB_FAIL(in_params_.prepare_allocate(cnt))) { + LOG_WARN("failed to init array", K(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < cnt; ++i) { + InParam* param = nullptr; + int64_t param_cnt = 0; + void *ptr = allocator_.alloc(sizeof(InParam)); + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memeory for in param"); + } else { + param = new(ptr)InParam(allocator_); + in_params_.at(i) = param; + OB_UNIS_DECODE(param_cnt); + if (OB_SUCC(ret)) { + if (OB_FAIL(param->prepare_allocate(param_cnt))) { + LOG_WARN("failed to init array"); + } + } + for (int64_t j = 0; OB_SUCC(ret) && j < param_cnt; ++j) { + OB_UNIS_DECODE(param->at(j)); + } + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObRangeMap) +{ + int64_t len = 0; + int64_t cnt = expr_final_infos_.count(); + OB_UNIS_ADD_LEN(cnt); + for (int64_t i = 0; i < cnt; ++i) { + OB_UNIS_ADD_LEN(expr_final_infos_.at(i).flags_); + if (expr_final_infos_.at(i).is_param_) { + OB_UNIS_ADD_LEN(expr_final_infos_.at(i).param_idx_); + } else if (expr_final_infos_.at(i).is_const_) { + OB_UNIS_ADD_LEN(*expr_final_infos_.at(i).const_val_); + } else if (expr_final_infos_.at(i).is_expr_) { + OB_UNIS_ADD_LEN(*expr_final_infos_.at(i).temp_expr_); + } + } + cnt = in_params_.count(); + OB_UNIS_ADD_LEN(cnt); + for (int64_t i = 0; i < cnt; ++i) { + InParam* param = in_params_.at(i); + if (OB_NOT_NULL(param)) { + OB_UNIS_ADD_LEN(param->count()); + for (int64_t j = 0; j < param->count(); ++j) { + OB_UNIS_ADD_LEN(param->at(j)); + } + } + } + return len; +} + +//ObRangeColumnMeta +OB_SERIALIZE_MEMBER(ObRangeColumnMeta, column_type_); + +int ObQueryRangeCtx::init(ObPreRangeGraph *pre_range_graph, + const ObIArray &range_columns, + ExprConstrantArray *expr_constraints, + const ParamStore *params, + ObRawExprFactory *expr_factory, + const bool phy_rowid_for_table_loc, + const bool ignore_calc_failure, + const int64_t index_prefix, + const ColumnIdInfoMap *geo_column_id_map) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(pre_range_graph) || OB_ISNULL(exec_ctx_) || OB_ISNULL(exec_ctx_->get_my_session()) || + OB_UNLIKELY(range_columns.count() <= 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected param", K(pre_range_graph), K(exec_ctx_)); + } else if (OB_FAIL(column_metas_.assign(pre_range_graph->get_column_metas()))) { + LOG_WARN("failed to assign column meta"); + } else if (OB_FAIL(column_flags_.prepare_allocate(pre_range_graph->get_column_metas().count()))) { + LOG_WARN("failed to prepare allocate"); + } else if (OB_FAIL(exec_ctx_->get_my_session()-> + is_enable_range_extraction_for_not_in(enable_not_in_range_))) { + LOG_WARN("failed to check not in range enabled", K(ret)); + } else if (OB_FAIL(exec_ctx_->get_my_session()-> + get_optimizer_features_enable_version(optimizer_features_enable_version_))) { + LOG_WARN("failed to get optimizer features enable version", K(ret)); + } else { + column_cnt_ = range_columns.count(); + expr_constraints_ = expr_constraints; + params_ = params; + phy_rowid_for_table_loc_ = phy_rowid_for_table_loc; + ignore_calc_failure_ = ignore_calc_failure; + expr_factory_ = expr_factory; + session_info_ = exec_ctx_->get_my_session(); + max_mem_size_ = exec_ctx_->get_my_session()->get_range_optimizer_max_mem_size(); + index_prefix_ = index_prefix; + geo_column_id_map_ = geo_column_id_map; + is_geo_range_ = geo_column_id_map != NULL; + } + for (int64_t i = 0; OB_SUCC(ret) && i < range_columns.count(); ++i) { + const ColumnItem &col = range_columns.at(i); + if (OB_UNLIKELY(col.is_invalid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get invalid column item", K(col)); + } else if (OB_FAIL(range_column_map_.set_refactored(col.column_id_, i))) { + LOG_WARN("failed to set column map", K(col), K(i)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < column_flags_.count(); ++i) { + column_flags_.at(i) = 0; + } + return ret; +} + +void ObPreRangeGraph::reset() +{ + table_id_ = OB_INVALID_ID; + column_count_ = 0; + range_size_ = 0; + node_count_ = 0; + node_head_ = nullptr; + is_standard_range_ = false; + is_precise_get_ = false; + is_equal_range_ = false; + is_get_ = false; + contain_exec_param_ = false; + column_metas_.reset(); + range_map_.expr_final_infos_.reset(); + range_map_.in_params_.reset(); + skip_scan_offset_ = -1; + range_exprs_.reset(); + ss_range_exprs_.reset(); + unprecise_range_exprs_.reset(); + total_range_sizes_.reset(); + flags_ = 0; +} + +int ObPreRangeGraph::deep_copy(const ObPreRangeGraph &other) +{ + int ret = OB_SUCCESS; + table_id_ = other.table_id_; + column_count_ = other.column_count_; + range_size_ = other.range_size_; + node_count_ = other.node_count_; + is_standard_range_ = other.is_standard_range_; + is_precise_get_ = other.is_precise_get_; + is_equal_range_ = other.is_equal_range_; + is_get_ = other.is_get_; + contain_exec_param_ = other.contain_exec_param_; + skip_scan_offset_ = other.skip_scan_offset_; + flags_ = other.flags_; + if (OB_FAIL(range_exprs_.assign(other.range_exprs_))) { + LOG_WARN("failed to assign range exprs"); + } else if (OB_FAIL(ss_range_exprs_.assign(other.ss_range_exprs_))) { + LOG_WARN("failed to assign ss range exprs"); + } else if (OB_FAIL(unprecise_range_exprs_.assign(other.unprecise_range_exprs_))) { + LOG_WARN("failed to assign unprecise range exprs"); + } else if (OB_FAIL(total_range_sizes_.assign(other.total_range_sizes_))) { + LOG_WARN("failed to assign total range sizes"); + } else if (OB_FAIL(deep_copy_range_graph(other.node_head_))) { + LOG_WARN("failed to deep copy range graph"); + } else if (OB_FAIL(deep_copy_column_metas(other.column_metas_))) { + LOG_WARN("failed to deep copy column metas"); + } else if (OB_FAIL(deep_copy_range_map(other.range_map_))) { + LOG_WARN("failed to deep copy range map"); + } + return ret; +} + +int ObPreRangeGraph::deep_copy_range_graph(ObRangeNode *src_node) +{ + int ret = OB_SUCCESS; + ObSEArray range_nodes; + ObSEArray, 16> ptr_pairs; + if (src_node == nullptr) { + // do nothing + } else if (OB_FAIL(inner_deep_copy_range_graph(src_node, range_nodes, ptr_pairs))) { + LOG_WARN("failed to inner deep copy range graph"); + } else if (OB_UNLIKELY(range_nodes.count() != node_count_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node count", K(node_count_), K(range_nodes.count())); + } else { + for (int64_t i = 0; i < node_count_; ++i) { + std::pair &ptr_pair = ptr_pairs.at(i); + range_nodes.at(i)->and_next_ = (-1 == ptr_pair.first) ? nullptr : range_nodes.at(ptr_pair.first); + range_nodes.at(i)->or_next_ = (-1 == ptr_pair.second) ? nullptr : range_nodes.at(ptr_pair.second); + } + node_head_ = node_count_ > 0 ? range_nodes.at(0) : nullptr; + } + return ret; +} + +int ObPreRangeGraph::inner_deep_copy_range_graph(ObRangeNode *range_node, + ObIArray &range_nodes, + ObIArray> &ptr_pairs) +{ + int ret = OB_SUCCESS; + for (ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->or_next_) { + int64_t and_next_id = (nullptr == cur_node->and_next_) ? -1 : cur_node->and_next_->node_id_; + int64_t or_next_id = (nullptr == cur_node->or_next_) ? -1 : cur_node->or_next_->node_id_; + ObRangeNode *new_node = static_cast(allocator_.alloc(sizeof(ObRangeNode))); + if (OB_ISNULL(new_node)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for range node"); + } else { + new_node = new(new_node)ObRangeNode(allocator_); + if (OB_FAIL(new_node->deep_copy(*cur_node))) { + LOG_WARN("failed to deep copy range node"); + } else if (OB_FAIL(range_nodes.push_back(new_node))) { + LOG_WARN("failed to push back range node"); + } else if (OB_FAIL(ptr_pairs.push_back(std::pair(and_next_id, or_next_id)))) { + LOG_WARN("failed to push back and/or next id"); + } + } + /** + * Node id is generated by dfs algorithm. So if node id of and_next smaller than node id + * of current node, and next node must have been copied. + * + * node(0) -- node(1) -- node(2) + * | / + * node(3) -- node(4) / + */ + if OB_SUCC(ret) { + if (cur_node->and_next_ != nullptr && cur_node->and_next_->node_id_ > cur_node->node_id_) { + if (OB_FAIL(SMART_CALL(inner_deep_copy_range_graph(cur_node->and_next_, range_nodes, ptr_pairs)))) { + LOG_WARN("failed to inner deep copy range graph"); + } + } + } + } + return ret; +} + +int ObPreRangeGraph::deep_copy_column_metas(const ObIArray &src_metas) +{ + int ret = OB_SUCCESS; + column_metas_.reset(); + int64_t count = src_metas.count(); + if (OB_FAIL(column_metas_.prepare_allocate(count))) { + LOG_WARN("failed to prepare allocate column meta", K(count)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { + const ObRangeColumnMeta *src_meta = src_metas.at(i); + ObRangeColumnMeta *column_meta = nullptr; + void *ptr = allocator_.alloc(sizeof(ObRangeColumnMeta)); + if (OB_ISNULL(src_meta)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memeory for ObRangeColumnMeta"); + } else { + column_meta = new(ptr)ObRangeColumnMeta(); + column_meta->column_type_ = src_meta->column_type_; + column_metas_.at(i) = column_meta; + } + } + return ret; +} + +int ObPreRangeGraph::deep_copy_range_map(const ObRangeMap &src_range_map) +{ + int ret = OB_SUCCESS; + range_map_.expr_final_infos_.reset(); + int64_t count = src_range_map.expr_final_infos_.count(); + if (OB_FAIL(range_map_.expr_final_infos_.prepare_allocate(count))) { + LOG_WARN("failed to prepare allocate expr final info", K(count)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { + range_map_.expr_final_infos_.at(i).flags_ = src_range_map.expr_final_infos_.at(i).flags_; + if (range_map_.expr_final_infos_.at(i).is_param_) { + range_map_.expr_final_infos_.at(i).param_idx_ = src_range_map.expr_final_infos_.at(i).param_idx_; + } else if (range_map_.expr_final_infos_.at(i).is_const_) { + ObObj *obj_val = nullptr; + void *ptr = allocator_.alloc(sizeof(ObObj)); + if (OB_ISNULL(src_range_map.expr_final_infos_.at(i).const_val_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null const val"); + } else if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memeory for ObObj"); + } else { + obj_val = new(ptr)ObObj(); + if (OB_FAIL(ob_write_obj(allocator_, *src_range_map.expr_final_infos_.at(i).const_val_, *obj_val))) { + LOG_WARN("failed to write obj", KPC(src_range_map.expr_final_infos_.at(i).const_val_)); + } else { + range_map_.expr_final_infos_.at(i).const_val_ = obj_val; + } + } + } else if (range_map_.expr_final_infos_.at(i).is_expr_) { + ObTempExpr *temp_expr = nullptr; + if (OB_ISNULL(src_range_map.expr_final_infos_.at(i).temp_expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null temp expr"); + } else if (OB_FAIL(src_range_map.expr_final_infos_.at(i).temp_expr_->deep_copy(allocator_, temp_expr))) { + LOG_WARN("faield to deep copy temp expr"); + } else { + range_map_.expr_final_infos_.at(i).temp_expr_ = temp_expr; + } + } + } + + if (OB_SUCC(ret)) { + count = src_range_map.in_params_.count(); + if (OB_FAIL(range_map_.in_params_.prepare_allocate(count))) { + LOG_WARN("failed to init array", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { + InParam* param = nullptr; + void *ptr = allocator_.alloc(sizeof(InParam)); + if (OB_ISNULL(src_range_map.in_params_.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null in param"); + } else if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memeory for in param"); + } else { + param = new(ptr)InParam(allocator_); + if (OB_FAIL(param->assign(*src_range_map.in_params_.at(i)))) { + LOG_WARN("failed to assign in param"); + } else { + range_map_.in_params_.at(i) = param; + } + } + } + } + return ret; +} + +int ObPreRangeGraph::preliminary_extract_query_range(const ObIArray &range_columns, + const ObIArray &root_exprs, + ObExecContext *exec_ctx, + ExprConstrantArray *expr_constraints, + const ParamStore *params, + const bool phy_rowid_for_table_loc, + const bool ignore_calc_failure, + const int64_t index_prefix /* =-1*/, + const ColumnIdInfoMap *geo_column_id_map /* = NULL*/) +{ + int ret = OB_SUCCESS; + ObRawExprFactory expr_factory(allocator_); + ObQueryRangeCtx ctx(exec_ctx); + if (OB_FAIL(fill_column_metas(range_columns))) { + LOG_WARN("failed to fill column metas"); + } else if (OB_FAIL(ctx.init(this, range_columns, expr_constraints, + params, &expr_factory, + phy_rowid_for_table_loc, ignore_calc_failure, index_prefix, + geo_column_id_map))) { + LOG_WARN("failed to init query range context"); + } else { + ObExprRangeConverter converter(allocator_, ctx); + ObRangeGraphGenerator graph_generator(allocator_, ctx, this, range_columns.count()); + if (OB_FAIL(graph_generator.generate_range_graph(root_exprs, converter))) { + LOG_WARN("failed to generate range graph"); + } else { + LOG_TRACE("succeed to preliminary extract query range", + KPC(this), K(range_columns), K(root_exprs)); + } + } + return ret; +} + +int ObPreRangeGraph::get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params) const +{ + int ret = OB_SUCCESS; + ObMbrFilterArray mbr_filter; + ObRangeGenerator range_generator(allocator, exec_ctx, this, ranges, all_single_value_ranges, dtc_params, mbr_filter); + if (OB_FAIL(range_generator.generate_ranges())) { + LOG_WARN("failed to generate ranges"); + } + return ret; +} + +int ObPreRangeGraph::get_tablet_ranges(ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params) +{ + int ret = OB_NOT_SUPPORTED; + LOG_WARN("new qeury range not support this interface"); + return ret; +} + +int ObPreRangeGraph::get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params, + ObIArray &mbr_filters) const +{ + int ret = OB_SUCCESS; + ObRangeGenerator range_generator(allocator, exec_ctx, this, ranges, all_single_value_ranges, dtc_params, mbr_filters); + if (OB_FAIL(range_generator.generate_ranges())) { + LOG_WARN("failed to generate ranges"); + } + return ret; +} + +int ObPreRangeGraph::get_ss_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ss_ranges, + const common::ObDataTypeCastParams &dtc_params) const +{ + int ret = OB_SUCCESS; + ObMbrFilterArray mbr_filter; + ss_ranges.reuse(); + if (!is_ss_range()) { + // do nothing + } else { + bool dummy_all_single_value = false; + ObRangeGenerator range_generator(allocator, exec_ctx, this, ss_ranges, dummy_all_single_value, dtc_params, mbr_filter); + if (OB_FAIL(range_generator.generate_ss_ranges())) { + LOG_WARN("failed to generate ranges"); + } else { + LOG_DEBUG("get skip range success", K(ss_ranges)); + } + } + return ret; +} + +int ObPreRangeGraph::get_fast_nlj_tablet_ranges(ObFastFinalNLJRangeCtx &fast_nlj_range_ctx, + common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + const ParamStore ¶m_store, + void *range_buffer, + ObQueryRangeArray &ranges, + const common::ObDataTypeCastParams &dtc_params) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!fast_nlj_range_ctx.has_check_valid)) { + if (OB_FAIL(ObRangeGenerator::check_can_final_fast_nlj_range(*this, + param_store, + fast_nlj_range_ctx.is_valid))) { + LOG_WARN("failed to check can final fast nlj range", K(ret)); + } + fast_nlj_range_ctx.has_check_valid = true; + } + if (OB_FAIL(ret)) { + } else if (OB_LIKELY(fast_nlj_range_ctx.is_valid)) { + if (OB_FAIL(ObRangeGenerator::generate_fast_nlj_range(*this, + param_store, + allocator, + range_buffer))) { + LOG_WARN("failed to generate fast nlj range", K(ret)); + } else if (OB_FAIL(ranges.push_back(static_cast(range_buffer)))) { + LOG_WARN("failed to push back array", K(ret)); + } + } else { + bool dummy_all_single_value_ranges = false; + if (OB_FAIL(get_tablet_ranges(allocator, + exec_ctx, + ranges, + dummy_all_single_value_ranges, + dtc_params))) { + LOG_WARN("failed to get tablet ranges", K(ret)); + } + } + + return ret; +} + +int ObPreRangeGraph::fill_column_metas(const ObIArray &range_columns) +{ + int ret = OB_SUCCESS; + column_count_ = range_columns.count(); + if (OB_FAIL(column_metas_.init(column_count_))) { + LOG_WARN("failed to init fixed array", K(column_count_)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < column_count_; ++i) { + const ObColumnRefRawExpr *column_expr = range_columns.at(i).expr_; + void *ptr = NULL; + if (OB_ISNULL(column_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (OB_ISNULL(ptr = allocator_.alloc(sizeof(ObRangeColumnMeta)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memeory for ObRangeColumnMeta"); + } else { + ObRangeColumnMeta *column_meta = new(ptr)ObRangeColumnMeta(column_expr->get_result_type()); + if (column_meta->column_type_.is_lob_locator()) { + column_meta->column_type_.set_type(ObLongTextType); + } + if (OB_FAIL(column_metas_.push_back(column_meta))) { + LOG_WARN("failed to push back column meta"); + } + } + if (OB_SUCC(ret)) { + if (i == 0) { + table_id_ = column_expr->get_table_id(); + } else if (OB_UNLIKELY(column_expr->get_table_id() != table_id_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("range columns should belong to same table", K(range_columns)); + } + } + } + return ret; +} + +int ObPreRangeGraph::get_prefix_info(int64_t &equal_prefix_count, + int64_t &range_prefix_count, + bool &contain_always_false) const +{ + int ret = OB_SUCCESS; + equal_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; + range_prefix_count = OB_USER_MAX_ROWKEY_COLUMN_NUMBER; + if (OB_ISNULL(node_head_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range node"); + } else if (node_head_->always_true_ || node_head_->always_false_) { + equal_prefix_count = 0; + range_prefix_count = 0; + contain_always_false = node_head_->always_false_; + } else { + bool equals[column_count_]; + MEMSET(equals, 0, sizeof(bool) * column_count_); + if (OB_FAIL(get_prefix_info(node_head_, equals, equal_prefix_count))) { + LOG_WARN("failed to get prefix info"); + } else { + range_prefix_count = (equal_prefix_count == column_count_) ? equal_prefix_count : equal_prefix_count + 1; + } + } + return ret; +} + +int ObPreRangeGraph::get_prefix_info(const ObRangeNode *range_node, + bool* equals, + int64_t &equal_prefix_count) const +{ + int ret = OB_SUCCESS; + ObSEArray new_idx; + for (const ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != NULL; cur_node = cur_node->or_next_) { + // reset equal flag in previous or range node + for (int64_t j = 0; j < new_idx.count(); ++j) { + equals[new_idx.at(j)] = false; + } + new_idx.reset(); + + if (cur_node->min_offset_ >= 0 && + OB_FAIL(get_new_equal_idx(cur_node, equals, new_idx))) { + LOG_WARN("failed to get new idx"); + } else if (cur_node->and_next_ != nullptr) { + if (OB_FAIL(SMART_CALL(get_prefix_info(cur_node->and_next_, equals, equal_prefix_count)))) { + LOG_WARN("failed to check is strict equal graph"); + } + } else { + int64_t cur_pos = 0; + for (; cur_pos < column_count_; ++cur_pos) { + if (!equals[cur_pos]) { + break; + } + } + equal_prefix_count = std::min(equal_prefix_count, cur_pos); + } + } + // reset equal flag in current range node + if (OB_SUCC(ret)) { + for (int64_t j = 0; j < new_idx.count(); ++j) { + equals[new_idx.at(j)] = false; + } + } + return ret; +} + +int ObPreRangeGraph::get_new_equal_idx(const ObRangeNode *range_node, + bool* equals, + ObIArray &new_idx) const +{ + int ret = OB_SUCCESS; + for (int64_t i = range_node->min_offset_; OB_SUCC(ret) && i <= range_node->max_offset_; ++i) { + if (!equals[i] && range_node->start_keys_[i] == range_node->end_keys_[i] && + (range_node->start_keys_[i] < OB_RANGE_EXTEND_VALUE || range_node->start_keys_[i] == OB_RANGE_NULL_VALUE)) { + equals[i] = true; + if (OB_FAIL(new_idx.push_back(i))) { + LOG_WARN("failed to push back idx", K(i)); + } + } + } + return ret; +} + +int ObPreRangeGraph::serialize_range_graph(ObRangeNode *range_node, + char *buf, + int64_t buf_len, + int64_t &pos) const +{ + int ret = OB_SUCCESS; + for (ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->or_next_) { + int64_t and_next_id = (nullptr == cur_node->and_next_) ? -1 : cur_node->and_next_->node_id_; + int64_t or_next_id = (nullptr == cur_node->or_next_) ? -1 : cur_node->or_next_->node_id_; + OB_UNIS_ENCODE(*cur_node); + OB_UNIS_ENCODE(and_next_id); + OB_UNIS_ENCODE(or_next_id); + /** + * Node id is generated by dfs algorithm. So if node id of and_next smaller than node id + * of current node, and next node must have been serialized. + * + * node(0) -- node(1) -- node(2) + * | / + * node(3) -- node(4) / + */ + if (cur_node->and_next_ != nullptr && cur_node->and_next_->node_id_ > cur_node->node_id_) { + if (OB_FAIL(SMART_CALL(serialize_range_graph(cur_node->and_next_, buf, buf_len, pos)))) { + LOG_WARN("failed to serialize range graph"); + } + } + } + return ret; +} + +int ObPreRangeGraph::deserialize_range_graph(ObRangeNode *&range_node, + const char *buf, + int64_t data_len, + int64_t &pos) +{ + int ret = OB_SUCCESS; + ObSEArray range_nodes; + ObSEArray, 16> ptr_pairs; + for (int64_t i = 0; OB_SUCC(ret) && i < node_count_; ++i) { + int64_t and_next_id = -1; + int64_t or_next_id = -1; + ObRangeNode* node = nullptr; + void *ptr = allocator_.alloc(sizeof(ObRangeNode)); + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memeory for ObRangeNode"); + } else { + node = new(ptr)ObRangeNode(allocator_); + OB_UNIS_DECODE(*node); + if (OB_SUCC(ret)) { + if (OB_UNLIKELY(node->node_id_ != i)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected node id", K(node->node_id_), K(i)); + } else if (OB_FAIL(range_nodes.push_back(node))) { + LOG_WARN("failed to push back range node"); + } + } + } + OB_UNIS_DECODE(and_next_id); + OB_UNIS_DECODE(or_next_id); + if (OB_SUCC(ret)) { + if (OB_UNLIKELY((and_next_id != -1 && and_next_id >= node_count_) || + (or_next_id != -1 && or_next_id >= node_count_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected and/or next id", K(and_next_id), K(or_next_id)); + } else if (OB_FAIL(ptr_pairs.push_back(std::pair(and_next_id, or_next_id)))) { + LOG_WARN("failed to push back and next id and or next id"); + } + } + } + if (OB_SUCC(ret)) { + for (int64_t i = 0; i < node_count_; ++i) { + std::pair &ptr_pair = ptr_pairs.at(i); + range_nodes.at(i)->and_next_ = (-1 == ptr_pair.first) ? nullptr : range_nodes.at(ptr_pair.first); + range_nodes.at(i)->or_next_ = (-1 == ptr_pair.second) ? nullptr : range_nodes.at(ptr_pair.second); + } + range_node = node_count_ > 0 ? range_nodes.at(0) : nullptr; + } + return ret; +} + +int64_t ObPreRangeGraph::get_serialize_size_range_graph(const ObRangeNode *range_node) const +{ + int64_t len = 0; + for (const ObRangeNode *cur_node = range_node; cur_node != nullptr; cur_node = cur_node->or_next_) { + int64_t and_next_id = (nullptr == cur_node->and_next_) ? -1 : cur_node->and_next_->node_id_; + int64_t or_next_id = (nullptr == cur_node->or_next_) ? -1 : cur_node->or_next_->node_id_; + OB_UNIS_ADD_LEN(*cur_node); + OB_UNIS_ADD_LEN(and_next_id); + OB_UNIS_ADD_LEN(or_next_id); + /** + * Node id is generated by dfs algorithm. So if node id of and_next smaller than node id + * of current node, and next node must have been serialized. + * + * node(0) -- node(1) -- node(2) + * | / + * node(3) -- node(4) / + */ + if (cur_node->and_next_ != nullptr && cur_node->and_next_->node_id_ > cur_node->node_id_) { + len += get_serialize_size_range_graph(cur_node->and_next_); + } + } + return len; +} + +OB_DEF_SERIALIZE(ObPreRangeGraph) +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(table_id_); + OB_UNIS_ENCODE(column_count_); + OB_UNIS_ENCODE(range_size_); + OB_UNIS_ENCODE(node_count_); + if (OB_SUCC(ret)) { + if (OB_FAIL(serialize_range_graph(node_head_, buf, buf_len, pos))) { + LOG_WARN("failed to serialize range graph"); + } + } + OB_UNIS_ENCODE(is_standard_range_); + OB_UNIS_ENCODE(is_precise_get_); + OB_UNIS_ENCODE(is_equal_range_); + OB_UNIS_ENCODE(is_get_); + OB_UNIS_ENCODE(contain_exec_param_); + if (OB_SUCC(ret)) { + int64_t count = column_metas_.count(); + OB_UNIS_ENCODE(count); + for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { + OB_UNIS_ENCODE(*column_metas_.at(i)); + } + } + OB_UNIS_ENCODE(range_map_); + OB_UNIS_ENCODE(skip_scan_offset_); + OB_UNIS_ENCODE(flags_); + return ret; +} + +OB_DEF_DESERIALIZE(ObPreRangeGraph) +{ + int ret = OB_SUCCESS; + OB_UNIS_DECODE(table_id_); + OB_UNIS_DECODE(column_count_); + OB_UNIS_DECODE(range_size_); + OB_UNIS_DECODE(node_count_); + if (OB_SUCC(ret)) { + if (OB_FAIL(deserialize_range_graph(node_head_, buf, data_len, pos))) { + LOG_WARN("failed to serialize range graph"); + } + } + OB_UNIS_DECODE(is_standard_range_); + OB_UNIS_DECODE(is_precise_get_); + OB_UNIS_DECODE(is_equal_range_); + OB_UNIS_DECODE(is_get_); + OB_UNIS_DECODE(contain_exec_param_); + if (OB_SUCC(ret)) { + column_metas_.reset(); + int64_t count = 0; + OB_UNIS_DECODE(count); + if (OB_SUCC(ret)) { + if (OB_FAIL(column_metas_.prepare_allocate(count))) { + LOG_WARN("failed to prepare allocate column meta", K(count)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { + ObRangeColumnMeta *column_meta = nullptr; + void *ptr = allocator_.alloc(sizeof(ObRangeColumnMeta)); + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("failed to allocate memeory for ObRangeColumnMeta"); + } else { + column_meta = new(ptr)ObRangeColumnMeta(); + OB_UNIS_DECODE(*column_meta); + if (OB_SUCC(ret)) { + column_metas_.at(i) = column_meta; + } + } + } + } + OB_UNIS_DECODE(range_map_); + OB_UNIS_DECODE(skip_scan_offset_); + OB_UNIS_DECODE(flags_); + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObPreRangeGraph) +{ + int64_t len = 0; + OB_UNIS_ADD_LEN(table_id_); + OB_UNIS_ADD_LEN(column_count_); + OB_UNIS_ADD_LEN(range_size_); + OB_UNIS_ADD_LEN(node_count_); + len += get_serialize_size_range_graph(node_head_); + OB_UNIS_ADD_LEN(is_standard_range_); + OB_UNIS_ADD_LEN(is_precise_get_); + OB_UNIS_ADD_LEN(is_equal_range_); + OB_UNIS_ADD_LEN(is_get_); + OB_UNIS_ADD_LEN(contain_exec_param_); + int64_t count = column_metas_.count(); + OB_UNIS_ADD_LEN(count); + for (int64_t i = 0; i < count; ++i) { + OB_UNIS_ADD_LEN(*column_metas_.at(i)); + } + OB_UNIS_ADD_LEN(range_map_); + OB_UNIS_ADD_LEN(skip_scan_offset_); + OB_UNIS_ADD_LEN(flags_); + return len; +} + + +DEF_TO_STRING(ObPreRangeGraph) +{ + int64_t pos = 0; + + J_ARRAY_START(); + if (NULL != node_head_) { + J_OBJ_START(); + J_KV(K_(table_id), + K_(is_equal_range), + K_(is_precise_get), + K_(is_standard_range), + K_(contain_exec_param)); + J_COMMA(); + J_NAME(N_RANGE_GRAPH); + J_COLON(); + J_OBJ_START(); + pos += range_graph_to_string(buf + pos, buf_len - pos, node_head_); + J_OBJ_END(); + J_OBJ_END(); + } + J_ARRAY_END(); + return pos; +} + +int64_t ObPreRangeGraph::range_graph_to_string(char *buf, + const int64_t buf_len, + ObRangeNode *range_node) const +{ + int64_t pos = 0; + bool is_stack_overflow = false; + int ret = OB_SUCCESS; + for (ObRangeNode *cur_node = range_node; cur_node != nullptr; cur_node = cur_node->or_next_) { + J_KV("range_node", *cur_node); + J_COMMA(); + if (cur_node->and_next_ != nullptr) { + pos += range_graph_to_string(buf + pos, buf_len - pos, cur_node->and_next_); + } + } + return pos; +} + +int64_t ObPreRangeGraph::set_total_range_sizes(uint64_t* total_range_sizes, int64_t count) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(total_range_sizes_.prepare_allocate(count))) { + LOG_WARN("failed to prepare allocate"); + } else { + for (int64_t i = 0; i < count; ++i) { + total_range_sizes_.at(i) = total_range_sizes[i]; + } + } + return ret; +} +int ObPreRangeGraph::get_total_range_sizes(common::ObIArray &total_range_sizes) const +{ + return total_range_sizes.assign(total_range_sizes_); +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/rewrite/ob_query_range_define.h b/src/sql/rewrite/ob_query_range_define.h new file mode 100644 index 000000000..dae5f278c --- /dev/null +++ b/src/sql/rewrite/ob_query_range_define.h @@ -0,0 +1,419 @@ +/** + * 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_REWRITE_OB_QUERY_RANGE_DEFINE_H_ +#define OCEANBASE_SQL_REWRITE_OB_QUERY_RANGE_DEFINE_H_ + +#include "lib/list/ob_obj_store.h" +#include "lib/allocator/ob_allocator.h" +#include "common/object/ob_object.h" +#include "sql/engine/expr/ob_expr_frame_info.h" +#include "lib/geo/ob_geo_common.h" +#include "sql/resolver/expr/ob_raw_expr.h" +#include "sql/rewrite/ob_query_range_provider.h" +#include "lib/hash/ob_placement_hashmap.h" +#include "sql/resolver/dml/ob_dml_stmt.h" + + + +namespace oceanbase +{ +namespace sql +{ +class ObExecContext; + +static const int64_t OB_RANGE_MAX_VALUE = INT64_MAX; +static const int64_t OB_RANGE_MIN_VALUE = INT64_MAX - 1; +static const int64_t OB_RANGE_EMPTY_VALUE = INT64_MAX - 2; +static const int64_t OB_RANGE_NULL_VALUE = INT64_MAX - 3; +static const int64_t OB_RANGE_EXTEND_VALUE = INT64_MAX - 4; +#define PHYSICAL_ROWID_IDX UINT8_MAX + +static const uint32_t OB_FINAL_EXPR_WITH_LOB_TRUNCATE = 1; + +class ObPreRangeGraph; +typedef common::ObIArray ExprConstrantArray; +class ObRangeNode +{ + OB_UNIS_VERSION(1); +public: + ObRangeNode(common::ObIAllocator &allocator) + : allocator_(allocator), + flags_(0), + column_cnt_(0), + start_keys_(nullptr), + end_keys_(nullptr), + min_offset_(-1), + max_offset_(-1), + in_param_count_(0), + node_id_(-1), + or_next_(nullptr), + and_next_(nullptr) {} + ~ObRangeNode() { reset(); } + void reset(); + void set_always_true(); + void set_always_false(); + int deep_copy(const ObRangeNode &other); + DECLARE_TO_STRING; +private: + DISALLOW_COPY_AND_ASSIGN(ObRangeNode); +public: + common::ObIAllocator &allocator_; + union { + uint32_t flags_; + struct { + uint32_t always_true_: 1; + uint32_t always_false_: 1; + uint32_t include_start_: 1; + uint32_t include_end_: 1; + uint32_t contain_in_: 1; + uint32_t is_phy_rowid_: 1; + uint32_t is_domain_node_: 1; + uint32_t is_not_in_node_: 1; + uint32_t reserved_: 24; + }; + }; + int64_t column_cnt_; + int64_t* start_keys_; + int64_t* end_keys_; + int64_t min_offset_; + int64_t max_offset_; + union { + int64_t in_param_count_; + struct { + uint32_t srid_; + int32_t domain_releation_type_; + } domain_extra_; + }; + int64_t node_id_; + //list member + ObRangeNode *or_next_; + ObRangeNode *and_next_; +}; + +typedef common::ObFixedArray InParam; + +struct ObRangeMap +{ + OB_UNIS_VERSION(1); +public: + struct ExprFinalInfo { + ExprFinalInfo() + : flags_(0), + param_idx_(OB_INVALID_ID) + {} + union { + uint32_t flags_; + struct { + uint32_t is_param_: 1; + uint32_t is_const_: 1; + uint32_t is_expr_: 1; + uint32_t null_safe_: 1; + /** + * rowid_idx_ = + * 0 : current final info is not rowid + * 1-129 : current final info is logical rowid + * 255 : current final info is physical rowid + */ + uint32_t rowid_idx_: 8; + uint32_t is_not_first_col_in_row_: 1; + uint32_t reserved_: 19; + }; + }; + union { + int64_t param_idx_; + common::ObObj* const_val_; + ObTempExpr *temp_expr_; + }; + TO_STRING_KV(K_(flags)); + }; +public: + ObRangeMap(common::ObIAllocator &alloc) + : allocator_(alloc), + expr_final_infos_(alloc), + in_params_(alloc) + {} + TO_STRING_KV(K_(expr_final_infos)); + common::ObIAllocator &allocator_; + common::ObFixedArray expr_final_infos_; + common::ObFixedArray in_params_; +}; + +class ObRangeColumnMeta +{ + OB_UNIS_VERSION(1); +public: + ObRangeColumnMeta() + : column_type_() + {} + + ObRangeColumnMeta(ObExprResType type) + : column_type_(type) + {} + + TO_STRING_KV(N_COLUMN_TYPE, column_type_); + + ObExprResType column_type_; +}; + +struct ObQueryRangeCtx +{ + ObQueryRangeCtx(ObExecContext *exec_ctx) + : column_cnt_(0), + need_final_extract_(false), + cur_is_precise_(false), + phy_rowid_for_table_loc_(false), + ignore_calc_failure_(false), + refresh_max_offset_(false), + exec_ctx_(exec_ctx), + expr_constraints_(nullptr), + params_(nullptr), + expr_factory_(nullptr), + session_info_(nullptr), + geo_column_id_map_(nullptr), + max_mem_size_(128*1024*1024), + enable_not_in_range_(true), + optimizer_features_enable_version_(0), + index_prefix_(-1), + is_geo_range_(false), + can_range_get_(true), + contail_geo_filters_(false) {} + ~ObQueryRangeCtx() {} + int init(ObPreRangeGraph *pre_range_graph, + const ObIArray &range_columns, + ExprConstrantArray *expr_constraints, + const ParamStore *params, + ObRawExprFactory *expr_factory, + const bool phy_rowid_for_table_loc, + const bool ignore_calc_failure, + const int64_t index_prefix, + const ColumnIdInfoMap *geo_column_id_map); + int64_t column_cnt_; + // 131 is the next prime number larger than OB_MAX_ROWKEY_COLUMN_NUMBER + common::hash::ObPlacementHashMap range_column_map_; + bool need_final_extract_; + // current expr can generate precise range + bool cur_is_precise_; + bool phy_rowid_for_table_loc_; + bool ignore_calc_failure_; + bool refresh_max_offset_; + ObExecContext *exec_ctx_; + ExprConstrantArray *expr_constraints_; + const common::ParamStore *params_; + ObRawExprFactory *expr_factory_; + ObSQLSessionInfo *session_info_; + common::ObSEArray final_exprs_; + common::ObSEArray final_exprs_flag_; + common::ObSEArray in_params_; + common::ObSEArray null_safe_value_idxs_; + common::ObSEArray column_metas_; + common::ObSEArray, 16> rowid_idxs_; + common::ObSEArray column_flags_; + common::ObSEArray non_first_in_row_value_idxs_; + const ColumnIdInfoMap *geo_column_id_map_; + int64_t max_mem_size_; + bool enable_not_in_range_; + uint64_t optimizer_features_enable_version_; + int64_t index_prefix_; + bool is_geo_range_; + bool can_range_get_; + bool contail_geo_filters_; +}; + +class ObPreRangeGraph : public ObQueryRangeProvider +{ +OB_UNIS_VERSION(1); +public: + ObPreRangeGraph(ObIAllocator &alloc) + : allocator_(alloc), + table_id_(OB_INVALID_ID), + column_count_(0), + range_size_(0), + node_count_(0), + node_head_(nullptr), + is_standard_range_(false), + is_precise_get_(false), + is_equal_range_(false), + is_get_(false), + contain_exec_param_(false), + column_metas_(alloc), + range_map_(alloc), + skip_scan_offset_(-1), + range_exprs_(alloc), + ss_range_exprs_(alloc), + unprecise_range_exprs_(alloc), + total_range_sizes_(alloc), + range_expr_max_offsets_(alloc), + flags_(0) {} + + virtual ~ObPreRangeGraph() { reset(); } + + void reset(); + virtual inline bool is_new_query_range() const { return true; } + virtual int deep_copy(const ObPreRangeGraph &other); + + int deep_copy_range_graph(ObRangeNode *src_node); + int inner_deep_copy_range_graph(ObRangeNode *range_node, + ObIArray &range_nodes, + ObIArray> &ptr_pairs); + int deep_copy_column_metas(const ObIArray &src_metas); + int deep_copy_range_map(const ObRangeMap &src_range_map); + + virtual int preliminary_extract_query_range(const ObIArray &range_columns, + const ObIArray &root_exprs, + ObExecContext *exec_ctx, + ExprConstrantArray *expr_constraints = NULL, + const ParamStore *params = NULL, + const bool phy_rowid_for_table_loc = false, + const bool ignore_calc_failure = true, + const int64_t index_prefix = -1, + const ColumnIdInfoMap *geo_column_id_map = NULL); + virtual int get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params) const; + virtual int get_tablet_ranges(ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params); + virtual int get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params, + ObIArray &mbr_filters) const; + virtual int get_fast_nlj_tablet_ranges(ObFastFinalNLJRangeCtx &fast_nlj_range_ctx, + common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + const ParamStore ¶m_store, + void *range_buffer, + ObQueryRangeArray &ranges, + const common::ObDataTypeCastParams &dtc_params) const; + int fill_column_metas(const ObIArray &range_columns); + virtual int get_ss_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ss_ranges, + const common::ObDataTypeCastParams &dtc_params) const; + virtual bool is_precise_whole_range() const { return (nullptr == node_head_) || (node_head_->always_true_); } + virtual int is_get(bool &is_get) const + { + is_get = is_get_; + return common::OB_SUCCESS; + } + virtual bool is_precise_get() const { return is_precise_get_; } + bool is_standard_range() const { return is_standard_range_; } + bool is_equal_range() const { return is_equal_range_; } + virtual int64_t get_column_count() const { return column_count_; } + virtual bool has_exec_param() const { return contain_exec_param_; } + virtual bool is_ss_range() const { return skip_scan_offset_ > -1; } + virtual int64_t get_skip_scan_offset() const { return skip_scan_offset_; } + virtual int reset_skip_scan_range() + { + skip_scan_offset_ = -1; + return common::OB_SUCCESS; + } + virtual inline bool has_range() const { return column_count_ > 0; } + virtual bool is_contain_geo_filters() const { return contain_geo_filters_; } + virtual const common::ObIArray &get_range_exprs() const { return range_exprs_; } + virtual const common::ObIArray &get_ss_range_exprs() const { return ss_range_exprs_; } + virtual const common::ObIArray &get_unprecise_range_exprs() const { return unprecise_range_exprs_; } + virtual int get_prefix_info(int64_t &equal_prefix_count, + int64_t &range_prefix_count, + bool &contain_always_false) const; + virtual int get_total_range_sizes(common::ObIArray &total_range_sizes) const; + + const ObIArray& get_range_sizes() const { return total_range_sizes_; } + virtual bool is_fast_nlj_range() const { return fast_nlj_range_; } + int get_prefix_info(const ObRangeNode *range_node, + bool* equals, + int64_t &equal_prefix_count) const; + int get_new_equal_idx(const ObRangeNode *range_node, + bool* equals, + ObIArray &new_idx) const; + + ObRangeNode* get_range_head() { return node_head_; } + const ObRangeNode* get_range_head() const { return node_head_; } + uint64_t get_table_id() const { return table_id_; } + uint64_t get_range_size() const { return range_size_; } + uint64_t get_node_count() const { return node_count_; } + int64_t get_column_cnt() const { return column_count_; } + ObIArray& get_column_metas() { return column_metas_; } + ObRangeColumnMeta* get_column_meta(int64_t idx) { return column_metas_.at(idx); } + const ObRangeColumnMeta* get_column_meta(int64_t idx) const { return column_metas_.at(idx); } + ObRangeMap& get_range_map() { return range_map_; } + const ObRangeMap& get_range_map() const { return range_map_; } + void set_table_id(const uint64_t v) { table_id_ = v; } + void set_range_size(const uint64_t v) { range_size_ = v; } + void set_node_count(const uint64_t v) { node_count_ = v; } + void set_range_head(ObRangeNode* head) { node_head_ = head; } + void set_is_standard_range(const bool v) { is_standard_range_ = v; } + void set_is_precise_get(const bool v) { is_precise_get_ = v; } + void set_is_equal_range(const bool v) { is_equal_range_ = v; } + void set_is_get(const bool v) { is_get_ = v; } + void set_contain_exec_param(const bool v) { contain_exec_param_ = v; } + void set_skip_scan_offset(int64_t v) { skip_scan_offset_ = v; } + int set_range_exprs(ObIArray &range_exprs) { return range_exprs_.assign(range_exprs); } + int set_ss_range_exprs(ObIArray &range_exprs) { return ss_range_exprs_.assign(range_exprs); } + int set_unprecise_range_exprs(ObIArray &range_exprs) { return unprecise_range_exprs_.assign(range_exprs); } + void set_fast_nlj_range(bool v) { fast_nlj_range_ = v; } + + int serialize_range_graph(ObRangeNode *range_node, char *buf, + int64_t buf_len, int64_t &pos) const; + int deserialize_range_graph(ObRangeNode *&range_node, const char *buf, + int64_t data_len, int64_t &pos); + int64_t get_serialize_size_range_graph(const ObRangeNode *range_node) const; + DECLARE_TO_STRING; + int64_t range_graph_to_string(char *buf, const int64_t buf_len, + ObRangeNode *range_node) const; + int64_t set_total_range_sizes(uint64_t* total_range_sizes, int64_t count); + void set_contain_geo_filters(bool v) { contain_geo_filters_ = v; } + int64_t set_range_expr_max_offsets(const ObIArray &max_offsets) { return range_expr_max_offsets_.assign(max_offsets); } + const ObIArray& get_range_expr_max_offsets() const { return range_expr_max_offsets_; } +private: + DISALLOW_COPY_AND_ASSIGN(ObPreRangeGraph); +private: + common::ObIAllocator &allocator_; + uint64_t table_id_; + int64_t column_count_; + uint64_t range_size_; + uint64_t node_count_; + ObRangeNode *node_head_; + // one range for all columns + bool is_standard_range_; + // one equal range for all columns. e.g. [1,2,3; 1,2,3] + bool is_precise_get_; + // one or more equal range for partial columns. e.g. (1,2,min; 1,2,max), (3,4,min; 3,4,max) + bool is_equal_range_; + // one or more equal range for all columns. e.g. [1,2,3; 1,2,3], [4,5,6; 4,5,6] + bool is_get_; + bool contain_exec_param_; + common::ObFixedArray column_metas_; + ObRangeMap range_map_; + int64_t skip_scan_offset_; + // only used by optimizer, don't need to serialize it + common::ObFixedArray range_exprs_; + common::ObFixedArray ss_range_exprs_; + common::ObFixedArray unprecise_range_exprs_; + common::ObFixedArray total_range_sizes_; + common::ObFixedArray range_expr_max_offsets_; + union { + uint32_t flags_; + struct { + uint32_t contain_geo_filters_ : 1; + uint32_t fast_nlj_range_ : 1; + uint32_t reserved_ : 30; + }; + }; +}; + +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_REWRITE_OB_QUERY_RANGE_DEFINE_H_ diff --git a/src/sql/rewrite/ob_query_range_provider.h b/src/sql/rewrite/ob_query_range_provider.h index 685258dbb..08db94078 100644 --- a/src/sql/rewrite/ob_query_range_provider.h +++ b/src/sql/rewrite/ob_query_range_provider.h @@ -16,7 +16,7 @@ #include "lib/container/ob_array.h" #include "lib/container/ob_se_array.h" #include "common/ob_range.h" - +#include "lib/geo/ob_s2adapter.h" namespace oceanbase { namespace common @@ -26,24 +26,78 @@ struct ObDataTypeCastParams; namespace sql { struct ColumnItem; +class ObRawExpr; typedef common::ObSEArray ObQueryRangeArray; typedef common::ObSEArray ObRangesArray; typedef common::ObSEArray ColumnArray; +static const int64_t MAX_NOT_IN_SIZE = 10; //do not extract range for not in row over this size +static const int64_t NEW_MAX_NOT_IN_SIZE = 1000; // mysql support 1000 not in range node + +struct ObFastFinalNLJRangeCtx +{ + ObFastFinalNLJRangeCtx() + : has_check_valid(false), + is_valid(false) {} + + bool has_check_valid; + bool is_valid; +}; class ObQueryRangeProvider { public: + virtual ~ObQueryRangeProvider() {} + virtual bool is_new_query_range() const = 0; + virtual int get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params) const = 0; virtual int get_tablet_ranges(ObQueryRangeArray &ranges, bool &all_single_value_ranges, const common::ObDataTypeCastParams &dtc_params) = 0; + virtual int get_ss_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ss_ranges, + const common::ObDataTypeCastParams &dtc_params) const = 0; + virtual int get_tablet_ranges(common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + ObQueryRangeArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params, + ObIArray &mbr_filters) const = 0; + virtual int get_fast_nlj_tablet_ranges(ObFastFinalNLJRangeCtx &fast_nlj_range_ctx, + common::ObIAllocator &allocator, + ObExecContext &exec_ctx, + const ParamStore ¶m_store, + void *range_buffer, + ObQueryRangeArray &ranges, + const common::ObDataTypeCastParams &dtc_params) const = 0; + virtual bool is_precise_whole_range() const = 0; + virtual int is_get(bool &is_get) const = 0; + virtual bool is_precise_get() const = 0; + virtual int64_t get_column_count() const = 0; + virtual bool has_exec_param() const = 0; + virtual bool is_ss_range() const = 0; + virtual int64_t get_skip_scan_offset() const = 0; + virtual int reset_skip_scan_range() = 0; + virtual bool has_range() const = 0; + virtual bool is_contain_geo_filters() const = 0; + virtual const common::ObIArray &get_range_exprs() const = 0; + virtual const common::ObIArray &get_ss_range_exprs() const = 0; + virtual const common::ObIArray &get_unprecise_range_exprs() const = 0; + virtual int get_prefix_info(int64_t &equal_prefix_count, + int64_t &range_prefix_count, + bool &contain_always_false) const = 0; // to string virtual int64_t to_string(char *buf, const int64_t buf_len) const = 0; + virtual int get_total_range_sizes(common::ObIArray &total_range_sizes) const = 0; + virtual bool is_fast_nlj_range() const = 0; }; + } } #endif //OCEANBASE_SQL_REWRITE_QUERY_RANGE_PROVIDER_ //// end of header file - - diff --git a/src/sql/rewrite/ob_range_generator.cpp b/src/sql/rewrite/ob_range_generator.cpp new file mode 100644 index 000000000..3d709624d --- /dev/null +++ b/src/sql/rewrite/ob_range_generator.cpp @@ -0,0 +1,2518 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX SQL_REWRITE +#include "sql/rewrite/ob_range_generator.h" +#include "lib/timezone/ob_time_convert.h" +#include "lib/container/ob_array_serialization.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/rc/ob_rc.h" +#include "sql/resolver/dml/ob_dml_stmt.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" +#include "common/ob_smart_call.h" +#include "sql/optimizer/ob_optimizer_util.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "sql/rewrite/ob_query_range.h" +#include "src/share/object/ob_obj_cast_util.h" +#include "sql/engine/expr/ob_expr_json_func_helper.h" +#include "sql/engine/expr/ob_expr_json_utils.h" + +namespace oceanbase +{ +using namespace common; +using namespace share::schema; +namespace sql +{ + +#define GET_RANGE_NODE_DOMAIN_TYPE(n) (static_cast((n)->domain_extra_.domain_releation_type_)) + +int ObTmpRange::copy(ObTmpRange &other) +{ + int ret = OB_SUCCESS; + if (this != &other) { + include_start_ = other.include_start_; + include_end_ = other.include_end_; + always_true_ = other.always_true_; + always_false_ = other.always_false_; + min_offset_ = other.min_offset_; + max_offset_ = other.max_offset_; + column_cnt_ = other.column_cnt_; + is_phy_rowid_ = other.is_phy_rowid_; + for (int64_t i = 0; i < column_cnt_; ++i) { + start_[i] = other.start_[i]; + end_[i] = other.end_[i]; + } + } + return ret; +} + +DEF_TO_STRING(ObTmpRange) +{ + int64_t pos = 0; + J_OBJ_START(); + // print parameters + J_KV(K(always_true_), + K(always_false_), + K(min_offset_), + K(max_offset_), + K(column_cnt_), + K(include_start_), + K(include_end_), + K(is_phy_rowid_)); + // print range + J_COMMA(); + BUF_PRINTF("range:"); + J_ARRAY_START(); + for (int64_t i = 0; i < column_cnt_; ++i) { + BUF_PRINTO(start_[i]); + if (i == column_cnt_ - 1) { + BUF_PRINTF("; "); + } else { + J_COMMA(); + } + } + for (int64_t i = 0; i < column_cnt_; ++i) { + BUF_PRINTO(end_[i]); + if (i < column_cnt_ - 1) { + J_COMMA(); + } + } + J_ARRAY_END(); + J_OBJ_END(); + return pos; +} + +int ObTmpRange::init_tmp_range(int64_t column_count) +{ + int ret = OB_SUCCESS; + void *start_ptr = NULL; + void *end_ptr = NULL; + if (OB_UNLIKELY(column_count <= 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected column count", K(column_count)); + } else if (OB_ISNULL(start_ptr = allocator_.alloc(sizeof(ObObj) * column_count)) || + OB_ISNULL(end_ptr = allocator_.alloc(sizeof(ObObj) * column_count))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("allocate memeory failed", K(start_ptr), K(end_ptr)); + } else { + start_ = new(start_ptr) ObObj[column_count]; + end_ = new(end_ptr) ObObj[column_count]; + column_cnt_ = column_count; + } + return ret; +} + +void ObTmpRange::set_always_true() +{ + always_true_ = true; + include_start_ = false; + include_end_ = false; + is_phy_rowid_ = false; + min_offset_ = 0; + max_offset_ = 0; + for (int64_t i = 0; i < column_cnt_; ++i) { + start_[i].set_min_value(); + end_[i].set_max_value(); + } +} + +void ObTmpRange::set_always_false() +{ + always_false_ = true; + include_start_ = false; + include_end_ = false; + is_phy_rowid_ = false; + min_offset_ = 0; + max_offset_ = 0; + for (int64_t i = 0; i < column_cnt_; ++i) { + start_[i].set_max_value(); + end_[i].set_min_value(); + } +} + +int ObTmpRange::intersect(ObTmpRange &other, bool ¬_consistent) +{ + int ret = OB_SUCCESS; + not_consistent = false; + if (OB_ISNULL(other.start_) || OB_ISNULL(other.end_) || + OB_ISNULL(start_) || OB_ISNULL(end_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(other.start_), K(other.end_), K(start_), K(end_)); + } else if (other.always_false_) { + set_always_false(); + } else if (other.always_true_ || always_false_) { + // do nothing + } else if (always_true_) { + if (OB_FAIL(copy(other))) { + LOG_WARN("failed to copy tmp range"); + } + } else if (min_offset_ <= other.min_offset_) { + if (max_offset_ < other.min_offset_ - 1) { + not_consistent = true; + } else { + // int64_t idx = other.min_offset_; + bool merge_start = false; + bool merge_end = false; + max_offset_ = std::max(max_offset_, other.max_offset_); + for (int64_t i = other.min_offset_; i < column_cnt_; ++i) { + int cmp = start_[i].compare(other.start_[i]); + if (cmp > 0) { + break; + } else if (cmp < 0) { + merge_start = true; + for (; i < column_cnt_; ++i) { + start_[i] = other.start_[i]; + } + include_start_ = other.include_start_; + } else if (i == column_cnt_ - 1) { + if (include_start_ && !other.include_start_) { + merge_start = true; + } + include_start_ = include_start_ && other.include_start_; + } + } + for (int64_t i = other.min_offset_; i < column_cnt_; ++i) { + int cmp = end_[i].compare(other.end_[i]); + if (cmp > 0) { + merge_end = true; + for (; i < column_cnt_; ++i) { + end_[i] = other.end_[i]; + } + include_end_ = other.include_end_; + } else if (cmp < 0) { + break; + } else if (i == column_cnt_ - 1) { + if (include_end_ && !other.include_end_) { + merge_end = true; + } + include_end_ = include_end_ && other.include_end_; + } + } + if (merge_start != merge_end) { + // only merge part of start key and end key, need to check if get always false range + bool always_false = false; + bool all_equal = true; + for (int64_t i = min_offset_; !always_false && i < column_cnt_; ++i) { + int cmp = start_[i].compare(end_[i]); + if (cmp > 0) { + always_false = true; + } else if (cmp < 0) { + break; + } else if (i == column_cnt_ - 1) { + always_false = !(include_start_ && include_end_); + } + } + if (always_false) { + set_always_false(); + } + } + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected offset", KPC(this), K(other)); + } + return ret; +} + +int ObTmpRange::formalize() +{ + int ret = OB_SUCCESS; + if (always_true_ || always_false_) { + // do nothing + } else { + bool always_true = true; + for (int64_t i = min_offset_; OB_SUCC(ret) && i < column_cnt_; ++i) { + if (start_[i].is_min_value() && end_[i].is_max_value()) { + // do nothing + } else if (OB_UNLIKELY(!start_[i].can_compare(end_[i]))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("start obj can not compare with end obj", K(start_[i]), K(end_[i])); + } else { + always_true = false; + int cmp = start_[i].compare(end_[i]); + if (cmp < 0) { + // find first start[i] < end[i], ignore following value + // e.g. (c1,c2) between (1,5) and (3,1) => (1, 5, max; 3, 1, min) + break; + } else if (cmp > 0) { + always_false_ = true; + break; + } else if (i == column_cnt_ - 1 && !(include_start_ && include_end_)) { + always_false_ = true; + } + } + } + if (OB_SUCC(ret)) { + if (always_true) { + always_true_ = always_true; + } else if (always_false_) { + set_always_false(); + } + } + } + return ret; +} + +int ObTmpRange::refine_final_range() +{ + int ret = OB_SUCCESS; + bool skip_start = false; + bool skip_end = false; + if (OB_ISNULL(start_) || OB_ISNULL(end_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(start_), K(end_)); + } else if (min_offset_ != 0) { + always_true_ = true; + include_start_ = false; + include_end_ = false; + for (int64_t i = 0; i < column_cnt_; ++i) { + start_[i].set_min_value(); + end_[i].set_max_value(); + } + } else { + // when find a min/max in start/end key, following start/end key is meanless. + // e.g. `(1, min, 3;` equal to `(1, min, min)` + bool find_min_start = false; + bool find_max_end = false; + for (int64_t i = 0; i < column_cnt_; ++i) { + if (find_min_start) { + start_[i].set_min_value(); + include_start_ = false; + } else if (start_[i].is_min_value()) { + find_min_start = true; + include_start_ = false; + } else if (OB_UNLIKELY(start_[i].is_nop_value())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected nop value"); + } + if (find_max_end) { + end_[i].set_max_value(); + include_end_ = false; + } else if (end_[i].is_max_value()) { + find_max_end = true; + include_end_ = false; + } else if (OB_UNLIKELY(end_[i].is_nop_value())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected nop value"); + } + } + } + return ret; +} + +int ObRangeGenerator::generate_tmp_range(ObTmpRange *&tmp_range, const int64_t column_cnt) +{ + int ret = OB_SUCCESS; + tmp_range = nullptr; + if (OB_ISNULL(tmp_range = static_cast(allocator_.alloc(sizeof(ObTmpRange))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("alloc memory failed"); + } else { + new(tmp_range) ObTmpRange(allocator_); + if (OB_FAIL(tmp_range->init_tmp_range(column_cnt))) { + LOG_WARN("failed to init tmp range"); + } + } + return ret; +} + +int ObRangeGenerator::generate_one_range(ObTmpRange &tmp_range) +{ + int ret = OB_SUCCESS; + ObNewRange *range = nullptr; + if (OB_FAIL(create_new_range(range, tmp_range.column_cnt_))) { + LOG_WARN("failed to create new range"); + } else if (OB_FAIL(tmp_range.refine_final_range())) { + LOG_WARN("failed to refine final range"); + } else { + ObObj *starts = range->start_key_.get_obj_ptr(); + ObObj *ends = range->end_key_.get_obj_ptr(); + for (int i = 0; OB_SUCC(ret) && i < tmp_range.column_cnt_; ++i) { + new(starts + i) ObObj(); + new(ends + i) ObObj(); + if (OB_FAIL(ob_write_obj(allocator_, *(tmp_range.start_ + i), *(starts + i)))) { + LOG_WARN("deep copy start obj failed", K(i)); + } else if (OB_FAIL(ob_write_obj(allocator_, *(tmp_range.end_ + i), *(ends + i)))) { + LOG_WARN("deep copy end obj failed", K(i)); + } + } + if (OB_SUCC(ret)) { + range->is_physical_rowid_range_ = tmp_range.is_phy_rowid_; + if (OB_UNLIKELY(tmp_range.is_phy_rowid_ && tmp_range.column_cnt_ > 1)) { + // rowid for table location, only has one column + if (starts[1].is_min_value()) { + range->border_flag_.set_inclusive_start(); + } else { + range->border_flag_.unset_inclusive_start(); + } + if (ends[1].is_max_value()) { + range->border_flag_.set_inclusive_end(); + } else { + range->border_flag_.unset_inclusive_end(); + } + range->start_key_.assign(starts, 1); + range->end_key_.assign(ends, 1); + } else { + if (tmp_range.include_start_) { + range->border_flag_.set_inclusive_start(); + } else { + range->border_flag_.unset_inclusive_start(); + } + if (tmp_range.include_end_) { + range->border_flag_.set_inclusive_end(); + } else { + range->border_flag_.unset_inclusive_end(); + } + } + if (tmp_range.always_false_) { + always_false_range_ = range; + } else if (tmp_range.always_true_) { + always_true_range_ = range; + all_single_value_ranges_ = false; + } else if (OB_FAIL(ranges_.push_back(range))) { + LOG_WARN("failed to push back range"); + } else if (!(range->border_flag_.inclusive_start() && + range->border_flag_.inclusive_end() && + range->start_key_ == range->end_key_)) { + all_single_value_ranges_ = false; + } + } + LOG_TRACE("succeed to generate one range", KPC(range), K(tmp_range)); + } + return ret; +} + +int ObRangeGenerator::generate_ranges() +{ + int ret = OB_SUCCESS; + ObPhysicalPlanCtx *phy_ctx = exec_ctx_.get_physical_plan_ctx(); + if (OB_ISNULL(pre_range_graph_) || OB_ISNULL(phy_ctx) || + OB_ISNULL(pre_range_graph_->get_range_head())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range graph", KPC(pre_range_graph_), K(phy_ctx)); + } else if (pre_range_graph_->has_exec_param() && !phy_ctx->is_exec_param_readable()) { + // pre range graph has exec param and not exec stage, generate (min; max) + if (OB_FAIL(generate_contain_exec_param_range())) { + LOG_WARN("faield to generate contain exec param range"); + } + } else if (OB_LIKELY(pre_range_graph_->is_precise_get())) { + if (OB_FAIL(generate_precise_get_range(*pre_range_graph_->get_range_head()))) { + LOG_WARN("failed to genenrate precise get range"); + } + } else if (pre_range_graph_->is_standard_range()) { + if (OB_FAIL(generate_standard_ranges(pre_range_graph_->get_range_head()))) { + LOG_WARN("failed to genenrate precise get range"); + } + } else if (OB_FAIL(generate_complex_ranges(pre_range_graph_->get_range_head()))) { + LOG_WARN("failed to generate final ranges"); + } + return ret; +} + +OB_INLINE int ObRangeGenerator::generate_precise_get_range(const ObRangeNode &node) +{ + int ret = OB_SUCCESS; + ObNewRange *range = nullptr; + if (OB_NOT_NULL(node.and_next_) || OB_NOT_NULL(node.or_next_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected precise get range", K(node)); + } else if (OB_FAIL(create_new_range(range, node.column_cnt_))) { + LOG_WARN("failed to create new range"); + } else { + bool always_false = false; + ObObj *starts = range->start_key_.get_obj_ptr(); + ObObj *ends = range->end_key_.get_obj_ptr(); + for (int64_t i = 0; i < node.column_cnt_; ++i) { + starts[i].set_min_value(); + ends[i].set_max_value(); + } + for (int i = 0; OB_SUCC(ret) && !always_false && i < node.column_cnt_; ++i) { + int64_t start_idx = node.start_keys_[i]; + int64_t end_idx = node.end_keys_[i]; + const ObRangeColumnMeta *meta = pre_range_graph_->get_column_meta(i); + int64_t cmp = 0; + bool is_valid = true; + if (OB_ISNULL(meta)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (OB_UNLIKELY(start_idx != end_idx || + !is_const_expr_or_null(start_idx) || + !is_const_expr_or_null(end_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("start idx should equal to end idx", K(start_idx), K(end_idx)); + } else if (start_idx == OB_RANGE_NULL_VALUE) { + starts[i].set_null(); + ends[i].set_null(); + } else if (OB_FAIL(get_result_value(start_idx, starts[i], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result vlaue", K(start_idx)); + } else if (!is_valid) { + always_false = true; + } else if (OB_LIKELY(ObSQLUtils::is_same_type_for_compare(starts[i].get_meta(), + meta->column_type_.get_obj_meta()) && + !starts[i].is_decimal_int())) { + starts[i].set_collation_type(meta->column_type_.get_collation_type()); + } else if (OB_LIKELY(!starts[i].is_overflow_integer(meta->column_type_.get_type()))) { + //fast cast with integer value + starts[i].set_meta_type(meta->column_type_); + } else if (!node.is_phy_rowid_ && OB_FAIL(try_cast_value(*meta, starts[i], cmp, CO_EQ))) { + LOG_WARN("failed to cast value", K(meta), K(starts[i])); + } else if (cmp != 0) { + always_false = true; + } else { + starts[i].set_collation_type(meta->column_type_.get_collation_type()); + } + if (OB_SUCC(ret) && !always_false) { + ends[i] = starts[i]; + } + } + + if (OB_SUCC(ret)) { + range->is_physical_rowid_range_ = node.is_phy_rowid_; + if (OB_LIKELY(!always_false)) { + range->border_flag_.set_inclusive_start(); + range->border_flag_.set_inclusive_end(); + } else { + range->border_flag_.unset_inclusive_start(); + range->border_flag_.unset_inclusive_end(); + for (int i = 0; i < node.column_cnt_; ++i) { + starts[i].set_max_value(); + ends[i].set_min_value(); + } + all_single_value_ranges_ = false; + } + if (OB_FAIL(ranges_.push_back(range))) { + LOG_WARN("failed to push back range"); + } + } + } + return ret; +} + +/** + * standard range doesn't have any or_next node, we can merge each range node directly +*/ +int ObRangeGenerator::generate_standard_ranges(const ObRangeNode *node) +{ + int ret = OB_SUCCESS; + ObTmpRange *init_range = nullptr; + if (OB_FAIL(generate_tmp_range(init_range, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } else { + init_range->set_always_true(); + if (OB_FAIL(formalize_standard_range(node, *init_range))) { + LOG_WARN("failed to formalize range"); + } else if (OB_FAIL(merge_and_remove_ranges())) { + LOG_WARN("faield to merge and remove ranges"); + } + } + return ret; +} + +int ObRangeGenerator::formalize_standard_range(const ObRangeNode *node, ObTmpRange &range) +{ + int ret = OB_SUCCESS; + ObTmpRange *new_range = nullptr; + bool not_consistent = false; + if (OB_UNLIKELY(node->contain_in_) || OB_NOT_NULL(node->or_next_) || + OB_UNLIKELY(node->is_not_in_node_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node in standard range", KPC(node)); + } else if (OB_FAIL(final_range_node(node, new_range, false))) { + LOG_WARN("failed to final range node"); + } else if (OB_FAIL(range.intersect(*new_range, not_consistent))) { + LOG_WARN("failed to do tmp range intersect"); + } else if (not_consistent || node->and_next_ == nullptr) { + if (is_generate_ss_range_) { + range.column_cnt_ -= pre_range_graph_->get_skip_scan_offset(); + range.min_offset_ -= pre_range_graph_->get_skip_scan_offset(); + range.max_offset_ -= pre_range_graph_->get_skip_scan_offset(); + range.start_ += pre_range_graph_->get_skip_scan_offset(); + range.end_ += pre_range_graph_->get_skip_scan_offset(); + } + if (OB_FAIL(generate_one_range(range))) { + LOG_WARN("faield to generate one range", K(range)); + } + } else if (OB_FAIL(SMART_CALL(formalize_standard_range(node->and_next_, range)))) { + LOG_WARN("failed to formalize range"); + } + return ret; +} + +/** + * complex range contain or_next node, offset of range node may not consistent along and_next. + * For example, (c1 > 1 or c2 > 1) and c1 = 2 will generate a range graph like this. + * c1 -- c1 + * | / + * c2 - + * We final each range node firstly and merge them laterly. +*/ +int ObRangeGenerator::generate_complex_ranges(const ObRangeNode *node) +{ + int ret = OB_SUCCESS; + bool need_merge = true; + tmp_range_lists_ = static_cast( + allocator_.alloc(sizeof(TmpRangeList) * pre_range_graph_->get_column_cnt())); + if (OB_ISNULL(tmp_range_lists_)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for tmp range list"); + } else if (OB_FAIL(all_tmp_ranges_.prepare_allocate(pre_range_graph_->get_node_count()))) { + LOG_WARN("failed to init fixed array size"); + } else if (OB_FAIL(all_tmp_node_caches_.prepare_allocate(pre_range_graph_->get_node_count()))) { + LOG_WARN("failed to init fixed array size"); + } else if (nullptr == always_false_tmp_range_ && + OB_FAIL(generate_tmp_range(always_false_tmp_range_, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } else { + always_false_tmp_range_->set_always_false(); + for (int64_t i = 0; i < pre_range_graph_->get_node_count(); ++i) { + all_tmp_ranges_.at(i) = nullptr; + } + for (int64_t i = 0; i < pre_range_graph_->get_column_cnt(); ++i) { + new(tmp_range_lists_ + i)TmpRangeList(); + } + for (int64_t i = 0; i < pre_range_graph_->get_node_count(); ++i) { + all_tmp_node_caches_.at(i) = nullptr; + } + if (OB_FAIL(formalize_complex_range(node))) { + LOG_WARN("failed to formalize range"); + } else if (OB_FAIL(check_need_merge_range_nodes(node, need_merge))) { + LOG_WARN("failed to check need merge range nodes"); + } else if (!need_merge) { + // do nothing + } else if (OB_FAIL(merge_and_remove_ranges())) { + LOG_WARN("faield to merge and remove ranges"); + } + } + return ret; +} + + + +int ObRangeGenerator::formalize_complex_range(const ObRangeNode *node) +{ + int ret = OB_SUCCESS; + int64_t pre_node_offset = -1; + bool add_last = false; + for (const ObRangeNode *cur_node = node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->or_next_) { + if (pre_node_offset != -1 && add_last) { + tmp_range_lists_[pre_node_offset].remove_last(); + } + add_last = false; + // min_offset = -1 means current node is a const value node. After final node will become always true of false. + pre_node_offset = cur_node->min_offset_ == -1 ? 0 : cur_node->min_offset_; + if (!cur_node->contain_in_ && + !cur_node->is_not_in_node_ && + !cur_node->is_domain_node_) { + ObTmpRange *new_range = nullptr; + if (OB_FAIL(final_range_node(cur_node, new_range, true))) { + LOG_WARN("failed to final range node"); + } else if (new_range->always_false_) { + if (OB_FAIL(generate_one_range(*new_range))) { + LOG_WARN("failed to generate one range", KPC(new_range)); + } + } else { + if (new_range->always_true_) { + // do nothing + } else if (OB_UNLIKELY(!tmp_range_lists_[pre_node_offset].add_last(new_range))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to add last to dlist", KPC(new_range)); + } else { + add_last = true; + } + if (OB_FAIL(ret)) { + } else if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(generate_one_complex_range())) { + LOG_WARN("faield to generate one range"); + } + } else if (OB_FAIL(SMART_CALL(formalize_complex_range(cur_node->and_next_)))) { + LOG_WARN("failed to formalize range"); + } + } + } else if (cur_node->contain_in_) { + for (int64_t i = 0; OB_SUCC(ret) && i < cur_node->in_param_count_; ++i) { + ObTmpRange *new_range = nullptr; + if (pre_node_offset != -1 && add_last) { + tmp_range_lists_[pre_node_offset].remove_last(); + } + add_last = false; + if (OB_FAIL(final_in_range_node(cur_node, i, new_range))) { + LOG_WARN("failed to final in range node"); + } else if (new_range->always_false_) { + if (OB_FAIL(generate_one_range(*new_range))) { + LOG_WARN("failed to generate one range", KPC(new_range)); + } + } else { + if (new_range->always_true_) { + // do nothing + } else if (OB_UNLIKELY(!tmp_range_lists_[pre_node_offset].add_last(new_range))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to add last to dlist", KPC(new_range)); + } else { + add_last = true; + } + if (OB_FAIL(ret)) { + } else if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(generate_one_complex_range())) { + LOG_WARN("faield to generate one range"); + } + } else if (OB_FAIL(SMART_CALL(formalize_complex_range(cur_node->and_next_)))) { + LOG_WARN("failed to formalize range"); + } + } + } + } else if (cur_node->is_not_in_node_) { + bool always_false = false; + ObTmpInParam *tmp_in_param = nullptr; + if (OB_FAIL(generate_tmp_not_in_param(*cur_node, tmp_in_param))) { + LOG_WARN("failed to generate tmp not in param", K(ret)); + } else if (OB_ISNULL(tmp_in_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(tmp_in_param)); + } else if (tmp_in_param->always_false_) { + if (OB_FAIL(generate_one_range(*always_false_tmp_range_))) { + LOG_WARN("failed to generate one range", K(ret)); + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < tmp_in_param->in_param_.count() + 1; ++i) { + ObTmpRange *new_range = nullptr; + if (pre_node_offset != -1 && add_last) { + tmp_range_lists_[pre_node_offset].remove_last(); + } + add_last = false; + if (OB_FAIL(final_not_in_range_node(*cur_node, i, tmp_in_param, new_range))) { + LOG_WARN("failed to final in range node"); + } else if (OB_UNLIKELY(!tmp_range_lists_[pre_node_offset].add_last(new_range))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to add last to dlist", KPC(new_range)); + } else if (OB_FALSE_IT(add_last = true)) { + } else if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(generate_one_complex_range())) { + LOG_WARN("faield to generate one range"); + } + } else if (OB_FAIL(SMART_CALL(formalize_complex_range(cur_node->and_next_)))) { + LOG_WARN("failed to formalize range"); + } + } + } + } else if (cur_node->is_domain_node_ && + is_geo_type(GET_RANGE_NODE_DOMAIN_TYPE(cur_node))) { + ObTmpGeoParam *tmp_geo_param = nullptr; + if (OB_FAIL(generate_tmp_geo_param(*cur_node, tmp_geo_param))) { + LOG_WARN("failed to generate tmp geo param", K(ret)); + } else if (OB_ISNULL(tmp_geo_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (tmp_geo_param->always_true_) { + if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(generate_one_complex_range())) { + LOG_WARN("faield to generate one range"); + } + } else if (OB_FAIL(SMART_CALL(formalize_complex_range(cur_node->and_next_)))) { + LOG_WARN("failed to formalize range"); + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < tmp_geo_param->start_keys_.count(); ++i) { + ObTmpRange *new_range = nullptr; + if (pre_node_offset != -1 && add_last) { + tmp_range_lists_[pre_node_offset].remove_last(); + } + add_last = false; + if (OB_FAIL(final_geo_range_node(*cur_node, + tmp_geo_param->start_keys_.at(i), + tmp_geo_param->end_keys_.at(i), + new_range))) { + LOG_WARN("failed to final in range node"); + } else if (OB_UNLIKELY(!tmp_range_lists_[pre_node_offset].add_last(new_range))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to add last to dlist", KPC(new_range)); + } else if (OB_FALSE_IT(add_last = true)) { + } else if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(generate_one_complex_range())) { + LOG_WARN("faield to generate one range"); + } + } else if (OB_FAIL(SMART_CALL(formalize_complex_range(cur_node->and_next_)))) { + LOG_WARN("failed to formalize range"); + } + } + } + } else if (cur_node->is_domain_node_ && + ObDomainOpType::T_JSON_MEMBER_OF == GET_RANGE_NODE_DOMAIN_TYPE(cur_node)) { + ObTmpRange *new_range = nullptr; + if (OB_FAIL(final_json_member_of_range_node(cur_node, new_range, true))) { + LOG_WARN("failed to final range node"); + } else if (new_range->always_false_) { + if (OB_FAIL(generate_one_range(*new_range))) { + LOG_WARN("failed to generate one range", KPC(new_range)); + } + } else { + if (new_range->always_true_) { + // do nothing + } else if (OB_UNLIKELY(!tmp_range_lists_[pre_node_offset].add_last(new_range))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to add last to dlist", KPC(new_range)); + } else { + add_last = true; + } + if (OB_FAIL(ret)) { + } else if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(generate_one_complex_range())) { + LOG_WARN("faield to generate one range"); + } + } else if (OB_FAIL(SMART_CALL(formalize_complex_range(cur_node->and_next_)))) { + LOG_WARN("failed to formalize range"); + } + } + } else if (cur_node->is_domain_node_ && + (ObDomainOpType::T_JSON_CONTAINS == GET_RANGE_NODE_DOMAIN_TYPE(cur_node) || + ObDomainOpType::T_JSON_OVERLAPS == GET_RANGE_NODE_DOMAIN_TYPE(cur_node))) { + ObTmpInParam *tmp_in_param = nullptr; + if (OB_FAIL(generate_tmp_json_array_param(*cur_node, tmp_in_param))) { + LOG_WARN("failed to generate tmp not in param", K(ret)); + } else if (OB_ISNULL(tmp_in_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(tmp_in_param)); + } else if (tmp_in_param->always_false_) { + if (OB_FAIL(generate_one_range(*always_false_tmp_range_))) { + LOG_WARN("failed to generate one range", K(ret)); + } + } else if (tmp_in_param->always_true_) { + if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(generate_one_complex_range())) { + LOG_WARN("faield to generate one range"); + } + } else if (OB_FAIL(SMART_CALL(formalize_complex_range(cur_node->and_next_)))) { + LOG_WARN("failed to formalize range"); + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < tmp_in_param->in_param_.count(); ++i) { + ObTmpRange *new_range = nullptr; + if (pre_node_offset != -1 && add_last) { + tmp_range_lists_[pre_node_offset].remove_last(); + } + add_last = false; + if (OB_FAIL(final_domain_range_node(*cur_node, i, tmp_in_param, new_range))) { + LOG_WARN("failed to final in range node"); + } else if (OB_UNLIKELY(!tmp_range_lists_[pre_node_offset].add_last(new_range))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to add last to dlist", KPC(new_range)); + } else if (OB_FALSE_IT(add_last = true)) { + } else if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(generate_one_complex_range())) { + LOG_WARN("faield to generate one range"); + } + } else if (OB_FAIL(SMART_CALL(formalize_complex_range(cur_node->and_next_)))) { + LOG_WARN("failed to formalize range"); + } + } + } + } + } + if (OB_SUCC(ret) && pre_node_offset != -1 && add_last) { + tmp_range_lists_[pre_node_offset].remove_last(); + } + return ret; +} + +int ObRangeGenerator::generate_one_complex_range() +{ + int ret = OB_SUCCESS; + ObTmpRange *range = nullptr; + bool and_next = true; + if (OB_FAIL(generate_tmp_range(range, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } else { + range->set_always_true(); + } + for (int64_t i = 0; OB_SUCC(ret) && and_next && i < pre_range_graph_->get_column_cnt(); ++i) { + DLIST_FOREACH_X(cur_range, tmp_range_lists_[i], (OB_SUCC(ret) && and_next)) { + bool not_consistent = false; + if (OB_ISNULL(cur_range)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range node"); + } else if (OB_FAIL(range->intersect(*cur_range, not_consistent))) { + LOG_WARN("failed to do tmp range intersect"); + } else if (not_consistent) { + and_next = false; + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(generate_one_range(*range))) { + LOG_WARN("faield to generate one range", K(range)); + } + } + return ret; +} + +int ObRangeGenerator::final_range_node(const ObRangeNode *node, ObTmpRange *&range, bool need_cache) { + int ret = OB_SUCCESS; + range = need_cache ? all_tmp_ranges_.at(node->node_id_) : nullptr; + if (range != nullptr) { + // already generated + } else if (OB_FAIL(generate_tmp_range(range, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } else { + bool always_false = false; + bool check_next = true; + int64_t truncated_key_idx_start = -1; + int64_t truncated_key_idx_end = -1; + for (int64_t i = 0; OB_SUCC(ret) && !always_false && i < pre_range_graph_->get_column_cnt(); ++i) { + int64_t start = node->start_keys_[i]; + int64_t end = node->end_keys_[i]; + bool is_valid = true; + if (start == OB_RANGE_EMPTY_VALUE && end == OB_RANGE_EMPTY_VALUE) { + range->min_offset_++; + range->start_[i].set_nop_value(); + range->end_[i].set_nop_value(); + } else if (OB_UNLIKELY(start == OB_RANGE_EMPTY_VALUE || end == OB_RANGE_EMPTY_VALUE)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", KPC(node)); + } else { + if (start == OB_RANGE_MIN_VALUE) { + range->start_[i].set_min_value(); + } else if (start == OB_RANGE_MAX_VALUE) { + range->start_[i].set_max_value(); + } else if (start == OB_RANGE_NULL_VALUE) { + range->start_[i].set_null(); + } else if (OB_FAIL(get_result_value(start, range->start_[i], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result vlaue", K(start)); + } else if (!is_valid) { + const ObRangeMap::ExprFinalInfo& expr_info = range_map_.expr_final_infos_.at(start); + if (expr_info.is_not_first_col_in_row_ && -1 == truncated_key_idx_start) { + truncated_key_idx_start = i; + } else { + always_false = true; + } + } + if (OB_FAIL(ret) || always_false) { + } else if (end == OB_RANGE_MIN_VALUE) { + range->end_[i].set_min_value(); + } else if (end == OB_RANGE_MAX_VALUE) { + range->end_[i].set_max_value(); + } else if (end == OB_RANGE_NULL_VALUE) { + range->end_[i].set_null(); + } else if (OB_FAIL(get_result_value(end, range->end_[i], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result vlaue", K(end)); + } else if (!is_valid) { + const ObRangeMap::ExprFinalInfo& expr_info = range_map_.expr_final_infos_.at(end); + if (expr_info.is_not_first_col_in_row_ && -1 == truncated_key_idx_end) { + truncated_key_idx_end = i; + } else { + always_false = true; + } + } + } + } + if (OB_SUCC(ret) && truncated_key_idx_start != -1) { + for (int64_t i = truncated_key_idx_start; i < pre_range_graph_->get_column_cnt(); ++i) { + range->start_[i].set_min_value(); + } + } + if (OB_SUCC(ret) && truncated_key_idx_end != -1) { + for (int64_t i = truncated_key_idx_end; i < pre_range_graph_->get_column_cnt(); ++i) { + range->end_[i].set_max_value(); + } + } + if (OB_SUCC(ret)) { + if (always_false) { + range->set_always_false(); + } else { + range->include_start_ = node->include_start_; + range->include_end_ = node->include_end_; + range->is_phy_rowid_ = node->is_phy_rowid_; + range->min_offset_ = node->min_offset_ > 0 ? node->min_offset_ : 0; + range->max_offset_ = node->max_offset_ > 0 ? node->max_offset_ : 0; + if (!node->is_phy_rowid_ && OB_FAIL(cast_value_type(*range))) { + LOG_WARN("cast value type failed", K(ret)); + } else if (need_cache) { + all_tmp_ranges_.at(node->node_id_) = range; + } + } + } + } + return ret; +} + +int ObRangeGenerator::final_in_range_node(const ObRangeNode *node, + const int64_t in_idx, + ObTmpRange *&range) { + int ret = OB_SUCCESS; + if (OB_UNLIKELY(node->node_id_ < 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected node", K(node->node_id_)); + } else if (OB_FALSE_IT(range = all_tmp_ranges_.at(node->node_id_))) { + } else if (range == nullptr && OB_FAIL(generate_tmp_range(range, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } else { + range->always_false_ = false; + bool always_false = false; + for (int64_t i = 0; OB_SUCC(ret) && !always_false && i < pre_range_graph_->get_column_cnt(); ++i) { + int64_t start = node->start_keys_[i]; + int64_t end = node->end_keys_[i]; + bool is_valid = true; + if (start == OB_RANGE_EMPTY_VALUE && end == OB_RANGE_EMPTY_VALUE) { + range->min_offset_++; + range->start_[i].set_nop_value(); + range->end_[i].set_nop_value(); + } else if (OB_UNLIKELY(start == OB_RANGE_EMPTY_VALUE || end == OB_RANGE_EMPTY_VALUE)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", KPC(node)); + } else { + if (start == OB_RANGE_MIN_VALUE) { + range->start_[i].set_min_value(); + } else if (start == OB_RANGE_MAX_VALUE) { + range->start_[i].set_max_value(); + } else if (start == OB_RANGE_NULL_VALUE) { + range->start_[i].set_null(); + } else if (start >= 0) { + if (OB_FAIL(get_result_value(start, range->start_[i], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result vlaue", K(start)); + } else if (!is_valid) { + always_false = true; + } + } else { + int64_t param_idx = -start - 1; + InParam *in_param = nullptr; + if (OB_UNLIKELY(param_idx < 0 || param_idx >= range_map_.in_params_.count()) || + OB_ISNULL(in_param = range_map_.in_params_.at(param_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected in param", K(param_idx), K(range_map_.in_params_.count()), + K(in_param)); + } else if (OB_FAIL(get_result_value(in_param->at(in_idx), range->start_[i], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result vlaue", K(start)); + } else if (!is_valid) { + always_false = true; + } + } + + if (OB_FAIL(ret) || always_false) { + } else if (end == OB_RANGE_MIN_VALUE) { + range->end_[i].set_min_value(); + } else if (end == OB_RANGE_MAX_VALUE) { + range->end_[i].set_max_value(); + } else if (end == OB_RANGE_NULL_VALUE) { + range->end_[i].set_null(); + } else if (end >= 0) { + if (OB_FAIL(get_result_value(end, range->end_[i], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result vlaue", K(end)); + } else if (!is_valid) { + always_false = true; + } + } else if (OB_LIKELY(end == start)) { + range->end_[i] = range->start_[i]; + } else { + int64_t param_idx = -end - 1; + InParam *in_param = nullptr; + if (OB_UNLIKELY(param_idx < 0 || param_idx >= range_map_.in_params_.count()) || + OB_ISNULL(in_param = range_map_.in_params_.at(param_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected in param", K(param_idx), K(range_map_.in_params_.count()), + K(in_param)); + } else if (OB_FAIL(get_result_value(in_param->at(in_idx), range->end_[i], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result vlaue", K(start)); + } else if (!is_valid) { + always_false = true; + } + } + } + } + if (OB_SUCC(ret)) { + if (always_false) { + range->set_always_false(); + } else { + range->include_start_ = node->include_start_; + range->include_end_ = node->include_end_; + range->is_phy_rowid_ = node->is_phy_rowid_; + range->min_offset_ = node->min_offset_ > 0 ? node->min_offset_ : 0; + range->max_offset_ = node->max_offset_ > 0 ? node->max_offset_ : 0; + if (!node->is_phy_rowid_ && OB_FAIL(cast_value_type(*range))) { + LOG_WARN("cast value type failed", K(ret)); + } else { + all_tmp_ranges_.at(node->node_id_) = range; + } + } + } + } + return ret; +} + +int ObRangeGenerator::get_result_value(const int64_t val_idx, + ObObj &value, + bool &is_valid, + ObExecContext &exec_ctx) const +{ + int ret = OB_SUCCESS; + ObPhysicalPlanCtx *phy_ctx = NULL; + is_valid = true; + if (OB_ISNULL(phy_ctx = exec_ctx.get_physical_plan_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null"); + } else if (OB_UNLIKELY(val_idx < 0 || val_idx >= range_map_.expr_final_infos_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid param idx", K(val_idx)); + } else { + const ObRangeMap::ExprFinalInfo& expr_info = range_map_.expr_final_infos_.at(val_idx); + if (expr_info.is_param_) { + int64_t idx = expr_info.param_idx_; + if (OB_UNLIKELY(idx < 0 || idx >= phy_ctx->get_param_store().count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid param idx", K(idx)); + } else { + value = phy_ctx->get_param_store().at(idx); + if (OB_UNLIKELY(value.is_nop_value())) { + ret = OB_ERR_UNEXPECTED; + } else if (value.is_lob_storage()) { + if (OB_FAIL(ObTextStringIter::convert_outrow_lob_to_inrow_templob(value, value, NULL, &allocator_, true))) { + LOG_WARN("fail to convert to inrow lob", K(value)); + } + } + } + } else if (expr_info.is_const_) { + ObObj *const_obj = expr_info.const_val_; + if (OB_ISNULL(const_obj)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null const obj"); + } else if (OB_FALSE_IT(value = *const_obj)) { + } else if (OB_UNLIKELY(value.is_nop_value())) { + ret = OB_ERR_UNEXPECTED; + } else if (value.is_lob_storage()) { + if (OB_FAIL(ObTextStringIter::convert_outrow_lob_to_inrow_templob(value, value, NULL, &allocator_, true))) { + LOG_WARN("fail to convert to inrow lob", K(value)); + } + } + } else if (expr_info.is_expr_) { + ObTempExpr *temp_expr = expr_info.temp_expr_; + ObNewRow tmp_row; + ObObj result; + if (OB_ISNULL(temp_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null temp expr", K(expr_info)); + } else if (OB_FAIL(temp_expr->eval(exec_ctx, tmp_row, result))) { + LOG_WARN("failed to eval temp expr"); + } else if (OB_UNLIKELY(result.is_nop_value())) { + ret = OB_ERR_UNEXPECTED; + } else if (result.is_lob_storage()) { + if (OB_FAIL(ObTextStringIter::convert_outrow_lob_to_inrow_templob(result, value, NULL, &allocator_, true, true))) { + LOG_WARN("fail to convert to inrow lob", K(ret), K(result)); + } + } else if (OB_FAIL(ob_write_obj(allocator_, result, value))) { + LOG_WARN("failed to write obj", K(result)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected temp expr", K(expr_info)); + } + if (OB_SUCC(ret) && value.is_null() && !expr_info.null_safe_) { + is_valid = false; + } + if (OB_SUCC(ret) && expr_info.rowid_idx_ > 0) { + if (value.is_urowid()) { + uint64_t pk_cnt; + ObArray pk_vals; + const ObURowIDData &urowid_data = value.get_urowid(); + bool is_physical_rowid = expr_info.rowid_idx_ == PHYSICAL_ROWID_IDX; + if (OB_UNLIKELY((urowid_data.is_physical_rowid() && !is_physical_rowid) || + (!urowid_data.is_physical_rowid() && is_physical_rowid))) { + ret = OB_INVALID_ROWID; + LOG_WARN("get inconsistent rowid", K(urowid_data), K(expr_info.rowid_idx_)); + } else if (urowid_data.is_physical_rowid()) { + // will convert in table scan. + } else if (OB_FAIL(urowid_data.get_pk_vals(pk_vals))) { + LOG_WARN("failed to get pk values", K(ret)); + } else if (OB_UNLIKELY((pk_cnt = urowid_data.get_real_pk_count(pk_vals)) < expr_info.rowid_idx_)) { + ret = OB_INVALID_ROWID; + LOG_WARN("get inconsistent rowid", K(pk_cnt), K(expr_info.rowid_idx_)); + } else { + value = pk_vals.at(expr_info.rowid_idx_ - 1); + } + } + } + } + return ret; +} + +int ObRangeGenerator::cast_value_type(ObTmpRange &range) +{ + int ret = OB_SUCCESS; + int64_t start_cmp = 0; + int64_t end_cmp = 0; + for (int64_t i = range.min_offset_; OB_SUCC(ret) && i < range.column_cnt_; ++i) { + const ObRangeColumnMeta *meta = pre_range_graph_->get_column_meta(i); + if (OB_ISNULL(meta)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (OB_FAIL(try_cast_value(*meta, range.start_[i], start_cmp, CO_GE))) { + LOG_WARN("failed to cast value", K(meta), K(range.start_[i])); + } else { + range.start_[i].set_collation_type(meta->column_type_.get_collation_type()); + if (start_cmp < 0) { + // after cast, precise becomes bigger + // * if is last value. `(` -> `[` + // e.g. (1, 2, 2.9; max, max, max) -> [1, 2, 3; max, max, max) + // * if is not last value. `[x, val, x` -> `(x, val, min` + // e.g. [1, 1.9, 3; max, max, max) -> (1, 2, min; max, max, max) + if (i == range.column_cnt_ - 1) { + range.include_start_ = true; + } else { + for (i = i + 1; i < range.column_cnt_; ++i) { + range.start_[i].set_min_value(); + } + range.include_start_ = false; + } + } else if (start_cmp > 0) { + // after cast, the result becomes smaller + // * if is last value. `[` -> `(` + // e.g. [1, 2, 3.1; max, max, max) -> (1, 2, 3; max, max, max) + // * if is not last value. `[x, val, x` -> `(x, val, max` + // e.g. [1, 2.1, 3; max, max, max) -> (1, 2, max; max, max, max) + if (i == range.column_cnt_ - 1) { + range.include_start_ = false; + } else { + for (i = i + 1; i < range.column_cnt_; ++i) { + range.start_[i].set_max_value(); + } + range.include_start_ = false; + } + } + } + } + for (int64_t i = range.min_offset_; OB_SUCC(ret) && i < range.column_cnt_; ++i) { + const ObRangeColumnMeta *meta = pre_range_graph_->get_column_meta(i); + if (OB_ISNULL(meta)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (OB_FAIL(try_cast_value(*meta, range.end_[i], end_cmp, CO_LE))) { + LOG_WARN("failed to cast value", K(meta), K(range.end_[i])); + } else { + range.end_[i].set_collation_type(meta->column_type_.get_collation_type()); + if (end_cmp < 0) { + // after cast, the result becomes bigger + // * if is last value. `]` -> `)` + // e.g. (min, min, min; 1, 2, 2.9] -> (min, min, min; 1, 2, 3) + // * if is not last value. `x, val, x]` -> `x, val, min)` + // e.g. (min, min, min; 1, 1.9, 3] -> (min, min, min; 1, 2, min) + if (i == range.column_cnt_ - 1) { + range.include_end_ = false; + } else { + for (i = i + 1; i < range.column_cnt_; ++i) { + range.end_[i].set_min_value(); + } + range.include_end_ = false; + } + } else if (end_cmp > 0) { + // after cast, the result becomes smaller + // * if is last value. `)` -> `]` + // e.g. (min, min, min; 1, 2, 3.1) -> (min, min, min; 1, 2, 3] + // * if is not last value. `x, val, x]` -> `x, val, max)` + // e.g. (min, min, min; 1, 2.1, 3] -> (min, min, min; 1, 2, max) + if (i == range.column_cnt_ - 1) { + range.include_end_ = true; + } else { + for (i = i + 1; i < range.column_cnt_; ++i) { + range.end_[i].set_max_value(); + } + range.include_end_ = false; + } + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(range.formalize())) { + LOG_WARN("failed to formalize tmp range"); + } + } + return ret; +} + +int ObRangeGenerator::try_cast_value(const ObRangeColumnMeta &meta, + ObObj &value, + int64_t &cmp, + common::ObCmpOp cmp_op) +{ + int ret = OB_SUCCESS; + if (!value.is_min_value() && !value.is_max_value() && !value.is_unknown() && + (!ObSQLUtils::is_same_type_for_compare(value.get_meta(), meta.column_type_.get_obj_meta()) || + value.is_decimal_int())) { + const ObObj *dest_val = NULL; + ObCollationType collation_type = meta.column_type_.get_collation_type(); + ObCastCtx cast_ctx(&allocator_, &dtc_params_, cur_datetime_, CM_WARN_ON_FAIL, collation_type); + ObExpectType expect_type; + expect_type.set_type(meta.column_type_.get_type()); + expect_type.set_collation_type(collation_type); + ObAccuracy res_acc; + ObObj tmp_dest_obj; + if (lib::is_mysql_mode() && + value.get_meta().get_type_class() == ObDoubleTC && + meta.column_type_.get_obj_meta().get_type_class() == ObDoubleTC && + meta.column_type_.get_accuracy().get_scale() != SCALE_UNKNOWN_YET) { + /* + The code here is primarily designed to fix the issue with double(-1,-1) -> double(20, 10), for example, + in the following SQL, the c2 column is an unsigned double(20,10), and the generated range + is (1.175494351e-38,MIN; 1.175494351e-38,MAX). However, at the storage layer, + this range is transformed to (0.,MIN; 0., MAX), which could result in the erroneous scanning of 0. + + select * from t1 where c2 = 1.175494351e-38; + */ + if (OB_FAIL(cast_double_to_fixed_double(meta, value, tmp_dest_obj))) { + LOG_WARN("failed to cast double to fixed double", K(ret)); + } else { + dest_val = &tmp_dest_obj; + } + } else { + if (meta.column_type_.is_decimal_int()) { + res_acc = meta.column_type_.get_accuracy(); + ObScale in_scale = value.get_scale(); + int32_t in_bytes = value.get_int_bytes(); + ObScale out_scale = res_acc.get_scale(); + int32_t out_bytes = wide::ObDecimalIntConstValue::get_int_bytes_by_precision(res_acc.get_precision()); + if (ObDatumCast::need_scale_decimalint(in_scale, in_bytes, out_scale, out_bytes)) { + // simply get range, using eq const mode + cast_ctx.cast_mode_ |= ObRelationalExprOperator::get_const_cast_mode(cmp_op, true); + } + cast_ctx.res_accuracy_ = &res_acc; + } + if (OB_FAIL(ObObjCaster::to_type(expect_type, cast_ctx, value, tmp_dest_obj, dest_val))) { + LOG_WARN("failed to cast object to expect_type", K(ret), K(value), K(expect_type)); + } + } + + // to check if EXPR CAST losses number precise + ObObjType cmp_type = ObMaxType; + if (OB_SUCC(ret)) { + if (OB_ISNULL(dest_val)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null value"); + } else if (ob_is_double_tc(expect_type.get_type())) { + const_cast(dest_val)->set_scale(meta.column_type_.get_accuracy().get_scale()); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type, + value.get_type(), + dest_val->get_type()))) { + LOG_WARN("failed to get relational cmp type", + K(cmp_type), K(value.get_type()), K(dest_val->get_type())); + } else if (OB_FAIL(ObRelationalExprOperator::compare_nullsafe(cmp, value, *dest_val, + cast_ctx, cmp_type, + collation_type))) { + LOG_WARN("failed to compare obj null safe", K(value), KPC(dest_val)); + } else { + value = *dest_val; + } + } + } + return ret; +} + +int ObRangeGenerator::generate_contain_exec_param_range() +{ + int ret = OB_SUCCESS; + ObNewRange *range = nullptr; + int64_t column_cnt = pre_range_graph_->get_column_count(); + if (OB_FAIL(create_new_range(range, column_cnt))) { + LOG_WARN("failed to create new range"); + } else { + ObObj *starts = range->start_key_.get_obj_ptr(); + ObObj *ends = range->end_key_.get_obj_ptr(); + for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt; ++i) { + starts[i].set_min_value(); + ends[i].set_max_value(); + } + range->is_physical_rowid_range_ = false; + range->border_flag_.unset_inclusive_start(); + range->border_flag_.unset_inclusive_end(); + all_single_value_ranges_ = false; + if (OB_FAIL(ranges_.push_back(range))) { + LOG_WARN("failed to push back range"); + } + } + return ret; +} + +// sort range according to start key +struct RangeCmp +{ + inline bool operator()(const ObNewRange *left, const ObNewRange *right) + { + bool bret = false; + if (left != nullptr && right != nullptr) { + bret = (left->compare_with_startkey2(*right) < 0); + } + return bret; + } +}; + +int ObRangeGenerator::merge_and_remove_ranges() +{ + int ret = OB_SUCCESS; + if (always_true_range_ != nullptr) { + ranges_.reset(); + if (OB_FAIL(ranges_.push_back(always_true_range_))) { + LOG_WARN("failed to push back always true range"); + } + } else if (0 == ranges_.count()) { + if (OB_ISNULL(always_false_range_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null always false range"); + } else if (OB_FAIL(ranges_.push_back(always_false_range_))) { + LOG_WARN("failed to push back always false range"); + } else { + all_single_value_ranges_ = false; + } + } else if (1 == ranges_.count()) { + // do nothing + } else if (pre_range_graph_->is_equal_range()) { + hash::ObHashSet range_set; + ObSEArray out_ranges; + if (OB_FAIL(range_set.create(pre_range_graph_->get_range_size() == 0 ? + RANGE_BUCKET_SIZE : pre_range_graph_->get_range_size()))) { + LOG_WARN("create range set bucket failed", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < ranges_.count(); ++i) { + ObQueryRange::ObRangeWrapper range_wrapper; + range_wrapper.range_ = ranges_.at(i); + if (OB_HASH_EXIST == (ret = range_set.set_refactored(range_wrapper, 0))) { + ret = OB_SUCCESS; + } else if (OB_UNLIKELY(OB_SUCCESS != ret)) { + LOG_WARN("failed to set range", K(ret)); + } else if (OB_FAIL(out_ranges.push_back(ranges_.at(i)))) { + LOG_WARN("failed to push back range"); + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(ranges_.assign(out_ranges))) { + LOG_WARN("failed to assign ranges"); + } else if (OB_FAIL(range_set.destroy())) { + LOG_WARN("failed to destroy hash set"); + } + } + } else { + lib::ob_sort(&ranges_.at(0), &ranges_.at(0) + ranges_.count(), RangeCmp()); + ObSEArray out_ranges; + ObNewRange *l_range = ranges_.at(0); + if (OB_ISNULL(l_range)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range"); + } + for (int64_t i = 1; OB_SUCC(ret) && i < ranges_.count(); ++i) { + ObNewRange *r_range = ranges_.at(i); + if (OB_ISNULL(r_range)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range"); + } else { + int cmp = l_range->compare_endkey_with_startkey(*r_range); + if (cmp < 0) { + if (OB_FAIL(out_ranges.push_back(l_range))) { + LOG_WARN("failed to push back range"); + } else { + l_range = r_range; + } + } else if (cmp == 0) { + l_range->end_key_.assign(r_range->end_key_.get_obj_ptr(), r_range->end_key_.get_obj_cnt()); + if (r_range->border_flag_.inclusive_end()) { + l_range->border_flag_.set_inclusive_end(); + } else { + l_range->border_flag_.unset_inclusive_end(); + } + } else { + int cmp2 = l_range->compare_with_endkey2(*r_range); + if (cmp2 < 0) { + l_range->end_key_.assign(r_range->end_key_.get_obj_ptr(), r_range->end_key_.get_obj_cnt()); + if (r_range->border_flag_.inclusive_end()) { + l_range->border_flag_.set_inclusive_end(); + } else { + l_range->border_flag_.unset_inclusive_end(); + } + } else if (cmp2 == 0) { + // do nothing + } else { + // do nothing + } + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(out_ranges.push_back(l_range))) { + LOG_WARN("failed to push back range"); + } else if (OB_FAIL(ranges_.assign(out_ranges))) { + LOG_WARN("failed to assign ranges"); + } + } + } + return ret; +} + +int ObRangeGenerator::generate_ss_ranges() +{ + int ret = OB_SUCCESS; + ObPhysicalPlanCtx *phy_ctx = exec_ctx_.get_physical_plan_ctx(); + if (OB_ISNULL(pre_range_graph_) || OB_ISNULL(phy_ctx) || + OB_ISNULL(pre_range_graph_->get_range_head())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range graph", KPC(pre_range_graph_), K(phy_ctx)); + } else if (OB_UNLIKELY(pre_range_graph_->get_skip_scan_offset() < 0 || + pre_range_graph_->get_skip_scan_offset() >= pre_range_graph_->get_column_cnt())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected skip scan range", K(pre_range_graph_->get_skip_scan_offset()), + K(pre_range_graph_->get_column_cnt())); + } else { + const ObRangeNode *ss_head = nullptr; + const ObRangeNode *cur_node = pre_range_graph_->get_range_head(); + while (cur_node != nullptr && cur_node->min_offset_ < pre_range_graph_->get_skip_scan_offset()) { + cur_node = cur_node->and_next_; + } + if (cur_node != nullptr && cur_node->min_offset_ == pre_range_graph_->get_skip_scan_offset()) { + ss_head = cur_node; + if (pre_range_graph_->has_exec_param() && !phy_ctx->is_exec_param_readable()) { + // pre range graph has exec param and not exec stage, generate (min; max) + if (OB_FAIL(generate_contain_exec_param_range())) { + LOG_WARN("faield to generate contain exec param range"); + } + } else { + is_generate_ss_range_ = true; + if (OB_FAIL(generate_standard_ranges(ss_head))) { + LOG_WARN("failed to genenrate precise get range"); + } + } + } + } + return ret; +} + +int ObRangeGenerator::create_new_range(ObNewRange *&range, int64_t column_cnt) +{ + int ret = OB_SUCCESS; + range = nullptr; + ObObj *starts = nullptr; + ObObj *ends = nullptr; + size_t rowkey_size = sizeof(ObObj) * column_cnt * 2; + size_t range_size = sizeof(ObNewRange) + rowkey_size; + void *range_buffer = nullptr; + if (OB_ISNULL(range_buffer = allocator_.alloc(range_size))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("alloc memory for range failed", K(range_size)); + } else { + range = new(range_buffer) ObNewRange(); + starts = reinterpret_cast(static_cast(range_buffer) + sizeof(ObNewRange)); + ends = starts + column_cnt; + range->table_id_ = pre_range_graph_->get_table_id(); + range->start_key_.assign(starts, column_cnt); + range->end_key_.assign(ends, column_cnt); + } + return ret; +} + +struct InParamObjCmp +{ + inline bool operator()(const ObObj *left, const ObObj *right) + { + bool bret = false; + if (left != nullptr && right != nullptr) { + bret = (left->compare(*right) < 0); + } + return bret; + } +}; + +int ObRangeGenerator::generate_tmp_not_in_param(const ObRangeNode &node, + ObTmpInParam *&tmp_in_param) +{ + int ret = OB_SUCCESS; + InParam *in_param = nullptr; + ObObj* objs_ptr = nullptr; + const ObRangeColumnMeta *meta = nullptr; + if (OB_UNLIKELY(!node.is_not_in_node_ || + node.node_id_ < 0 || + node.node_id_ >= all_tmp_node_caches_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected not in node", K(node.node_id_), K(all_tmp_node_caches_.count())); + } else if (OB_NOT_NULL(tmp_in_param = static_cast(all_tmp_node_caches_.at(node.node_id_)))) { + // do nothing + } else if (OB_UNLIKELY(node.min_offset_ < 0 || + node.min_offset_ >= pre_range_graph_->get_column_cnt() || + node.start_keys_[node.min_offset_] >= 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range", K(node)); + } else if (OB_ISNULL(meta = pre_range_graph_->get_column_meta(node.min_offset_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexecpted null", K(meta)); + } else if (OB_ISNULL(in_param = range_map_.in_params_.at(-node.start_keys_[node.min_offset_] - 1))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected in param", K(node.node_id_)); + } else if (OB_ISNULL(tmp_in_param = (ObTmpInParam*)allocator_.alloc(sizeof(ObTmpInParam)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memeory failed", K(tmp_in_param)); + } else if (OB_ISNULL(objs_ptr = (ObObj*)allocator_.alloc(sizeof(ObObj) * in_param->count()))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memeory failed", K(objs_ptr)); + } else if (OB_FALSE_IT(tmp_in_param = new(tmp_in_param) ObTmpInParam(allocator_))) { + } else if (OB_FAIL(tmp_in_param->in_param_.init(in_param->count()))) { + LOG_WARN("failed to init fixed array size", K(ret)); + } else { + objs_ptr = new(objs_ptr) ObObj[in_param->count()]; + bool always_false = false; + for (int64_t i = 0; OB_SUCC(ret) && !always_false && i < in_param->count(); ++i) { + bool is_valid = false; + bool need_add = true; + int64_t cmp = 0; + if (OB_FAIL(get_result_value(in_param->at(i), objs_ptr[i], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result vlaue", K(i)); + } else if (!is_valid) { + always_false = true; + need_add = false; + } else if (OB_LIKELY(ObSQLUtils::is_same_type_for_compare(objs_ptr[i].get_meta(), + meta->column_type_.get_obj_meta()) && + !objs_ptr[i].is_decimal_int())) { + objs_ptr[i].set_collation_type(meta->column_type_.get_collation_type()); + } else if (!node.is_phy_rowid_ && OB_FAIL(try_cast_value(*meta, objs_ptr[i], cmp, CO_EQ))) { + LOG_WARN("failed to cast value", K(meta), K(objs_ptr[i])); + } else if (cmp != 0) { + need_add = false; + } else { + objs_ptr[i].set_collation_type(meta->column_type_.get_collation_type()); + } + if (OB_SUCC(ret) && need_add) { + if(OB_FAIL(tmp_in_param->in_param_.push_back(&objs_ptr[i]))) { + LOG_WARN("failed to push back in param", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (OB_FALSE_IT(all_tmp_node_caches_.at(node.node_id_) = tmp_in_param)) { + } else if (always_false) { + tmp_in_param->always_false_ = always_false; + } else { + lib::ob_sort(&tmp_in_param->in_param_.at(0), + &tmp_in_param->in_param_.at(0) + tmp_in_param->in_param_.count(), + InParamObjCmp()); + } + } + return ret; +} + +int ObRangeGenerator::final_not_in_range_node(const ObRangeNode &node, + const int64_t not_in_idx, + ObTmpInParam *tmp_in_param, + ObTmpRange *&range) +{ + int ret = OB_SUCCESS; + const ObRangeColumnMeta *meta = nullptr; + range = all_tmp_ranges_.at(node.node_id_); + if (range == nullptr) { + if (OB_FAIL(generate_tmp_range(range, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } + } + if (OB_SUCC(ret)) { + int64_t start_padding = OB_RANGE_MIN_VALUE; + int64_t end_padding = OB_RANGE_MAX_VALUE; + range->always_false_ = false; + if (OB_ISNULL(range)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_ISNULL(tmp_in_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(tmp_in_param)); + } else { + for (int64_t i = 0; i < node.min_offset_; ++i) { + range->start_[i].set_nop_value(); + range->end_[i].set_nop_value(); + } + range->min_offset_ = node.min_offset_; + range->max_offset_ = node.max_offset_; + range->include_start_ = false; + range->include_end_ = false; + range->is_phy_rowid_ = node.is_phy_rowid_; + } + + if (OB_FAIL(ret)) { + } else if (tmp_in_param->in_param_.empty()) { + if (lib::is_mysql_mode()) { + range->start_[range->min_offset_].set_null(); + start_padding = OB_RANGE_MAX_VALUE; + } else { + range->start_[range->min_offset_].set_min_value(); + start_padding = OB_RANGE_MIN_VALUE; + } + if (lib::is_oracle_mode()) { + range->end_[range->min_offset_].set_null(); + end_padding = OB_RANGE_MIN_VALUE; + } else { + range->end_[range->min_offset_].set_max_value(); + end_padding = OB_RANGE_MAX_VALUE; + } + } else if (0 == not_in_idx) { + if (lib::is_mysql_mode()) { + range->start_[range->min_offset_].set_null(); + start_padding = OB_RANGE_MAX_VALUE; + } else { + range->start_[range->min_offset_].set_min_value(); + start_padding = OB_RANGE_MIN_VALUE; + } + if (OB_FAIL(ob_write_obj(allocator_, *tmp_in_param->in_param_.at(not_in_idx), + range->end_[range->min_offset_]))) { + LOG_WARN("failed to write obj", K(ret)); + } else { + end_padding = OB_RANGE_MIN_VALUE; + } + } else if (tmp_in_param->in_param_.count() <= not_in_idx) { + if (OB_FAIL(ob_write_obj(allocator_, *tmp_in_param->in_param_.at(not_in_idx - 1), + range->start_[range->min_offset_]))) { + LOG_WARN("failed to write obj", K(ret)); + } else { + if (lib::is_oracle_mode()) { + range->end_[range->min_offset_].set_null(); + end_padding = OB_RANGE_MIN_VALUE; + } else { + range->end_[range->min_offset_].set_max_value(); + end_padding = OB_RANGE_MAX_VALUE; + } + start_padding = OB_RANGE_MAX_VALUE; + } + } else { + if (OB_FAIL(ob_write_obj(allocator_, *tmp_in_param->in_param_.at(not_in_idx - 1), + range->start_[range->min_offset_]))) { + LOG_WARN("failed to write obj", K(ret)); + } else if (OB_FAIL(ob_write_obj(allocator_, *tmp_in_param->in_param_.at(not_in_idx), + range->end_[range->min_offset_]))) { + LOG_WARN("failed to write obj", K(ret)); + } else { + start_padding = OB_RANGE_MAX_VALUE; + end_padding = OB_RANGE_MIN_VALUE; + } + } + if (OB_SUCC(ret)) { + for (int64_t i = range->min_offset_ + 1; i < pre_range_graph_->get_column_cnt(); ++i) { + if (start_padding == OB_RANGE_MIN_VALUE) { + range->start_[i].set_min_value(); + } else if (start_padding == OB_RANGE_MAX_VALUE) { + range->start_[i].set_max_value(); + } + if (end_padding == OB_RANGE_MIN_VALUE) { + range->end_[i].set_min_value(); + } else if (start_padding == OB_RANGE_MAX_VALUE) { + range->end_[i].set_max_value(); + } + } + if (!node.is_phy_rowid_ && OB_FAIL(cast_value_type(*range))) { + LOG_WARN("cast value type failed", K(ret)); + } else { + all_tmp_ranges_.at(node.node_id_) = range; + } + } + } + return ret; +} + +int ObRangeGenerator::generate_tmp_geo_param(const ObRangeNode &node, + ObTmpGeoParam *&tmp_geo_param) +{ + int ret = OB_SUCCESS; + uint32_t input_srid; + ObObj objs_ptr[2]; + ObString wkb_str; + double distance = NAN; + bool is_valid = false; + ObArenaAllocator tmp_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObDomainOpType op_type = GET_RANGE_NODE_DOMAIN_TYPE(&node); + if (OB_UNLIKELY(!node.is_domain_node_ || + node.node_id_ < 0 || + node.node_id_ >= all_tmp_node_caches_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected not in node", K(node.node_id_), K(all_tmp_node_caches_.count())); + } else if (OB_NOT_NULL(tmp_geo_param = static_cast(all_tmp_node_caches_.at(node.node_id_)))) { + // do nothing + } else if (OB_UNLIKELY(node.min_offset_ < 0 || + node.min_offset_ >= pre_range_graph_->get_column_cnt())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range", K(node)); + } else if (OB_ISNULL(tmp_geo_param = (ObTmpGeoParam*)allocator_.alloc(sizeof(ObTmpGeoParam)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memeory failed", K(tmp_geo_param)); + } else if (OB_FALSE_IT(tmp_geo_param = new(tmp_geo_param) ObTmpGeoParam(allocator_))) { + } else if (OB_FAIL(get_result_value(node.start_keys_[node.min_offset_], objs_ptr[0], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result value", K(node.start_keys_[node.min_offset_])); + } else if (!is_valid) { + tmp_geo_param->always_true_ = true; + } else if ((op_type == ObDomainOpType::T_GEO_DWITHIN || + op_type == ObDomainOpType::T_GEO_RELATE) && + OB_FAIL(get_result_value(node.end_keys_[node.min_offset_], objs_ptr[1], is_valid, exec_ctx_))) { + LOG_WARN("failed to get result value", K(ret)); + } else if (!is_valid) { + tmp_geo_param->always_true_ = true; + } else if (op_type == ObDomainOpType::T_GEO_RELATE && + OB_FAIL(get_spatial_relationship_by_mask(objs_ptr[1], op_type))) { + LOG_WARN("failed to get spatial relationship by mask", K(ret)); + } else if (!is_geo_type(op_type)) { + tmp_geo_param->always_true_ = true; + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(&tmp_allocator, objs_ptr[0], wkb_str))) { + LOG_WARN("fail to get real string data", K(ret), K(objs_ptr[0])); + } else if (OB_FAIL(ObGeoTypeUtil::get_srid_from_wkb(wkb_str, input_srid))) { + LOG_WARN("failed to get srid", K(ret), K(wkb_str)); + } else if (OB_FAIL(ObSqlGeoUtils::check_srid(node.domain_extra_.srid_, input_srid))) { + ret = OB_ERR_WRONG_SRID_FOR_COLUMN; + LOG_USER_ERROR(OB_ERR_WRONG_SRID_FOR_COLUMN, static_cast(input_srid), + static_cast(node.domain_extra_.srid_)); + } else{ + if (op_type == ObDomainOpType::T_GEO_DWITHIN) { + distance = objs_ptr[1].get_double(); + } + switch (op_type) { + case ObDomainOpType::T_GEO_INTERSECTS: + case ObDomainOpType::T_GEO_COVERS: + case ObDomainOpType::T_GEO_DWITHIN: + if (OB_FAIL(get_intersects_tmp_geo_param(input_srid, wkb_str, op_type, distance, tmp_geo_param))) { + LOG_WARN("failed to get keypart from intersects_keypart", K(ret), K(op_type)); + } + break; + case ObDomainOpType::T_GEO_COVEREDBY: + if (OB_FAIL(get_coveredby_tmp_geo_param(input_srid, wkb_str, op_type, tmp_geo_param))) { + LOG_WARN("failed to get keypart from intersects_keypart", K(ret), K(op_type)); + } + break; + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Not support op_type", K(ret), K(op_type)); + break; + } + if (OB_SUCC(ret)) { + all_tmp_node_caches_.at(node.node_id_) = tmp_geo_param; + } + } + return ret; +} + +int ObRangeGenerator::get_intersects_tmp_geo_param(uint32_t input_srid, + const common::ObString &wkb_str, + const common::ObDomainOpType op_type, + const double &distance, + ObTmpGeoParam *geo_param) +{ + int ret = OB_SUCCESS; + common::ObArenaAllocator tmp_alloc(lib::ObLabel("GisIndex"), OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObS2Cellids cells; + ObS2Cellids cells_with_ancestors; + ObSpatialMBR mbr_filter(op_type); + ObGeoType geo_type = ObGeoType::GEOMETRY; + const ObSrsItem *srs_item = NULL; + omt::ObSrsCacheGuard srs_guard; + const ObSrsBoundsItem *srs_bound = NULL; + ObS2Adapter *s2object = NULL; + ObString buffer_geo; + + if ((input_srid != 0) && OB_FAIL(OTSRS_MGR->get_tenant_srs_guard(srs_guard))) { + LOG_WARN("get tenant srs guard failed", K(input_srid), K(ret)); + } else if ((input_srid != 0) && OB_FAIL(srs_guard.get_srs_item(input_srid, srs_item))) { + LOG_WARN("get tenant srs failed", K(input_srid), K(ret)); + } else if (((input_srid == 0) || !(srs_item->is_geographical_srs())) && + OB_FAIL(OTSRS_MGR->get_srs_bounds(input_srid, srs_item, srs_bound))) { + LOG_WARN("failed to get srs item", K(ret)); + } else if (op_type == ObDomainOpType::T_GEO_DWITHIN) { + if (std::isnan(distance)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid distance para", K(ret)); + } else if (input_srid != 0 && srs_item->is_geographical_srs()) { + double sphere_radius = (srs_item->semi_major_axis() * 2 + srs_item->semi_minor_axis()) / 3; + const double SPHERIOD_ERR_FRACTION = 0.005; + double radius = ((1.0 + SPHERIOD_ERR_FRACTION) * distance) / sphere_radius; + s2object = OB_NEWx(ObS2Adapter, (&tmp_alloc), (&tmp_alloc), true, radius); + if (OB_ISNULL(s2object)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc s2 object", K(ret)); + } + } else { + if (OB_FAIL(ObGeoTypeUtil::get_buffered_geo(&tmp_alloc, wkb_str, distance, srs_item, buffer_geo))) { + LOG_WARN("failed to get buffer geo", K(ret)); + if (ret == OB_INVALID_ARGUMENT) { + LOG_USER_ERROR(OB_INVALID_ARGUMENT, N_ST_BUFFER); + } else if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_BUFFER); + } + } + } + } + + if (s2object == NULL && OB_SUCC(ret)) { + s2object = OB_NEWx(ObS2Adapter, (&tmp_alloc), (&tmp_alloc), (input_srid != 0 ? srs_item->is_geographical_srs() : false), true); + if (OB_ISNULL(s2object)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc s2 object", K(ret)); + } + } + + if (OB_SUCC(ret)) { + lib::ObMallocHookAttrGuard malloc_guard(lib::ObMemAttr(MTL_ID(), "S2Adapter")); + // build s2 object from wkb + if (OB_FAIL(ObGeoTypeUtil::get_type_from_wkb((buffer_geo.empty() ? wkb_str : buffer_geo), geo_type))) { + LOG_WARN("fail to get geo type by wkb", K(ret)); + } else if (OB_FAIL(s2object->init((buffer_geo.empty() ? wkb_str : buffer_geo), srs_bound))) { + LOG_WARN("Init s2object failed", K(ret)); + } else if (OB_FAIL(s2object->get_cellids_and_unrepeated_ancestors(cells, cells_with_ancestors))) { + LOG_WARN("Get cellids from s2object failed", K(ret)); + } else if (OB_FAIL(s2object->get_mbr(mbr_filter))) { + LOG_WARN("Get mbr from s2object failed", K(ret)); + } else if (OB_FAIL(mbr_filters_.push_back(mbr_filter))) { + LOG_WARN("Push back to mbr_filters array failed", K(ret)); + } else if (mbr_filter.is_empty()) { + if (cells.size() == 0) { + LOG_INFO("it's might be empty geometry collection", K(wkb_str)); + geo_param->always_true_ = true; + } else { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid geometry", K(ret), K(wkb_str)); + } + } else { + int64_t range_count = cells_with_ancestors.size(); + range_count += cells.size(); + if (OB_FAIL(geo_param->start_keys_.init(range_count))) { + LOG_WARN("failed to init start keys", K(ret)); + } else if (OB_FAIL(geo_param->end_keys_.init(range_count))) { + LOG_WARN("failed to init end keys", K(ret)); + } + // build keypart from cells_with_ancestors + for (uint64_t i = 0; OB_SUCC(ret) && i < cells_with_ancestors.size(); i++) { + if (OB_FAIL(geo_param->start_keys_.push_back(cells_with_ancestors[i]))) { + LOG_WARN("failed to push back into array", K(ret)); + } else if (OB_FAIL(geo_param->end_keys_.push_back(cells_with_ancestors[i]))) { + LOG_WARN("failed to push back into array", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (((geo_type != ObGeoType::POINT && geo_type != ObGeoType::POINTZ) || !std::isnan(distance))) { + // build keypart to index child_of_cellid + for (uint64_t i = 0; OB_SUCC(ret) && i < cells.size(); i++) { + uint64_t cellid = cells.at(i); + uint64_t start_id = 0; + uint64_t end_id = 0; + ObS2Adapter::get_child_of_cellid(cellid, start_id, end_id); + if (OB_FAIL(geo_param->start_keys_.push_back(start_id))) { + LOG_WARN("failed to push back into array", K(ret)); + } else if (OB_FAIL(geo_param->end_keys_.push_back(end_id))) { + LOG_WARN("failed to push back into array", K(ret)); + } + } + } else { + for (uint64_t i = 0; OB_SUCC(ret) && i < cells.size(); i++) { + if (OB_FAIL(geo_param->start_keys_.push_back(cells[i]))) { + LOG_WARN("failed to push back into array", K(ret)); + } else if (OB_FAIL(geo_param->end_keys_.push_back(cells[i]))) { + LOG_WARN("failed to push back into array", K(ret)); + } + } + } + } + } + + if (OB_NOT_NULL(s2object)) { + s2object->~ObS2Adapter(); + } + + return ret; +} + +int ObRangeGenerator::get_coveredby_tmp_geo_param(uint32_t input_srid, + const common::ObString &wkb_str, + const common::ObDomainOpType op_type, + ObTmpGeoParam *geo_param) +{ + int ret = OB_SUCCESS; + common::ObArenaAllocator tmp_alloc(lib::ObLabel("GisIndex"), OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObS2Cellids cells; + ObSpatialMBR mbr_filter(op_type); + const ObSrsItem *srs_item = NULL; + omt::ObSrsCacheGuard srs_guard; + const ObSrsBoundsItem *srs_bound = NULL; + ObS2Adapter *s2object = NULL; + ObString buffer_geo; + + if ((input_srid != 0) && OB_FAIL(OTSRS_MGR->get_tenant_srs_guard(srs_guard))) { + LOG_WARN("get tenant srs guard failed", K(input_srid), K(ret)); + } else if ((input_srid != 0) && OB_FAIL(srs_guard.get_srs_item(input_srid, srs_item))) { + LOG_WARN("get tenant srs failed", K(input_srid), K(ret)); + } else if (((input_srid == 0) || !(srs_item->is_geographical_srs())) && + OB_FAIL(OTSRS_MGR->get_srs_bounds(input_srid, srs_item, srs_bound))) { + LOG_WARN("failed to get srs item", K(ret)); + } + if (s2object == NULL && OB_SUCC(ret)) { + s2object = OB_NEWx(ObS2Adapter, (&tmp_alloc), (&tmp_alloc), (input_srid != 0 ? srs_item->is_geographical_srs() : false)); + if (OB_ISNULL(s2object)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc s2 object", K(ret)); + } + } + + if (OB_SUCC(ret)) { + lib::ObMallocHookAttrGuard malloc_guard(lib::ObMemAttr(MTL_ID(), "S2Adapter")); + // build s2 object from wkb + if (OB_FAIL(s2object->init((buffer_geo.empty() ? wkb_str : buffer_geo), srs_bound))) { + LOG_WARN("Init s2object failed", K(ret)); + } else if (OB_FAIL(s2object->get_inner_cover_cellids(cells))) { + LOG_WARN("Get cellids from s2object failed", K(ret)); + } else if (OB_FAIL(s2object->get_mbr(mbr_filter))) { + LOG_WARN("Get mbr from s2object failed", K(ret)); + } else if (OB_FAIL(mbr_filters_.push_back(mbr_filter))) { + LOG_WARN("Push back to mbr_filters array failed", K(ret)); + } else if (mbr_filter.is_empty()) { + if (cells.size() == 0) { + LOG_INFO("it's might be empty geometry collection", K(wkb_str)); + geo_param->always_true_ = true; + } else { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid geometry", K(ret), K(wkb_str)); + } + } else { + hash::ObHashSet cellid_set; + if (OB_FAIL(cellid_set.create(128, "CoveredByKeyPart", "HashNode", MTL_ID()))) { + LOG_WARN("failed to create cellid set", K(ret)); + } else if (!cellid_set.created()) { + ret = OB_NOT_INIT; + LOG_WARN("fail to init cellid set", K(ret)); + } + for (uint64_t i = 0; OB_SUCC(ret) && i < cells.size(); i++) { + int hash_ret = cellid_set.exist_refactored(cells[i]); + ObS2Cellids ancestors; + if (OB_HASH_NOT_EXIST == hash_ret) { + if (OB_FAIL(cellid_set.set_refactored(cells[i]))) { + LOG_WARN("failed to add cellid into set", K(ret)); + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(s2object->get_ancestors(cells[i], ancestors))) { + LOG_WARN("Get ancestors of cell failed", K(ret)); + } + // if cur cellid is exists in set, then it's ancestors also exist in set + int hash_ret = OB_HASH_NOT_EXIST; + for (uint64_t i = 0; OB_SUCC(ret) && i < ancestors.size(); i++) { + hash_ret = cellid_set.exist_refactored(ancestors[i]); + if (hash_ret == OB_HASH_NOT_EXIST) { + if (OB_FAIL(cellid_set.set_refactored(ancestors[i]))) { + LOG_WARN("failed to add cellid into set", K(ret)); + } + } else if (OB_HASH_EXIST != hash_ret) { + ret = hash_ret; + LOG_WARN("fail to check if key exist", K(ret), K(ancestors[i]), K(i)); + } + } + } else if (OB_HASH_EXIST != hash_ret) { + ret = hash_ret; + LOG_WARN("fail to check if key exist", K(ret), K(cells[i]), K(i)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(geo_param->start_keys_.init(cellid_set.size()))) { + LOG_WARN("failed to init start keys", K(ret)); + } else if (OB_FAIL(geo_param->end_keys_.init(cellid_set.size()))) { + LOG_WARN("failed to init end keys", K(ret)); + } else { + for (hash::ObHashSet::const_iterator itr = cellid_set.begin(); OB_SUCC(ret) && itr != cellid_set.end(); + ++itr) { + if (OB_FAIL(geo_param->start_keys_.push_back(itr->first))) { + LOG_WARN("failed to push back array", K(ret)); + } else if (OB_FAIL(geo_param->end_keys_.push_back(itr->first))) { + LOG_WARN("failed to push back array", K(ret)); + } + } + } + } + // clear hashset + if (cellid_set.created()) { + int tmp_ret = cellid_set.destroy(); + if (OB_SUCC(ret) && OB_FAIL(tmp_ret)) { + LOG_WARN("failed to destory param set", K(ret)); + } + } + } + } + if (OB_NOT_NULL(s2object)) { + s2object->~ObS2Adapter(); + } + return ret; +} + +int ObRangeGenerator::final_geo_range_node(const ObRangeNode &node, + const uint64_t start, + const uint64_t end, + ObTmpRange *&range) +{ + int ret = OB_SUCCESS; + range = all_tmp_ranges_.at(node.node_id_); + if (range == nullptr) { + if (OB_FAIL(generate_tmp_range(range, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } + } + if (OB_SUCC(ret)) { + ObObj start_val; + ObObj end_val; + start_val.set_uint64(start); + end_val.set_uint64(end); + if (OB_FAIL(fill_domain_range_node(node, start_val, end_val, range))) { + LOG_WARN("failed to fill domain equal range node", K(ret)); + } + } + return ret; +} + +int ObRangeGenerator::check_need_merge_range_nodes(const ObRangeNode *node, + bool &need_merge) +{ + int ret = OB_SUCCESS; + need_merge = true; + if (OB_ISNULL(node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (node->is_domain_node_ && OB_ISNULL(node->or_next_)) { + need_merge = false; + } + return ret; +} +int ObRangeGenerator::generate_fast_nlj_range(const ObPreRangeGraph &pre_range_graph, + const ParamStore ¶m_store, + ObIAllocator &allocator, + void *range_buffer) +{ + int ret = OB_SUCCESS; + bool always_false = false; + const ObRangeNode *node = pre_range_graph.get_range_head(); + const ObRangeMap &range_map = pre_range_graph.get_range_map(); + ObNewRange *range = static_cast(range_buffer); + ObObj *starts = reinterpret_cast(static_cast(range_buffer) + sizeof(ObNewRange)); + ObObj *ends = starts + node->column_cnt_; + for (int i = 0; OB_SUCC(ret) && !always_false && i < node->column_cnt_; ++i) { + int64_t start_idx = node->start_keys_[i]; + int64_t end_idx = node->end_keys_[i]; + if (start_idx == OB_RANGE_MIN_VALUE && + end_idx == OB_RANGE_MAX_VALUE) { + starts[i].set_min_value(); + ends[i].set_max_value(); + } else if (start_idx == OB_RANGE_NULL_VALUE) { + starts[i].set_null(); + ends[i].set_null(); + } else { + const ObRangeMap::ExprFinalInfo& expr_info = range_map.expr_final_infos_.at(start_idx); + const ObObj* src_obj = nullptr; + if (expr_info.is_param_) { + src_obj = ¶m_store.at(expr_info.param_idx_); + } else if (expr_info.is_const_) { + src_obj = expr_info.const_val_; + } + if (src_obj->is_null() && !expr_info.null_safe_) { + always_false = true; + } else if (OB_FAIL(ob_write_obj(allocator, *src_obj, *(starts + i)))) { + LOG_WARN("failed to write obj", K(ret)); + } else { + *(ends + i) = *(starts + i); + } + } + } + if (OB_SUCC(ret)) { + range->is_physical_rowid_range_ = node->is_phy_rowid_; + if (OB_LIKELY(!always_false)) { + if (node->include_start_) { + range->border_flag_.set_inclusive_start(); + } else { + range->border_flag_.unset_inclusive_start(); + } + if (node->include_end_) { + range->border_flag_.set_inclusive_end(); + } else { + range->border_flag_.unset_inclusive_end(); + } + range->start_key_.assign(starts, node->column_cnt_); + range->end_key_.assign(ends, node->column_cnt_); + } else { + range->set_false_range(); + } + } + return ret; +} + +int ObRangeGenerator::check_can_final_fast_nlj_range(const ObPreRangeGraph &pre_range_graph, + const ParamStore ¶m_store, + bool &is_valid) +{ + int ret = OB_SUCCESS; + const ObRangeNode *node = pre_range_graph.get_range_head(); + const ObRangeMap &range_map = pre_range_graph.get_range_map(); + is_valid = true; + for (int i = 0; OB_SUCC(ret) && i < node->column_cnt_; ++i) { + int64_t start_idx = node->start_keys_[i]; + int64_t end_idx = node->end_keys_[i]; + const ObRangeColumnMeta *meta = pre_range_graph.get_column_meta(i); + int64_t cmp = 0; + const ObObj* src_obj = nullptr; + if (OB_ISNULL(meta)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null column meta"); + } else if (start_idx == OB_RANGE_MIN_VALUE && + end_idx == OB_RANGE_MAX_VALUE) { + // do nothing + } else if (OB_UNLIKELY(start_idx != end_idx || + !is_const_expr_or_null(start_idx) || + !is_const_expr_or_null(end_idx) || + start_idx < 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("start idx should equal to end idx", K(start_idx), K(end_idx)); + } else if (start_idx == OB_RANGE_NULL_VALUE) { + // do nothing + } else if (range_map.expr_final_infos_.at(start_idx).is_param_) { + src_obj = ¶m_store.at(range_map.expr_final_infos_.at(start_idx).param_idx_); + } else if (range_map.expr_final_infos_.at(start_idx).is_const_) { + src_obj = range_map.expr_final_infos_.at(start_idx).const_val_; + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node in fast nlj range", K(ret)); + } + + if (OB_FAIL(ret)) { + } else if (src_obj == nullptr) { + // do nothing + } else if (OB_LIKELY(ObSQLUtils::is_same_type_for_compare(src_obj->get_meta(), + meta->column_type_.get_obj_meta()) && + !src_obj->is_decimal_int())) { + // do nothing + } else { + is_valid = false; + } + } + return ret; +} + +int ObRangeGenerator::cast_double_to_fixed_double(const ObRangeColumnMeta &meta, + const ObObj& in_value, + ObObj &out_value) +{ + int ret = OB_SUCCESS; + double value = in_value.get_double(); + if (ObUDoubleType == meta.column_type_.get_type() && value < 0.) { + out_value.set_double(meta.column_type_.get_type(), 0.); + } else if (OB_FAIL(refine_real_range(meta.column_type_.get_accuracy(), value))) { + LOG_WARN("failed to real range check", K(ret)); + } else { + out_value.set_double(meta.column_type_.get_type(), value); + } + return ret; +} + +int ObRangeGenerator::refine_real_range(const ObAccuracy &accuracy, double &value) +{ + int ret = OB_SUCCESS; + const ObPrecision precision = accuracy.get_precision(); + const ObScale scale = accuracy.get_scale(); + if (OB_LIKELY(precision > 0) && + OB_LIKELY(scale >= 0) && + OB_LIKELY(precision >= scale)) { + double integer_part = static_cast(pow(10.0, static_cast(precision - scale))); + double decimal_part = static_cast(pow(10.0, static_cast(scale))); + double max_value = static_cast(integer_part - 1 / decimal_part); + double min_value = static_cast(-max_value); + if (value < min_value) { + value = min_value; + } else if (value > max_value) { + value = max_value; + } else { + value = static_cast(rint((value - + floor(static_cast(value)))* decimal_part) / + decimal_part + floor(static_cast(value))); + } + } + return ret; +} + +int ObRangeGenerator::get_spatial_relationship_by_mask(const ObObj& extra, ObDomainOpType& op_type) +{ + int ret = OB_SUCCESS; + if (!ob_is_string_type(extra.get_type())) { + op_type = ObDomainOpType::T_DOMAIN_OP_END; + } else { + ObString mask_str(extra.get_string()); + common::ObArenaAllocator temp_allocator(lib::ObLabel("GisIndex"), OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObString upper_str; + void* ptr = NULL; + char *cmp_str = NULL; + if (OB_FAIL(ob_simple_low_to_up(temp_allocator, mask_str, upper_str))) { + LOG_WARN("failed to get upper string", K(ret)); + } else if (NULL == (ptr = temp_allocator.alloc(upper_str.length() + 1))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret), K(upper_str.length())); + } else { + cmp_str = static_cast(ptr); + cmp_str[upper_str.length()] = '\0'; + MEMCPY(cmp_str, upper_str.ptr(), upper_str.length()); + if (nullptr != strstr(cmp_str, "ANYINTERACT")) { + op_type = ObDomainOpType::T_GEO_INTERSECTS; + } else { + // other spatial relationsh is not supported yet, no need to continue + op_type = ObDomainOpType::T_DOMAIN_OP_END; + } + } + } + return ret; +} + +bool ObRangeGenerator::is_geo_type(const ObDomainOpType& op_type) +{ + bool bret = false; + if (op_type == ObDomainOpType::T_GEO_COVERS || + op_type == ObDomainOpType::T_GEO_INTERSECTS || + op_type == ObDomainOpType::T_GEO_DWITHIN || + op_type == ObDomainOpType::T_GEO_COVEREDBY || + op_type == ObDomainOpType::T_GEO_RELATE) { + bret = true; + } + return bret; +} + +int ObRangeGenerator::final_json_member_of_range_node(const ObRangeNode *node, + ObTmpRange *&range, + bool need_cache) +{ + int ret = OB_SUCCESS; + ObObj obj; + const ObRangeColumnMeta *meta = NULL; + ObIJsonBase* j_base = nullptr; + ObObj cast_obj; + range = need_cache ? all_tmp_ranges_.at(node->node_id_) : nullptr; + bool is_valid = false; + int64_t cmp = 0; + if (range != nullptr) { + // already generated + } else if (OB_UNLIKELY(node->min_offset_ < 0 || + node->min_offset_ >= pre_range_graph_->get_column_cnt())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range", K(node)); + } else if (OB_ISNULL(meta = pre_range_graph_->get_column_meta(node->min_offset_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected column meta", K(ret)); + } else if (OB_FAIL(generate_tmp_range(range, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } else if (OB_FAIL(get_result_value(node->start_keys_[node->min_offset_], obj, is_valid, exec_ctx_))) { + LOG_WARN("failed to get result value", K(node->start_keys_[node->min_offset_])); + } else if (!is_valid) { + range->set_always_false(); + } else { + cast_obj = obj; + if (ob_is_json(obj.get_type()) || + ob_is_datetime_tc(meta->column_type_.get_type()) || + ob_is_date_tc(meta->column_type_.get_type()) || + ob_is_time_tc(meta->column_type_.get_type())) { + if (OB_FAIL(ObJsonExprHelper::refine_range_json_value_const(obj, + &exec_ctx_, + false, + &allocator_, + j_base))) { + LOG_WARN("failed cast to json scalar.", K(ret), K(cast_obj)); + } else if (OB_FAIL(ObJsonUtil::cast_json_scalar_to_sql_obj(&allocator_, + &exec_ctx_, + j_base, + meta->column_type_, + cast_obj))) { + LOG_WARN("failed cast to sql scalar.", K(ret), K(cast_obj)); + } + } + + if (OB_FAIL(ret)) { + ret = OB_SUCCESS; + range->set_always_true(); + } else if (OB_FAIL(try_cast_value(*meta, cast_obj, cmp, CO_EQ))) { + LOG_WARN("failed to cast value", K(ret)); + } else if (cmp != 0) { + range->set_always_true(); + } else if (OB_FAIL(fill_domain_range_node(*node, cast_obj, cast_obj, range))) { + LOG_WARN("failed to fill domain range node", K(ret)); + } + } + return ret; +} + +int ObRangeGenerator::fill_domain_range_node(const ObRangeNode &node, + const ObObj& start_val, + const ObObj& end_val, + ObTmpRange *range) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(range)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else { + range->always_false_ = false; + range->always_true_ = false; + range->min_offset_ = node.min_offset_; + range->max_offset_ = node.max_offset_; + range->include_start_ = node.include_start_; + range->include_end_ = node.include_end_; + range->is_phy_rowid_ = node.is_phy_rowid_; + + for (int64_t i = 0; OB_SUCC(ret) && i < pre_range_graph_->get_column_cnt(); ++i) { + if (i == node.min_offset_) { + range->start_[node.min_offset_] = start_val; + range->end_[node.min_offset_] = end_val; + } else { + int64_t start = node.start_keys_[i]; + int64_t end = node.end_keys_[i]; + if (start == OB_RANGE_MIN_VALUE) { + range->start_[i].set_min_value(); + } else if (start == OB_RANGE_MAX_VALUE) { + range->start_[i].set_max_value(); + } else if (start == OB_RANGE_NULL_VALUE) { + range->start_[i].set_null(); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", K(ret), K(node)); + } + if (OB_FAIL(ret)) { + } else if (end == OB_RANGE_MIN_VALUE) { + range->end_[i].set_min_value(); + } else if (end == OB_RANGE_MAX_VALUE) { + range->end_[i].set_max_value(); + } else if (end == OB_RANGE_NULL_VALUE) { + range->end_[i].set_null(); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", K(ret), K(node)); + } + } + } + } + return ret; +} + +int ObRangeGenerator::generate_tmp_json_array_param(const ObRangeNode &node, + ObTmpInParam *&tmp_in_param) +{ + int ret = OB_SUCCESS; + InParam *in_param = nullptr; + ObObj* objs_ptr = nullptr; + const ObRangeColumnMeta *meta = nullptr; + ObObj const_param; + bool is_valid = false; + ObIJsonBase* j_base = nullptr; + if (OB_UNLIKELY(!node.is_domain_node_ || + node.node_id_ < 0 || + node.node_id_ >= all_tmp_node_caches_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected not in node", K(node.node_id_), K(all_tmp_node_caches_.count())); + } else if (OB_NOT_NULL(tmp_in_param = static_cast(all_tmp_node_caches_.at(node.node_id_)))) { + // do nothing + } else if (OB_UNLIKELY(node.min_offset_ < 0 || + node.min_offset_ >= pre_range_graph_->get_column_cnt())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range", K(node)); + } else if (OB_ISNULL(meta = pre_range_graph_->get_column_meta(node.min_offset_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexecpted null", K(meta)); + } else if (OB_ISNULL(tmp_in_param = (ObTmpInParam*)allocator_.alloc(sizeof(ObTmpInParam)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memeory failed", K(tmp_in_param)); + } else if (OB_FALSE_IT(tmp_in_param = new(tmp_in_param) ObTmpInParam(allocator_))) { + } else if (OB_FAIL(get_result_value(node.start_keys_[node.min_offset_], const_param, is_valid, exec_ctx_))) { + LOG_WARN("failed to get result value", K(node.start_keys_[node.min_offset_])); + } else if (!is_valid) { + tmp_in_param->always_false_ = true; + } else if (OB_FAIL(ObJsonExprHelper::refine_range_json_value_const(const_param, &exec_ctx_, false, &allocator_, j_base))) { + LOG_WARN("fail to get json val", K(ret), K(const_param)); + } else if (OB_ISNULL(j_base)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get json base", K(ret)); + } else if (j_base->is_json_scalar(j_base->json_type())) { + ObObj cast_obj = const_param; + int64_t cmp = 0; + if (OB_FAIL(ObJsonUtil::cast_json_scalar_to_sql_obj(&allocator_, + &exec_ctx_, + j_base, + meta->column_type_, + cast_obj))) { + ret = OB_SUCCESS; + tmp_in_param->always_true_ = true; + } else if (OB_FAIL(try_cast_value(*meta, cast_obj, cmp, CO_EQ))) { + LOG_WARN("failed to cast value", K(ret)); + } else if (cmp != 0) { + tmp_in_param->always_true_ = true; + } else if (OB_ISNULL(objs_ptr = (ObObj*)allocator_.alloc(sizeof(ObObj)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memeory failed", K(objs_ptr)); + } else if (OB_FAIL(tmp_in_param->in_param_.init(1))) { + LOG_WARN("failed to init fixed array size", K(ret)); + } else { + tmp_in_param->in_param_[0] = objs_ptr; + *objs_ptr = cast_obj; + } + } else if (j_base->json_type() == common::ObJsonNodeType::J_ARRAY) { + int64_t size = j_base->element_count(); + int64_t cmp = 0; + if (size == 0) { + tmp_in_param->always_true_ = true; + } else if (OB_ISNULL(objs_ptr = (ObObj*)allocator_.alloc(sizeof(ObObj) * size))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memeory failed", K(objs_ptr)); + } else if (OB_FAIL(tmp_in_param->in_param_.init(size))) { + LOG_WARN("failed to init fixed array size", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && !tmp_in_param->always_true_ && i < size; ++i) { + ObIJsonBase* tmp_j_base = nullptr; + if (OB_FAIL(j_base->get_array_element(i, tmp_j_base))) { + LOG_WARN("fail to get json array element", K(i), K(ret)); + } else if (OB_ISNULL(tmp_j_base)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get json array element result is null", K(i), K(ret)); + } else if (OB_FAIL(ObJsonUtil::cast_json_scalar_to_sql_obj(&allocator_, + &exec_ctx_, + tmp_j_base, + meta->column_type_, + objs_ptr[i]))) { + ret = OB_SUCCESS; + tmp_in_param->always_true_ = true; + } else if (OB_FAIL(try_cast_value(*meta, objs_ptr[i], cmp, CO_EQ))) { + LOG_WARN("failed to cast value", K(ret)); + } else if (cmp != 0) { + tmp_in_param->always_true_ = true; + } else { + tmp_in_param->in_param_.push_back(&objs_ptr[i]); + } + } + } + } else { + tmp_in_param->always_true_ = true; + } + return ret; +} + +int ObRangeGenerator::final_domain_range_node(const ObRangeNode &node, + const int64_t in_idx, + ObTmpInParam *in_param, + ObTmpRange *&range) +{ + int ret = OB_SUCCESS; + range = all_tmp_ranges_.at(node.node_id_); + if (range == nullptr) { + if (OB_FAIL(generate_tmp_range(range, pre_range_graph_->get_column_cnt()))) { + LOG_WARN("failed to generate tmp range"); + } + } + if (OB_SUCC(ret)) { + if (OB_ISNULL(in_param) || + OB_UNLIKELY(in_idx >= in_param->in_param_.count()) || + OB_ISNULL(in_param->in_param_.at(in_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected in idx", K(ret), K(in_idx), KPC(in_param)); + } else if (OB_FAIL(fill_domain_range_node(node, + *in_param->in_param_.at(in_idx), + *in_param->in_param_.at(in_idx), + range))) { + LOG_WARN("failed to fill domain equal range node", K(ret)); + } + } + return ret; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/rewrite/ob_range_generator.h b/src/sql/rewrite/ob_range_generator.h new file mode 100644 index 000000000..f33058337 --- /dev/null +++ b/src/sql/rewrite/ob_range_generator.h @@ -0,0 +1,220 @@ +/** + * 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_REWRITE_OB_RANGE_GENERATOR_H_ +#define OCEANBASE_SQL_REWRITE_OB_RANGE_GENERATOR_H_ + +#include "sql/rewrite/ob_query_range_define.h" +#include "sql/rewrite/ob_expr_range_converter.h" + +namespace oceanbase +{ +namespace sql +{ + +struct ObTmpRange : public common::ObDLinkBase +{ + ObTmpRange(common::ObIAllocator &allocator) + : start_(NULL), + end_(NULL), + include_start_(false), + include_end_(false), + always_true_(false), + always_false_(false), + min_offset_(0), + max_offset_(0), + column_cnt_(0), + is_phy_rowid_(false), + allocator_(allocator) + { + } + int copy(ObTmpRange &other); + int init_tmp_range(int64_t column_count); + void set_always_true(); + void set_always_false(); + int intersect(ObTmpRange &other, bool &need_delay); + int formalize(); + int refine_final_range(); + DECLARE_TO_STRING; + // int tailor_final_range(int64_t column_count); + common::ObObj *start_; + common::ObObj *end_; + bool include_start_; + bool include_end_; + bool always_true_; + bool always_false_; + int min_offset_; + int max_offset_; + int column_cnt_; + bool is_phy_rowid_; + common::ObIAllocator &allocator_; +}; + +typedef ObDList TmpRangeList; + +struct ObTmpInParam +{ + ObTmpInParam(common::ObIAllocator &allocator) + : always_false_(false), + always_true_(false), + in_param_(allocator) {} + + TO_STRING_KV(K_(always_false), K_(always_true), K(in_param_)); + bool always_false_; + bool always_true_; + ObFixedArray in_param_; +}; + +struct ObTmpGeoParam +{ + ObTmpGeoParam(common::ObIAllocator &allocator) + : always_true_(false), + start_keys_(allocator), + end_keys_(allocator) {} + + TO_STRING_KV(K(always_true_), K(start_keys_), K(end_keys_)); + bool always_true_; + ObFixedArray start_keys_; + ObFixedArray end_keys_; +}; + +class ObRangeGenerator +{ +public: + ObRangeGenerator(ObIAllocator &allocator, + ObExecContext &exec_ctx, + const ObPreRangeGraph *pre_range_graph, + ObIArray &ranges, + bool &all_single_value_ranges, + const common::ObDataTypeCastParams &dtc_params, + ObIArray &mbr_filters) + : allocator_(allocator), + exec_ctx_(exec_ctx), + pre_range_graph_(pre_range_graph), + ranges_(ranges), + all_single_value_ranges_(all_single_value_ranges), + dtc_params_(dtc_params), + range_map_(pre_range_graph->get_range_map()), + always_true_range_(nullptr), + always_false_range_(nullptr), + all_tmp_ranges_(allocator), + tmp_range_lists_(nullptr), + all_tmp_node_caches_(allocator), + always_false_tmp_range_(nullptr), + mbr_filters_(mbr_filters), + is_generate_ss_range_(false), + cur_datetime_(0) + { + if (OB_NOT_NULL(exec_ctx_.get_physical_plan_ctx())) { + cur_datetime_ = exec_ctx_.get_physical_plan_ctx()->get_cur_time().get_datetime(); + } + } + + int generate_ranges(); + int generate_ss_ranges(); + static int generate_fast_nlj_range(const ObPreRangeGraph &pre_range_graph, + const ParamStore ¶m_store, + ObIAllocator &allocator, + void *range_buffer); + static int check_can_final_fast_nlj_range(const ObPreRangeGraph &pre_range_graph, + const ParamStore ¶m_store, + bool &is_valid); + static int get_spatial_relationship_by_mask(const ObObj& extra, ObDomainOpType& op_type); + static bool is_geo_type(const ObDomainOpType& op_type); +private: + int generate_tmp_range(ObTmpRange *&tmp_range, const int64_t column_cnt); + int generate_one_range(ObTmpRange &tmp_range); + int generate_precise_get_range(const ObRangeNode &node); + int generate_standard_ranges(const ObRangeNode *node); + int formalize_standard_range(const ObRangeNode *node, ObTmpRange &range); + int generate_complex_ranges(const ObRangeNode *node); + int formalize_complex_range(const ObRangeNode *node); + int generate_one_complex_range(); + int final_range_node(const ObRangeNode *node, ObTmpRange *&range, bool need_cache); + int final_in_range_node(const ObRangeNode *node, const int64_t in_idx, ObTmpRange *&range); + int get_result_value(const int64_t param_idx, ObObj &val, bool &is_valid, ObExecContext &exec_ctx) const; + + int cast_value_type(ObTmpRange &range); + int try_cast_value(const ObRangeColumnMeta &meta, + ObObj &value, + int64_t &cmp, + common::ObCmpOp cmp_op); + int generate_contain_exec_param_range(); + int merge_and_remove_ranges(); + int try_intersect_delayed_range(ObTmpRange &range); + int create_new_range(ObNewRange *&range, int64_t column_cnt); + static inline bool is_const_expr_or_null(int64_t idx) { return idx < OB_RANGE_EXTEND_VALUE || OB_RANGE_NULL_VALUE == idx; } + int final_not_in_range_node(const ObRangeNode &node, + const int64_t not_in_idx, + ObTmpInParam *in_param, + ObTmpRange *&range); + int generate_tmp_not_in_param(const ObRangeNode &node, + ObTmpInParam *&in_param); + int generate_tmp_geo_param(const ObRangeNode &node, + ObTmpGeoParam *&tmp_geo_param); + int get_intersects_tmp_geo_param(uint32_t input_srid, + const common::ObString &wkb, + const common::ObDomainOpType op_type, + const double &distance, + ObTmpGeoParam *geo_param); + int get_coveredby_tmp_geo_param(uint32_t input_srid, + const common::ObString &wkb, + const common::ObDomainOpType op_type, + ObTmpGeoParam *geo_param); + int final_geo_range_node(const ObRangeNode &node, + const uint64_t start, + const uint64_t end, + ObTmpRange *&range); + int check_need_merge_range_nodes(const ObRangeNode *node, + bool &need_merge); + + int cast_double_to_fixed_double(const ObRangeColumnMeta &meta, + const ObObj& in_value, + ObObj &out_value); + + int refine_real_range(const ObAccuracy &accuracy, double &value); + int final_json_member_of_range_node(const ObRangeNode *node, ObTmpRange *&range, bool need_cache); + int fill_domain_range_node(const ObRangeNode &node, + const ObObj& start_val, + const ObObj& end_val, + ObTmpRange *range); + int generate_tmp_json_array_param(const ObRangeNode &node, + ObTmpInParam *&in_param); + int final_domain_range_node(const ObRangeNode &node, + const int64_t in_idx, + ObTmpInParam *in_param, + ObTmpRange *&range); +private: + ObRangeGenerator(); + static const int64_t RANGE_BUCKET_SIZE = 1000; +private: + ObIAllocator &allocator_; + ObExecContext &exec_ctx_; + const ObPreRangeGraph *pre_range_graph_; + ObIArray &ranges_; + bool &all_single_value_ranges_; + const common::ObDataTypeCastParams &dtc_params_; + const ObRangeMap &range_map_; + common::ObNewRange *always_true_range_; + common::ObNewRange *always_false_range_; + ObFixedArray all_tmp_ranges_; + TmpRangeList* tmp_range_lists_; + ObFixedArray all_tmp_node_caches_; + ObTmpRange *always_false_tmp_range_; + ObIArray &mbr_filters_; + bool is_generate_ss_range_; + int64_t cur_datetime_; +}; + + +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_REWRITE_OB_RANGE_GENERATOR_H_ diff --git a/src/sql/rewrite/ob_range_graph_generator.cpp b/src/sql/rewrite/ob_range_graph_generator.cpp new file mode 100644 index 000000000..fae31bbd6 --- /dev/null +++ b/src/sql/rewrite/ob_range_graph_generator.cpp @@ -0,0 +1,1723 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX SQL_REWRITE +#include "sql/rewrite/ob_range_graph_generator.h" +#include "common/ob_smart_call.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/code_generator/ob_column_index_provider.h" +namespace oceanbase +{ +using namespace common; +using namespace share::schema; +namespace sql +{ + +static const int64_t MAX_RANGE_SIZE = 100000; +ERRSIM_POINT_DEF(ERRSIM_CROP_RANGE_GRAPH_WITH_CHECK); +int ObRangeGraphGenerator::generate_range_graph(const ObIArray &exprs, + ObExprRangeConverter &range_node_generator) +{ + int ret = OB_SUCCESS; + ObRawExpr *expr = nullptr; + ObSEArray range_nodes; + ObSEArray pricise_exprs; + ObSEArray unprecise_exprs; + ObSEArray sorted_exprs; + if (OB_FAIL(range_node_generator.sort_range_exprs(exprs, sorted_exprs))) { + LOG_WARN("failed to sort range exprs", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < sorted_exprs.count(); ++i) { + ObRangeNode *range_node = nullptr; + bool is_precise = false; + int64_t max_offset = 0; + if (OB_ISNULL(expr = sorted_exprs.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (OB_FAIL(generate_range_node(expr, range_node_generator, range_node, 0, is_precise, max_offset))) { + LOG_WARN("faield to generate range node", K(ret)); + } else if (!range_node->always_true_ && + OB_FAIL(range_nodes.push_back(range_node))) { + LOG_WARN("failed to push back range node"); + } else if (expr->is_const_expr()) { + // isolated const expr which can be used as startup filter. Consider it imprecise. + } else if (is_precise && OB_FAIL(pricise_exprs.push_back(ObPriciseExprItem(expr, max_offset)))) { + LOG_WARN("failed to push back pricise expr item"); + } else if (!is_precise && !range_node->always_true_ && + OB_FAIL(unprecise_exprs.push_back(ObPriciseExprItem(expr, max_offset)))) { + LOG_WARN("failed to push back unprecise expr"); + } + } + LOG_DEBUG("total memory used to get pre range graph", + "total_size", allocator_.used() - range_node_generator.get_mem_used()); + + if (OB_FAIL(ret) && OB_ERR_QUERY_RANGE_MEMORY_EXHAUSTED == ret) { + // use too much memory when extract query range, generate whole range. + ret = OB_SUCCESS; + range_nodes.reset(); + LOG_INFO("use too much memory during extract query range, fall back to whole range", + K(ctx_.max_mem_size_)); + } + if (OB_SUCC(ret) && ctx_.is_geo_range_ && range_nodes.count() > 1) { + ObRangeNode *final_geo_range = nullptr; + if (OB_FAIL(or_range_nodes(range_node_generator, range_nodes, ctx_.column_cnt_, final_geo_range))) { + LOG_WARN("failed to or range nodes"); + } else if (OB_FALSE_IT(range_nodes.reuse())) { + } else if (OB_FAIL(range_nodes.push_back(final_geo_range))) { + LOG_WARN("failed to push back range nodes"); + } + } + if (OB_SUCC(ret)) { + ObRangeNode *final_range_node = nullptr; + bool can_fast_nlj_extraction = false; + if (range_nodes.empty()) { + if (OB_FAIL(range_node_generator.generate_always_true_or_false_node(true, final_range_node))) { + LOG_WARN("failed to generate whole range"); + } else { + final_range_node->node_id_ = 0; + pre_range_graph_->set_range_size(1); + pre_range_graph_->set_node_count(1); + pre_range_graph_->set_range_head(final_range_node); + pre_range_graph_->set_is_precise_get(false); + pre_range_graph_->set_is_standard_range(true); + pre_range_graph_->set_is_equal_range(false); + pre_range_graph_->set_is_get(false); + update_max_precise_offset(0); + } + } else if (OB_FAIL(and_range_nodes(range_nodes, ctx_.column_cnt_, final_range_node))) { + LOG_WARN("failed to and range nodes"); + } else if (is_standard_range(final_range_node) && OB_FAIL(relink_standard_range_if_needed(final_range_node))) { + LOG_WARN("failed to relink standard range if needed"); + } else if (OB_FAIL(formalize_final_range_node(final_range_node))) { + LOG_WARN("failed to formalize final range node"); + } else if (OB_FAIL(check_graph_type(final_range_node))) { + LOG_WARN("check graph type failed", K(ret)); + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(fill_range_exprs(pricise_exprs, unprecise_exprs))) { + LOG_WARN("failed to fill range exprs", K(ret)); + } else if (OB_FAIL(generate_expr_final_info())) { + LOG_WARN("failed to generate final exprs"); + } else if (pre_range_graph_->has_exec_param() && + OB_FAIL(check_can_fast_nlj_range_extraction(pre_range_graph_->get_range_head(), + pre_range_graph_->get_range_map(), + pre_range_graph_->is_equal_range(), + can_fast_nlj_extraction))) { + LOG_WARN("failed to check can fast nlj range extraction", K(ret)); + } else { + pre_range_graph_->set_fast_nlj_range(can_fast_nlj_extraction); + pre_range_graph_->set_contain_geo_filters(ctx_.contail_geo_filters_); + } + } + return ret; +} + +int ObRangeGraphGenerator::generate_range_node(ObRawExpr* expr, + ObExprRangeConverter &range_node_generator, + ObRangeNode *&range_node, + int64_t expr_depth, + bool &is_precise, + int64_t &max_offset) +{ + int ret = OB_SUCCESS; + range_node = nullptr; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (T_OP_AND == expr->get_expr_type() && !ctx_.is_geo_range_) { + if (OB_FAIL(generate_and_range_node(expr, range_node_generator, range_node, expr_depth+1, is_precise, max_offset))) { + LOG_WARN("failed to generate and range node"); + } + } else if (T_OP_OR == expr->get_expr_type() || + (T_OP_AND == expr->get_expr_type() && ctx_.is_geo_range_)) { + if (OB_FAIL(generate_or_range_node(expr, range_node_generator, range_node, expr_depth+1, is_precise, max_offset))) { + LOG_WARN("failed to generate or range node"); + } + } else if (OB_FALSE_IT(ctx_.refresh_max_offset_ = false)) { + } else if (OB_FAIL(range_node_generator.convert_expr_to_range_node(expr, range_node, expr_depth, is_precise))) { + LOG_WARN("failed to generate range node"); + } else if (OB_ISNULL(range_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range node"); + } else if (ctx_.refresh_max_offset_) { + max_offset = -1; + if (OB_FAIL(get_max_offset(range_node, max_offset))) { + LOG_WARN("failed to get max offset", K(ret)); + } + } else { + max_offset = range_node->max_offset_; + } + return ret; +} + +int ObRangeGraphGenerator::generate_and_range_node(ObRawExpr *and_expr, + ObExprRangeConverter &range_node_generator, + ObRangeNode *&range_node, + int64_t expr_depth, + bool &is_precise, + int64_t &max_offset) +{ + int ret = OB_SUCCESS; + is_precise = true; + max_offset = 0; + if (OB_ISNULL(and_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else { + ObSEArray range_nodes; + for (int64_t i = 0; OB_SUCC(ret) && i < and_expr->get_param_count(); ++i) { + ObRawExpr *expr = and_expr->get_param_expr(i); + ObRangeNode *tmp_node = nullptr; + bool cur_precise = false; + int64_t cur_max_offset = 0; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(i), KPC(and_expr)); + } else if (OB_FAIL(generate_range_node(expr, range_node_generator, tmp_node, + expr_depth, cur_precise, cur_max_offset))) { + LOG_WARN("failed to generate range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else { + is_precise &= cur_precise; + max_offset = std::max(max_offset, cur_max_offset); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(and_range_nodes(range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to do and range nodes", K(ret)); + } + } + } + return ret; +} + +int ObRangeGraphGenerator::generate_or_range_node(ObRawExpr *or_expr, + ObExprRangeConverter &range_node_generator, + ObRangeNode *&range_node, + int64_t expr_depth, + bool &is_precise, + int64_t &max_offset) +{ + int ret = OB_SUCCESS; + is_precise = true; + max_offset = 0; + if (OB_ISNULL(or_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else { + ObSEArray range_nodes; + for (int64_t i = 0; OB_SUCC(ret) && i < or_expr->get_param_count(); ++i) { + ObRawExpr *expr = or_expr->get_param_expr(i); + ObRangeNode *tmp_node = nullptr; + bool cur_precise = false; + int64_t cur_max_offset = 0; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr", K(i), KPC(or_expr)); + } else if (OB_FAIL(generate_range_node(expr, range_node_generator, tmp_node, + expr_depth, cur_precise, cur_max_offset))) { + LOG_WARN("failed to generate range node", K(ret)); + } else if (OB_FAIL(range_nodes.push_back(tmp_node))) { + LOG_WARN("failed to push back range node"); + } else { + is_precise &= cur_precise; + max_offset = std::max(max_offset, cur_max_offset); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(or_range_nodes(range_node_generator, range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to do and range nodes", K(ret)); + } + } + } + return ret; +} + +/** + * 尝试合并多个and节点,要求满足如下条件 + * 1. 合并的range node不含or next节点 + * 2. 两个range node的参数必须存在交集或相邻 +*/ +int ObRangeGraphGenerator::and_range_nodes(ObIArray &range_nodes, + const int64_t column_cnt, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + if (range_nodes.count() > 1) { + // sort range node as following order: + // 1. always false + // 2. always true + // 3. node with smaller min_offset + lib::ob_sort(&range_nodes.at(0), &range_nodes.at(0) + range_nodes.count(), RangeNodeCmp()); + } + ObRangeNode *always_true_node = nullptr; + ObRangeNode *last_node = nullptr; + for (int64_t i = 0; OB_SUCC(ret) && i < range_nodes.count(); ++i) { + ObRangeNode *cur_node = range_nodes.at(i); + if (OB_ISNULL(cur_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range node"); + } else if (cur_node->always_false_) { + range_node = cur_node; + break; + } else if (cur_node->always_true_) { + if (always_true_node == nullptr) { + always_true_node = cur_node; + } + continue; + } else if (range_node == nullptr) { + range_node = cur_node; + last_node = cur_node; + } else if (cur_node->is_phy_rowid_ != last_node->is_phy_rowid_) { + // physical rowid node can only intersect with pyhsical rowid node + if (last_node->is_phy_rowid_) { + // do nothing + } else { + range_node = cur_node; + last_node = cur_node; + } + } else if (cur_node->min_offset_ == -1 || last_node->min_offset_ == -1 || + cur_node->is_not_in_node_ || last_node->is_not_in_node_|| + cur_node->is_domain_node_ || last_node->is_domain_node_) { + and_link_range_node(last_node, cur_node); + last_node = cur_node; + } else if (nullptr == cur_node->and_next_ && nullptr == cur_node->or_next_ && + nullptr == last_node->and_next_ && nullptr == last_node->or_next_ && + !(cur_node->contain_in_ && last_node->contain_in_)) { + bool merged = false; + if (OB_FAIL(and_two_range_node(last_node, cur_node, column_cnt, merged))) { + LOG_WARN("failed to and two range node"); + } else if (merged && last_node->always_false_) { + range_node = last_node; + break; + } else if (merged) { + last_node->max_offset_ = std::max(last_node->max_offset_, cur_node->max_offset_); + } else { + and_link_range_node(last_node, cur_node); + last_node = cur_node; + }; + } else { + and_link_range_node(last_node, cur_node); + last_node = cur_node; + } + } + if (OB_SUCC(ret) && range_node == nullptr) { + if (OB_ISNULL(always_true_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", K(range_nodes)); + } else { + range_node = always_true_node; + } + } + return ret; +} + +int ObRangeGraphGenerator::and_two_range_node(ObRangeNode *&l_node, + ObRangeNode *&r_node, + const int64_t column_cnt, + bool &is_merge) +{ + int ret = OB_SUCCESS; + is_merge = false; + if (OB_ISNULL(l_node) || OB_ISNULL(r_node) || + OB_UNLIKELY(l_node->min_offset_ > r_node->min_offset_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range node", KPC(l_node), KPC(r_node)); + } else if (l_node->max_offset_ < r_node->min_offset_ - 1) { + // only merge consistent node + } else if (r_node->min_offset_ - 1 >= 0 && r_node->min_offset_ - 1 >= l_node->min_offset_ && + l_node->start_keys_[r_node->min_offset_ - 1] != l_node->end_keys_[r_node->min_offset_ - 1]) { + // only merge previous offset has equal range node + // for example `c1 > 1` (1, max; max, max) and `c2 < 2` (ept, min; ept, 2) + // will not be merged as (1, max; max, 2) which equals to (1, max; max, max). + // Instead we remain both (1, max; max, max) and (ept, min; ept, 2). + // (ept, min; ept, 2) can used to extract skip scan range. + } else { + bool merge_start = false; + bool use_r_start = false; + int64_t start_offset = 0; + bool merge_end = false; + bool use_r_end = false; + int64_t end_offset = 0; + for (int64_t i = r_node->min_offset_; !merge_start && i < column_cnt; ++i) { + int64_t s1 = l_node->start_keys_[i]; + int64_t s2 = r_node->start_keys_[i]; + if (OB_UNLIKELY(s1 == OB_RANGE_EMPTY_VALUE || s2 == OB_RANGE_EMPTY_VALUE)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", K(i), K(s1), K(s2), K(l_node->min_offset_), K(r_node->min_offset_)); + } else if (s1 == OB_RANGE_MIN_VALUE) { + if (s2 == OB_RANGE_MIN_VALUE) { + continue; + } else if (s2 == OB_RANGE_MAX_VALUE) { + use_r_start = true; + merge_start = true; + } else if (s2 == OB_RANGE_NULL_VALUE) { + use_r_start = true; + merge_start = true; + } else if (s2 < OB_RANGE_EXTEND_VALUE) { + use_r_start = true; + merge_start = true; + } + } else if (s1 == OB_RANGE_MAX_VALUE) { + if (s2 == OB_RANGE_MIN_VALUE) { + merge_start = true; + } else if (s2 == OB_RANGE_MAX_VALUE) { + continue; + } else if (s2 == OB_RANGE_NULL_VALUE) { + merge_start = true; + } else if (s2 < OB_RANGE_EXTEND_VALUE) { + merge_start = true; + } + } else if (s1 == OB_RANGE_NULL_VALUE) { + if (s2 == OB_RANGE_MIN_VALUE) { + merge_start = true; + } else if (s2 == OB_RANGE_MAX_VALUE) { + use_r_start = true; + merge_start = true; + } else if (s2 == OB_RANGE_NULL_VALUE) { + continue; + } else if (s2 < OB_RANGE_EXTEND_VALUE) { + if (lib::is_oracle_mode()) { + merge_start = true; + } else { + use_r_start = true; + merge_start = true; + } + } + } else if (s1 < OB_RANGE_EXTEND_VALUE) { + if (s2 == OB_RANGE_MIN_VALUE) { + merge_start = true; + } else if (s2 == OB_RANGE_MAX_VALUE) { + use_r_start = true; + merge_start = true; + } else if (s2 == OB_RANGE_NULL_VALUE) { + if (lib::is_oracle_mode()) { + use_r_start = true; + merge_start = true; + } else { + merge_start = true; + } + } else if (s2 < OB_RANGE_EXTEND_VALUE) { + // can not compare + break; + } + } + if (use_r_start) { + start_offset = i; + } + } + for (int64_t i = r_node->min_offset_; !merge_end && i < column_cnt; ++i) { + int64_t e1 = l_node->end_keys_[i]; + int64_t e2 = r_node->end_keys_[i]; + if (OB_UNLIKELY(e1 == OB_RANGE_EMPTY_VALUE || e2 == OB_RANGE_EMPTY_VALUE)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", K(i), K(e1), K(e1)); + } else if (e1 == OB_RANGE_MIN_VALUE) { + if (e2 == OB_RANGE_MIN_VALUE) { + continue; + } else if (e2 == OB_RANGE_MAX_VALUE) { + merge_end = true; + } else if (e2 == OB_RANGE_NULL_VALUE) { + merge_end = true; + } else if (e2 < OB_RANGE_EXTEND_VALUE) { + merge_end = true; + } + } else if (e1 == OB_RANGE_MAX_VALUE) { + if (e2 == OB_RANGE_MIN_VALUE) { + use_r_end = true; + merge_end = true; + } else if (e2 == OB_RANGE_MAX_VALUE) { + continue; + } else if (e2 == OB_RANGE_NULL_VALUE) { + use_r_end = true; + merge_end = true; + } else if (e2 < OB_RANGE_EXTEND_VALUE) { + use_r_end = true; + merge_end = true; + } + } else if (e1 == OB_RANGE_NULL_VALUE) { + if (e2 == OB_RANGE_MIN_VALUE) { + use_r_end = true; + merge_end = true; + } else if (e2 == OB_RANGE_MAX_VALUE) { + merge_end = true; + } else if (e2 == OB_RANGE_NULL_VALUE) { + continue; + } else if (e2 < OB_RANGE_EXTEND_VALUE) { + if (lib::is_oracle_mode()) { + use_r_end = true; + merge_end = true; + } else { + merge_end = true; + } + } + } else if (e1 < OB_RANGE_EXTEND_VALUE) { + if (e2 == OB_RANGE_MIN_VALUE) { + use_r_end = true; + merge_end = true; + } else if (e2 == OB_RANGE_MAX_VALUE) { + merge_end = true; + } else if (e2 == OB_RANGE_NULL_VALUE) { + if (lib::is_oracle_mode()) { + merge_end = true; + } else { + use_r_end = true; + merge_end = true; + } + } else if (e2 < OB_RANGE_EXTEND_VALUE) { + // can not compare + break; + } + } + if (use_r_end) { + end_offset = i; + } + } + + if (merge_start && merge_end) { + is_merge = true; + if (use_r_start) { + set_new_start_key(*l_node, *r_node, column_cnt, start_offset); + l_node->include_start_ = r_node->include_start_; + } + if (use_r_end) { + set_new_end_key(*l_node, *r_node, column_cnt, end_offset); + l_node->include_end_ = r_node->include_end_; + } + if (use_r_start || use_r_end) { + l_node->max_offset_ = std::max(l_node->max_offset_, r_node->max_offset_); + } + if (l_node->contain_in_ || r_node->contain_in_) { + bool cnt_in = false; + for (int64_t i = 0; !cnt_in && i < column_cnt; ++i) { + if (l_node->start_keys_[i] < 0 || l_node->end_keys_[i] < 0) { + cnt_in = true; + } + } + l_node->contain_in_ = cnt_in; + l_node->in_param_count_ = cnt_in ? std::max(l_node->in_param_count_, r_node->in_param_count_) : 0; + } + } + } + if (OB_SUCC(ret) && is_merge) { + if (OB_FAIL(formalize_one_range_node(*l_node))) { + LOG_WARN("failed to formalize one range node", K(ret)); + } + } + return ret; +} + +void ObRangeGraphGenerator::set_new_start_key(ObRangeNode &l_node, + ObRangeNode &r_node, + const int64_t column_cnt, + int64_t start_offset) +{ + for (int64_t i = start_offset; i < column_cnt; ++i) { + l_node.start_keys_[i] = r_node.start_keys_[i]; + } +} + +void ObRangeGraphGenerator::set_new_end_key(ObRangeNode &l_node, + ObRangeNode &r_node, + const int64_t column_cnt, + int64_t start_offset) +{ + for (int64_t i = start_offset; i < column_cnt; ++i) { + l_node.end_keys_[i] = r_node.end_keys_[i]; + } +} + +int ObRangeGraphGenerator::or_range_nodes(ObExprRangeConverter &range_node_generator, + ObIArray &range_nodes, + const int64_t column_cnt, + ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + if (range_nodes.count() > 1) { + // sort range node as following order: + // 1. always false + // 2. always true + // 3. node with smaller min_offset + lib::ob_sort(&range_nodes.at(0), &range_nodes.at(0) + range_nodes.count(), RangeNodeCmp()); + } + ObRangeNode *last_node = nullptr; + ObRangeNode *always_false_node = nullptr; + for (int64_t i = 0; OB_SUCC(ret) && i < range_nodes.count(); ++i) { + ObRangeNode *cur_node = range_nodes.at(i); + if (OB_ISNULL(cur_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range node"); + } else if (cur_node->always_false_) { + if (always_false_node == nullptr) { + always_false_node = cur_node; + } + continue; + } else if (cur_node->always_true_) { + range_node = cur_node; + break; + } else if (range_node == nullptr) { + range_node = cur_node; + last_node = cur_node; + } else if (OB_UNLIKELY(cur_node->is_phy_rowid_ != last_node->is_phy_rowid_)) { + // rowid = xxx or c1 = 1 get always true + range_node = nullptr; + if (OB_FAIL(range_node_generator.generate_always_true_or_false_node(true, range_node))) { + LOG_WARN("failed to generate whole range"); + } + break; + } else { + while (last_node->or_next_ != nullptr) { + last_node = last_node->or_next_; + } + last_node->or_next_ = cur_node; + last_node = cur_node; + } + } + if (OB_SUCC(ret) && range_node == nullptr) { + if (OB_ISNULL(always_false_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", K(range_nodes)); + } else { + range_node = always_false_node; + } + } + return ret; +} + +/** + * 在 pre 阶段看不到具体的参数值, or 节点的合并只能处理一些非常简单的场景 + * 1. c1 > :1 (:1,max,max; null,min,min) + * c1 is null (null,min,min; null,max,max) + * => (:1,max,max, null,max,max) + * 2. c1 < :1 (min,min,min; :1,min,min) + * c1 >= :1 (:1,min,min; null,min,min) + * => (min,min,min, null,min,min) +*/ +int ObRangeGraphGenerator::or_two_range_node(ObRangeNode *&l_node, + ObRangeNode *&r_node, + const int64_t column_cnt) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(l_node) || OB_ISNULL(r_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null range node", KP(l_node), KP(r_node)); + } else { + bool is_equal = true; + for (int64_t i = r_node->min_offset_; is_equal && i < column_cnt; ++i) { + if (l_node->end_keys_[i] != r_node->start_keys_[i]) { + is_equal = false; + } else if (i == column_cnt - 1) { + if (l_node->end_keys_[i] != OB_RANGE_MIN_VALUE && + l_node->end_keys_[i] != OB_RANGE_MAX_VALUE && + !l_node->include_end_ && !r_node->include_start_) { + is_equal = false; + } + } + } + if (is_equal) { + MEMCPY(l_node->end_keys_, r_node->end_keys_, sizeof(int64_t) * column_cnt); + } else { + bool is_equal = true; + for (int64_t i = r_node->min_offset_; is_equal && i < column_cnt; ++i) { + if (l_node->start_keys_[i] != r_node->end_keys_[i]) { + is_equal = false; + } else if (i == column_cnt - 1) { + if (l_node->start_keys_[i] != OB_RANGE_MIN_VALUE && + l_node->start_keys_[i] != OB_RANGE_MAX_VALUE && + !l_node->include_start_ && !r_node->include_end_) { + is_equal = false; + } + } + } + if (is_equal) { + MEMCPY(l_node->start_keys_, r_node->start_keys_, sizeof(int64_t) * column_cnt); + } + } + } + return ret; +} + +int ObRangeGraphGenerator::and_link_range_node(ObRangeNode *&l_node, + ObRangeNode *&r_node) +{ + int ret = OB_SUCCESS; + ObSEArray and_tails; + if (OB_FAIL(get_and_tails(l_node, and_tails))) { + LOG_WARN("failed to get and tails"); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < and_tails.count(); ++i) { + if (OB_ISNULL(and_tails.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null"); + } else { + and_tails.at(i)->and_next_ = r_node; + } + } + } + return ret; +} + +int ObRangeGraphGenerator::get_and_tails(ObRangeNode *range_node, + ObIArray &and_tails) +{ + int ret = OB_SUCCESS; + for (ObRangeNode* cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->or_next_) { + if (cur_node->and_next_ == nullptr) { + if (OB_FAIL(and_tails.push_back(cur_node))) { + LOG_WARN("failed to push back and tail"); + } + } else if (OB_FAIL(SMART_CALL(get_and_tails(cur_node->and_next_, and_tails)))) { + LOG_WARN("failed to and link range node"); + } + } + return ret; +} + +/** + * formalize final range graph + * 1. estimate range size + * 2. check if skip scan valid + * 3. remove useless range node for standard range + * 4. generate node id +*/ +int ObRangeGraphGenerator::formalize_final_range_node(ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + if (range_node->always_false_ || range_node->always_true_) { + pre_range_graph_->set_range_size(1); + } else { + bool start_from_zero = false; + int64_t min_offset = 0; + uint64_t total_range_sizes[pre_range_graph_->get_column_count()]; + uint64_t range_sizes[pre_range_graph_->get_column_count()]; + for (int64_t i = 0; i < pre_range_graph_->get_column_count(); ++i) { + total_range_sizes[i] = 0; + range_sizes[i] = 1; + } + if (OB_FAIL(collect_graph_infos(range_node, total_range_sizes, range_sizes, start_from_zero, min_offset))) { + LOG_WARN("failed to collect graph infos"); + } else { + bool need_refine = false; + int64_t crop_offset = 0; + int64_t max_range_size = MAX_RANGE_SIZE; + if (ERRSIM_CROP_RANGE_GRAPH_WITH_CHECK) { + max_range_size = -ERRSIM_CROP_RANGE_GRAPH_WITH_CHECK; + } + for (int64_t i = 1; i < pre_range_graph_->get_column_count(); ++i) { + if (0 == total_range_sizes[i]) { + total_range_sizes[i] = total_range_sizes[i - 1]; + } + } + for (int64_t i = 0; !need_refine && i < pre_range_graph_->get_column_count(); ++i) { + if (total_range_sizes[i] > max_range_size) { + need_refine = true; + crop_offset = i; + } + } + if (OB_SUCC(ret) && need_refine) { + ObRangeNode* crop_range_node = range_node; + if (crop_offset == 0) { + range_node->set_always_true(); + } else if (OB_FAIL(crop_final_range_node(crop_range_node, crop_offset))) { + LOG_WARN("failed to crop final range node", K(ret)); + } else { + range_node = crop_range_node; + } + if (OB_SUCC(ret)) { + update_max_precise_offset(crop_offset); + start_from_zero = false; + if (range_node->always_true_) { + start_from_zero = true; + pre_range_graph_->set_range_size(1); + } else if (OB_FAIL(get_start_from_zero(range_node, start_from_zero))) { + LOG_WARN("failed to get start from zero", K(ret)); + } + } + } + } + if (OB_SUCC(ret) && is_standard_range(range_node)) { + ObRangeNode *ss_head = nullptr; + if (OB_FAIL(check_skip_scan_valid(range_node, ss_head))) { + LOG_WARN("failed to check skip scan valid"); + } else if (ss_head != nullptr) { + if (OB_FAIL(remove_useless_range_node(ss_head, pre_range_graph_->get_skip_scan_offset()))) { + LOG_WARN("failed to remove useless range", K(ret)); + } + } else if (OB_FAIL(remove_useless_range_node(range_node))) { + LOG_WARN("failed to remove useless range", K(ret)); + } + } + if (OB_SUCC(ret) && !start_from_zero && !pre_range_graph_->is_ss_range()) { + range_node->set_always_true(); + pre_range_graph_->set_range_size(1); + } + if (OB_SUCC(ret)) { + pre_range_graph_->set_total_range_sizes(total_range_sizes, pre_range_graph_->get_column_count()); + } + } + if (OB_SUCC(ret)) { + uint64_t node_count = 0; + if (OB_FAIL(generate_node_id(range_node, node_count))) { + LOG_WARN("failed to generate node id"); + } else { + pre_range_graph_->set_node_count(node_count); + } + } + return ret; +} + +int ObRangeGraphGenerator::collect_graph_infos(ObRangeNode *range_node, + uint64_t *total_range_sizes, + uint64_t *range_sizes, + bool &start_from_zero, + int64_t &min_offset) +{ + int ret = OB_SUCCESS; + uint64_t cur_or_count = 0; + if (range_node->always_true_ || range_node->always_false_) { + ret= OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected pos", KPC(range_node)); + } else { + int64_t idx = range_node->min_offset_; + for (const ObRangeNode *cur_node = range_node->or_next_; + -1 == idx && cur_node != nullptr; cur_node = cur_node->or_next_) { + idx = cur_node->min_offset_; + } + if (-1 == idx) { + idx = 0; + } + for (const ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->or_next_) { + if (cur_node->contain_in_) { + cur_or_count += cur_node->in_param_count_; + } else if (cur_node->is_not_in_node_) { + cur_or_count += cur_node->in_param_count_ + 1; + } else if (cur_node->is_domain_node_) { + cur_or_count += 25; + } else { + ++cur_or_count; + } + + if (nullptr == cur_node->or_next_ || + cur_node->min_offset_ != cur_node->or_next_->min_offset_ || + cur_node->or_next_->and_next_ != cur_node->and_next_) { + if (cur_node->min_offset_ <= 0) { + start_from_zero = true; + } + range_sizes[idx] *= cur_or_count; + min_offset = std::min(idx, min_offset); + if (cur_node->and_next_ != nullptr) { + int64_t child_min_offset = idx + 1; + if (OB_FAIL(SMART_CALL(collect_graph_infos(cur_node->and_next_, total_range_sizes, + range_sizes, start_from_zero, + child_min_offset)))) { + LOG_WARN("failed to collect graph infos"); + } else if (idx < child_min_offset) { + uint64_t range_size = 1; + for (int64_t i = 0; i <= idx; ++i) { + range_size *= range_sizes[i]; + } + total_range_sizes[idx] += range_size; + } + min_offset = std::min(child_min_offset, min_offset); + } else { + uint64_t range_size = 1; + for (int64_t i = 0; i <= idx; ++i) { + range_size *= range_sizes[i]; + } + total_range_sizes[idx] += range_size; + for (int64_t i = idx + 1; i < cur_node->column_cnt_; ++i) { + range_size *= range_sizes[i]; + total_range_sizes[i] += range_size; + } + } + range_sizes[idx] /= cur_or_count; + cur_or_count = 0; + } + } + } + return ret; +} + +int ObRangeGraphGenerator::check_skip_scan_valid(ObRangeNode *range_node, + ObRangeNode *&ss_head) +{ + int ret = OB_SUCCESS; + ss_head = NULL; + int64_t max_precise_pos = 0; + int64_t ss_max_precise_pos = 0; + ObRangeNode *cur_node = range_node; + if (OB_FAIL(get_max_precise_pos(range_node, max_precise_pos))) { + LOG_WARN("failed to get max precise pos"); + } else { + update_max_precise_offset(max_precise_pos); + // skip prefix precise range + while (cur_node != nullptr && cur_node->min_offset_ < max_precise_pos) { + cur_node = cur_node->and_next_; + } + if (NULL != cur_node) { + ss_head = cur_node; + pre_range_graph_->set_skip_scan_offset(ss_head->min_offset_); + if (OB_FAIL(get_max_precise_pos(ss_head, ss_max_precise_pos, ss_head->min_offset_))) { + LOG_WARN("failed to get max precise pos"); + } else { + update_ss_max_precise_offset(ss_max_precise_pos); + } + } + } + return ret; +} + +int ObRangeGraphGenerator::remove_useless_range_node(ObRangeNode *range_node, int64_t start_pos) const +{ + int ret = OB_SUCCESS; + int64_t max_offset = start_pos; + for (ObRangeNode *cur_node = range_node; cur_node != nullptr; cur_node = cur_node->and_next_) { + if (cur_node->min_offset_ > max_offset) { + cur_node->and_next_ = nullptr; + } else if (cur_node->max_offset_ >= max_offset) { + max_offset = cur_node->max_offset_ + 1; + } + } + return ret; +} + +int ObRangeGraphGenerator::generate_node_id(ObRangeNode *range_node, uint64_t &node_count) +{ + int ret = OB_SUCCESS; + for (ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->or_next_) { + cur_node->node_id_ = node_count++; + if (cur_node->and_next_ != nullptr && -1 == cur_node->and_next_->node_id_) { + if (OB_FAIL(SMART_CALL(generate_node_id(cur_node->and_next_, node_count)))) { + LOG_WARN("failed to generate node id"); + } + } + } + return ret; +} + +int ObRangeGraphGenerator::check_graph_type(ObRangeNode *range_node) +{ + int ret = OB_SUCCESS; + bool is_equal_range = false; + bool is_get = false; + int64_t max_precise_pos = 0; + pre_range_graph_->set_range_head(range_node); + pre_range_graph_->set_is_precise_get(is_precise_get(range_node)); + pre_range_graph_->set_is_standard_range(is_standard_range(range_node)); + if (pre_range_graph_->is_ss_range()) { + // do nothing + } else if (OB_FAIL(get_max_precise_pos(range_node, max_precise_pos))) { + LOG_WARN("failed to get max precise pos"); + } else { + update_max_precise_offset(max_precise_pos); + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(is_strict_equal_graph(range_node, is_equal_range, is_get))) { + LOG_WARN("is strict equal graph failed", K(ret)); + } else { + pre_range_graph_->set_is_equal_range(is_equal_range); + pre_range_graph_->set_is_get(ctx_.can_range_get_ && is_get); + } + } + return ret; +} + +bool ObRangeGraphGenerator::is_precise_get(ObRangeNode *range_node) const +{ + bool is_precise_get = false; + if (range_node->and_next_ == nullptr && range_node->or_next_ == nullptr && range_node->min_offset_ == 0) { + // range nodes can always merge to one node if is precise get + if (range_node->is_domain_node_ || range_node->contain_in_ || + range_node->is_not_in_node_) { + is_precise_get = false; + } else if (is_strict_equal_node(range_node)) { + is_precise_get = true; + } + } + return is_precise_get; +} + +bool ObRangeGraphGenerator::is_standard_range(ObRangeNode *range_node) const +{ + bool is_standard_range = true; + for (const ObRangeNode *cur_node = range_node; + is_standard_range && cur_node != nullptr; + cur_node = cur_node->and_next_) { + if (cur_node->contain_in_ || cur_node->or_next_ != nullptr || + cur_node->is_not_in_node_ || + cur_node->is_domain_node_) { + is_standard_range = false; + } + } + return is_standard_range; +} + +int ObRangeGraphGenerator::get_max_precise_pos(ObRangeNode *range_node, + int64_t &max_precise_pos, + int64_t start_pos) const +{ + int ret = OB_SUCCESS; + max_precise_pos = ctx_.column_cnt_; + if (!pre_range_graph_->is_precise_get()) { + bool equals[ctx_.column_cnt_]; + MEMSET(equals, 0, sizeof(bool) * ctx_.column_cnt_); + ret = inner_get_max_precise_pos(range_node, equals, max_precise_pos, start_pos); + } + return ret; +} + +int ObRangeGraphGenerator::inner_get_max_precise_pos(const ObRangeNode *range_node, + bool* equals, + int64_t &max_offset, + int64_t start_pos) const +{ + int ret = OB_SUCCESS; + ObSEArray new_idx; + for (const ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != NULL; cur_node = cur_node->or_next_) { + // reset equal flag in previous or range node + for (int64_t j = 0; j < new_idx.count(); ++j) { + equals[new_idx.at(j)] = false; + } + new_idx.reset(); + + if (cur_node->min_offset_ >= 0 && + !cur_node->is_not_in_node_ && + !cur_node->is_domain_node_ && + OB_FAIL(get_new_equal_idx(cur_node, equals, new_idx))) { + LOG_WARN("failed to get new idx"); + } else if (cur_node->and_next_ != nullptr) { + if(SMART_CALL(inner_get_max_precise_pos(cur_node->and_next_, equals, max_offset, start_pos))) { + LOG_WARN("failed to check is strict equal graph"); + } + } else { + int64_t cur_max_offset = ctx_.column_cnt_; + for (int64_t i = start_pos; i < ctx_.column_cnt_; ++i) { + if (!equals[i]) { + cur_max_offset = i; + break; + } + } + if (cur_max_offset + 1 < max_offset) { + max_offset = cur_max_offset + 1; + } + } + } + // reset equal flag in current range node + if (OB_SUCC(ret)) { + for (int64_t j = 0; j < new_idx.count(); ++j) { + equals[new_idx.at(j)] = false; + } + } + return ret; +} + +/** + * check if all ranges are strict euqal range. + * 1. key consecutive + * 2. key alignment + * 3. key has equal condition +*/ +int ObRangeGraphGenerator::is_strict_equal_graph(const ObRangeNode *range_node, + bool &is_strict_equal, + bool &is_get) const +{ + int ret = OB_SUCCESS; + if (pre_range_graph_->is_precise_get()) { + is_strict_equal = true; + is_get = true; + } else { + int64_t max_offset = -1; + int64_t max_node_offset = -1; + bool equals[ctx_.column_cnt_]; + MEMSET(equals, 0, sizeof(bool) * ctx_.column_cnt_); + if (OB_FAIL(SMART_CALL(inner_is_strict_equal_graph(range_node, equals, max_offset, + max_node_offset, is_strict_equal)))) { + LOG_WARN("failed to check inner is strict equal graph"); + } else if (is_strict_equal) { + is_get = max_offset == ctx_.column_cnt_; + } + } + return ret; +} + +int ObRangeGraphGenerator::inner_is_strict_equal_graph(const ObRangeNode *range_node, + bool* equals, + int64_t &max_offset, + int64_t &max_node_offset, + bool &is_strict_equal) const +{ + int ret = OB_SUCCESS; + is_strict_equal = true; + ObSEArray new_idx; + for (const ObRangeNode *cur_node = range_node; + OB_SUCC(ret) && is_strict_equal && cur_node != NULL; + cur_node = cur_node->or_next_) { + // reset equal flag in previous or range node + for (int64_t j = 0; j < new_idx.count(); ++j) { + equals[new_idx.at(j)] = false; + } + new_idx.reset(); + if (cur_node->max_offset_ > max_node_offset) { + max_node_offset = cur_node->max_offset_; + } + + if (cur_node->min_offset_ < 0 && + cur_node->and_next_ == nullptr) { + is_strict_equal = false; + } else if (cur_node->is_not_in_node_ || + cur_node->is_domain_node_) { + is_strict_equal = false; + } else if (cur_node->min_offset_ >= 0 && + OB_FAIL(get_new_equal_idx(cur_node, equals, new_idx))) { + LOG_WARN("failed to get new idx"); + } else if (cur_node->and_next_ != nullptr) { + if(OB_FAIL(SMART_CALL(inner_is_strict_equal_graph(cur_node->and_next_, equals, max_offset, + max_node_offset, is_strict_equal)))) { + LOG_WARN("failed to check is strict equal graph"); + } + } else { + if (-1 == max_offset) { + // max_offset = max_equal_offset + 1; + for (max_offset = 0; max_offset < ctx_.column_cnt_; ++max_offset) { + if (!equals[max_offset]) { + break; + } + } + for (int64_t i = max_offset + 1; i < ctx_.column_cnt_; ++i) { + if (equals[i]) { + is_strict_equal = false; + } + } + if (max_node_offset >= max_offset) { + is_strict_equal = false; + } + } else { + for (int64_t i = 0; i < max_offset; ++i) { + if (!equals[i]) { + is_strict_equal = false; + } + } + for (int64_t i = max_offset; i < ctx_.column_cnt_; ++i) { + if (equals[i]) { + is_strict_equal = false; + } + } + if (max_node_offset >= max_offset) { + is_strict_equal = false; + } + } + } + } + // reset equal flag in current range node + if (OB_SUCC(ret) && is_strict_equal) { + for (int64_t j = 0; j < new_idx.count(); ++j) { + equals[new_idx.at(j)] = false; + } + } + return ret; +} + +int ObRangeGraphGenerator::get_new_equal_idx(const ObRangeNode *range_node, + bool* equals, + ObIArray &new_idx) const +{ + int ret = OB_SUCCESS; + for (int64_t i = range_node->min_offset_; OB_SUCC(ret) && i <= range_node->max_offset_; ++i){ + if (!equals[i] && range_node->start_keys_[i] == range_node->end_keys_[i] && + (range_node->start_keys_[i] < OB_RANGE_EXTEND_VALUE || range_node->start_keys_[i] == OB_RANGE_NULL_VALUE)) { + equals[i] = true; + if (OB_FAIL(new_idx.push_back(i))) { + LOG_WARN("failed to push back idx", K(i)); + } + } + } + return ret; +} + +/** + * check if all key are equal condition. e.g. (:1,:2,:3; :1,:2,:3) +*/ +bool ObRangeGraphGenerator::is_strict_equal_node(const ObRangeNode *range_node) const +{ + bool is_equal = true; + for (int64_t i = 0; is_equal && i < ctx_.column_cnt_; ++i) { + if (range_node->start_keys_[i] != range_node->end_keys_[i] || + !is_const_expr_or_null(range_node->start_keys_[i])) { + is_equal = false; + } + } + return is_equal; +} + +/** + * check if all valid key are equal condition. e.g. (ept,:2,min; ept,:2,max) +*/ +bool ObRangeGraphGenerator::is_equal_node(const ObRangeNode *range_node) const +{ + bool is_equal = true; + if (range_node->min_offset_ < 0) { + // range node for const expr + is_equal = false; + } else { + for (int64_t i = range_node->min_offset_; is_equal && i < ctx_.column_cnt_; ++i) { + if (range_node->start_keys_[i] == OB_RANGE_MIN_VALUE && + range_node->end_keys_[i] == OB_RANGE_MAX_VALUE) { + // do nothing + } else if (range_node->start_keys_[i] != range_node->end_keys_[i]) { + is_equal = false; + } + } + } + return is_equal; +} + +int ObRangeGraphGenerator::fill_range_exprs(ObIArray &pricise_exprs, + ObIArray &unpricise_exprs) +{ + int ret = OB_SUCCESS; + ObSEArray range_exprs; + ObSEArray ss_range_exprs; + ObSEArray unpricise_range_exprs; + ObSEArray range_expr_max_offsets; + for (int64_t i = 0; OB_SUCC(ret) && i < pricise_exprs.count(); ++i) { + ObPriciseExprItem &expr_item = pricise_exprs.at(i); + if (expr_item.max_offset_ < max_precise_offset_) { + if (OB_FAIL(range_exprs.push_back(const_cast(expr_item.expr_)))) { + LOG_WARN("push back precise range expr failed", K(ret)); + } else if (OB_FAIL(range_expr_max_offsets.push_back(expr_item.max_offset_))) { + LOG_WARN("failed to push back to array", K(ret)); + } + } else if (expr_item.max_offset_ < ss_max_precise_offset_) { + if (OB_FAIL(ss_range_exprs.push_back(const_cast(expr_item.expr_)))) { + LOG_WARN("push back precise range expr failed", K(ret)); + } + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < unpricise_exprs.count(); ++i) { + ObPriciseExprItem &expr_item = unpricise_exprs.at(i); + if (expr_item.max_offset_ < max_precise_offset_) { + if (OB_FAIL(unpricise_range_exprs.push_back(const_cast(expr_item.expr_)))) { + LOG_WARN("push back precise range expr failed", K(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(pre_range_graph_->set_range_exprs(range_exprs))) { + LOG_WARN("failed to assign range exprs", K(ret)); + } else if (OB_FAIL(pre_range_graph_->set_ss_range_exprs(ss_range_exprs))) { + LOG_WARN("failed to assign range exprs", K(ret)); + } else if (OB_FAIL(pre_range_graph_->set_unprecise_range_exprs(unpricise_range_exprs))) { + LOG_WARN("failed to assign range exprs", K(ret)); + } else if (OB_FAIL(pre_range_graph_->set_range_expr_max_offsets(range_expr_max_offsets))) { + LOG_WARN("failed to assign range expr max offsets", K(ret)); + } else { + LOG_TRACE("finish fill range exprs", K(max_precise_offset_), K(ss_max_precise_offset_), + K(range_exprs), K(ss_range_exprs), K(unpricise_range_exprs)); + } + } + return ret; +} + +int ObRangeGraphGenerator::generate_expr_final_info() +{ + int ret = OB_SUCCESS; + RowDesc row_desc; + ObRangeMap &range_map = pre_range_graph_->get_range_map(); + ObIArray &final_exprs = ctx_.final_exprs_; + ObExecContext *exec_ctx = ctx_.exec_ctx_; + range_map.expr_final_infos_.reset(); + range_map.in_params_.reset(); + int64_t N = final_exprs.count(); + bool cnt_exec_param = false; + if (OB_ISNULL(exec_ctx) || OB_ISNULL(exec_ctx->get_sql_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(exec_ctx)); + } else if (OB_FAIL(range_map.expr_final_infos_.prepare_allocate(N))) { + LOG_WARN("failed to prepare allocate expr final infos", K(N)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { + const ObRawExpr *expr = final_exprs.at(i); + ObRangeMap::ExprFinalInfo &expr_info = range_map.expr_final_infos_.at(i); + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null expr"); + } else if (T_QUESTIONMARK == expr->get_expr_type()) { + const ObConstRawExpr *const_expr = static_cast(expr); + const ObObj& val = const_expr->get_value(); + if (OB_UNLIKELY(!val.is_unknown())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected value type", K(val)); + } else { + val.get_unknown(expr_info.param_idx_); + expr_info.is_param_ = true; + } + } else if (expr->has_flag(IS_CONST)) { + const ObConstRawExpr *const_expr = static_cast(expr); + void *ptr = exec_ctx->get_allocator().alloc(sizeof(ObObj)); + if (OB_ISNULL(ptr)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memeory for ObObj"); + } else { + expr_info.const_val_ = new(ptr)ObObj(); + expr_info.is_const_ = true; + if (OB_FAIL(ob_write_obj(exec_ctx->get_allocator(), const_expr->get_value(), *expr_info.const_val_))) { + LOG_WARN("failed to deep copy obj", K(const_expr->get_value())); + } + } + } else if (OB_FAIL(ObStaticEngineExprCG::gen_expr_with_row_desc( + expr, row_desc, + exec_ctx->get_allocator(), + exec_ctx->get_my_session(), + exec_ctx->get_sql_ctx()->schema_guard_, + expr_info.temp_expr_, + true))) { + LOG_WARN("failed to generate expr with row desc", K(ret)); + } else { + expr_info.is_expr_ = true; + } + + if (expr->has_flag(CNT_DYNAMIC_PARAM)) { + cnt_exec_param = true; + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < ctx_.null_safe_value_idxs_.count(); ++i) { + int64_t idx = ctx_.null_safe_value_idxs_.at(i); + if (OB_UNLIKELY(idx < 0 || idx >= range_map.expr_final_infos_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null safe idx", K(idx), K(range_map.expr_final_infos_.count())); + } else { + range_map.expr_final_infos_.at(idx).null_safe_ = true; + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < ctx_.rowid_idxs_.count(); ++i) { + int64_t idx = ctx_.rowid_idxs_.at(i).first; + if (OB_UNLIKELY(idx < 0 || idx >= range_map.expr_final_infos_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null safe idx", K(idx), K(range_map.expr_final_infos_.count())); + } else if (ctx_.rowid_idxs_.at(i).second == PHYSICAL_ROWID_IDX) { + range_map.expr_final_infos_.at(idx).rowid_idx_ = static_cast(ctx_.rowid_idxs_.at(i).second); + } else { + range_map.expr_final_infos_.at(idx).rowid_idx_ = static_cast(ctx_.rowid_idxs_.at(i).second) + 1; + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < ctx_.non_first_in_row_value_idxs_.count(); ++i) { + int64_t idx = ctx_.non_first_in_row_value_idxs_.at(i); + if (OB_UNLIKELY(idx < 0 || idx >= range_map.expr_final_infos_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected row value idx", K(idx), K(range_map.expr_final_infos_.count())); + } else { + range_map.expr_final_infos_.at(idx).is_not_first_col_in_row_ = true; + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(range_map.in_params_.assign(ctx_.in_params_))) { + LOG_WARN("failed to assign in params"); + } else { + pre_range_graph_->set_contain_exec_param(cnt_exec_param); + } + } + return ret; +} + +int ObRangeGraphGenerator::relink_standard_range_if_needed(ObRangeNode *&range_node) +{ + int ret = OB_SUCCESS; + bool need_relink = false; + int64_t last_off = -1; + for (const ObRangeNode *cur_node = range_node; !need_relink && cur_node != nullptr; cur_node = cur_node->and_next_) { + if (cur_node->min_offset_ < last_off) { + need_relink = true; + } else { + last_off = cur_node->min_offset_; + } + } + if (OB_UNLIKELY(need_relink)) { + ObSEArray range_nodes; + ObRangeNode *cur_node = range_node; + while (cur_node != nullptr) { + if (OB_FAIL(range_nodes.push_back(cur_node))) { + LOG_WARN("failed to push back range node"); + } else { + ObRangeNode *last_node = cur_node; + cur_node = cur_node->and_next_; + last_node->and_next_ = nullptr; + } + } + if (OB_SUCC(ret)) { + range_node = nullptr; + if (OB_FAIL(and_range_nodes(range_nodes, ctx_.column_cnt_, range_node))) { + LOG_WARN("failed to and range nodes"); + } + } + } + return ret; +} + +int ObRangeGraphGenerator::crop_final_range_node(ObRangeNode *&range_node, int64_t crop_offset) +{ + int ret = OB_SUCCESS; + uint64_t node_count = 0; + common::hash::ObHashMap refined_ranges; + common::hash::ObHashSet shared_ranges; + ObArenaAllocator alloc("CropRangeAlloc", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObRangeNode *out_range_node = nullptr; + RangeNodeConnectInfo connect_info; + bool check_range_graph = ERRSIM_CROP_RANGE_GRAPH_WITH_CHECK; + if (OB_ISNULL(out_range_node = range_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(generate_node_id(range_node, node_count))) { + LOG_WARN("failed to generate node id", K(ret)); + } else if (OB_FAIL(refined_ranges.create(node_count, "RefinedRanges", "RefinedRanges", MTL_ID()))) { + LOG_WARN("fail to init hashmap", K(ret)); + } else if (OB_FAIL(shared_ranges.create(1000, "SharedRanges", "SharedRanges", MTL_ID()))) { + LOG_WARN("failed to init hashset", K(ret)); + } else if (check_range_graph && + OB_FAIL(generate_range_node_connect_info(alloc, range_node, node_count, connect_info))) { + LOG_WARN("failed to generate range node connect info", K(ret)); + } else { + for (ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->and_next_) { + if (OB_FAIL(shared_ranges.set_refactored(reinterpret_cast(cur_node), 0))) { + LOG_WARN("failed to set refactored", K(ret)); + } + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(crop_final_range_node(out_range_node, crop_offset, connect_info, refined_ranges, shared_ranges))) { + LOG_WARN("failed to crop final range node", K(ret)); + } else if (OB_ISNULL(out_range_node)) { + range_node->set_always_true(); + } else { + range_node = out_range_node; + } + + if (OB_SUCC(ret) && OB_FAIL(reset_node_id(range_node))) { + LOG_WARN("failed to reset node id", K(ret)); + } + return ret; +} + +int ObRangeGraphGenerator::crop_final_range_node( + ObRangeNode *&range_node, int64_t crop_offset, + RangeNodeConnectInfo &connect_info, + common::hash::ObHashMap &refined_ranges, + common::hash::ObHashSet &shared_ranges) +{ + int ret = OB_SUCCESS; + ObRangeNode *out_range_node = nullptr; + if (OB_ISNULL(range_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null"); + } else if (OB_FAIL(refined_ranges.get_refactored(reinterpret_cast(range_node), + out_range_node))) { + if (OB_HASH_NOT_EXIST == ret) { + ret = OB_SUCCESS; + bool crop_or_node = false; + ObRangeNode* last_range_node = nullptr; + out_range_node = range_node; + ObRangeNode* prev_and_next = nullptr; + ObRangeNode* prev_and_next_out = nullptr; + for (ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; + cur_node = cur_node->or_next_) { + if (cur_node->and_next_ != nullptr) { + if (cur_node->and_next_ == prev_and_next) { + cur_node->and_next_ = prev_and_next_out; + } else if (OB_FALSE_IT(prev_and_next = cur_node->and_next_)) { + } else if (OB_FAIL(SMART_CALL(crop_final_range_node(cur_node->and_next_, + crop_offset, + connect_info, + refined_ranges, + shared_ranges)))) { + LOG_WARN("failed to refine range node"); + } else { + prev_and_next_out = cur_node->and_next_; + } + } + if (OB_SUCC(ret) && nullptr == cur_node->or_next_) { + last_range_node = cur_node; + } + } + if(OB_FAIL(ret)) { + } else if (range_node->or_next_ == nullptr) { + if (range_node->min_offset_ >= crop_offset) { + out_range_node = range_node->and_next_; + } + } else { + for (ObRangeNode *cur_node = range_node; + OB_SUCC(ret) && !crop_or_node && cur_node != nullptr; + cur_node = cur_node->or_next_) { + if (cur_node->min_offset_ >= crop_offset) { + crop_or_node = true; + } + } + if (OB_SUCC(ret) && crop_or_node) { + out_range_node = nullptr; + bool find = false; + for (ObRangeNode *cur_node = last_range_node->and_next_; OB_SUCC(ret) && cur_node != nullptr && !find; + cur_node = cur_node->and_next_) { + if (OB_HASH_EXIST == (ret = shared_ranges.exist_refactored(reinterpret_cast(cur_node)))) { + out_range_node = cur_node; + find = true; + ret = OB_SUCCESS; + } else if (OB_HASH_NOT_EXIST == ret) { + ret = OB_SUCCESS; + } else { + LOG_WARN("failed to get exist refactored", K(ret)); + } + } + } + if (OB_SUCC(ret) && crop_or_node && connect_info.inited_) { + if (nullptr != out_range_node && + OB_FAIL(check_crop_range_node_valid(range_node, out_range_node, connect_info))) { + LOG_WARN("failed to check crop range node valid", K(ret)); + } + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(refined_ranges.set_refactored(reinterpret_cast(range_node), + out_range_node))) { + LOG_WARN("failed to set refined ranges refactored", K(ret)); + } else { + range_node = out_range_node; + } + } + } else { + LOG_WARN("failed to get refined ranges from map", K(ret)); + } + } else { + range_node = out_range_node; + } + return ret; +} + +int ObRangeGraphGenerator::reset_node_id(ObRangeNode *range_node) +{ + int ret = OB_SUCCESS; + for (ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->or_next_) { + cur_node->node_id_ = -1; + if (cur_node->and_next_ != nullptr && -1 != cur_node->and_next_->node_id_) { + if (OB_FAIL(SMART_CALL(reset_node_id(cur_node->and_next_)))) { + LOG_WARN("failed to generate node id"); + } + } + } + return ret; +} + +int ObRangeGraphGenerator::generate_range_node_connect_info(ObIAllocator &allocator, + ObRangeNode *range_node, + uint64_t node_count, + RangeNodeConnectInfo &connect_info) +{ + int ret = OB_SUCCESS; + int64_t alloc_size = 0; + connect_info.inited_ = true; + connect_info.data_ = nullptr; + connect_info.node_count_ = node_count; + connect_info.per_node_info_len_ = 0; + if (OB_ISNULL(range_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FALSE_IT(connect_info.per_node_info_len_ = ((connect_info.node_count_ + 8) / 8))) { + } else if (OB_FALSE_IT(alloc_size = connect_info.node_count_ * connect_info.per_node_info_len_)) { + } else if (OB_ISNULL(connect_info.data_ = (uint8_t*)allocator.alloc(alloc_size))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc connect info", K(ret)); + } else { + memset(connect_info.data_, 0, alloc_size); + } + + if (OB_SUCC(ret) && OB_FAIL(collect_range_node_connect_info(range_node, connect_info))) { + LOG_WARN("failed to collect range node connect info", K(ret)); + } + return ret; +} + +int ObRangeGraphGenerator::collect_range_node_connect_info(ObRangeNode *range_node, + RangeNodeConnectInfo &connect_info) +{ + int ret = OB_SUCCESS; + int64_t flag_index = 0; + if (OB_ISNULL(range_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_UNLIKELY(range_node->node_id_ == -1) || + OB_UNLIKELY(range_node->node_id_ >= connect_info.node_count_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range node", K(ret), KPC(range_node)); + } else if (OB_FALSE_IT(flag_index = (range_node->node_id_ + 1) * connect_info.per_node_info_len_ - 1)) { + } else if ((connect_info.data_[flag_index] & 128) == 128) { + // do nothing + } else { + int64_t range_node_offset = range_node->node_id_ * connect_info.per_node_info_len_; + for (ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr; cur_node = cur_node->or_next_) { + int64_t offset = cur_node->node_id_ * connect_info.per_node_info_len_ + cur_node->node_id_ / 8; + connect_info.data_[offset] |= 1 << (cur_node->node_id_ % 8); + if (cur_node->and_next_ == nullptr) { + // do nothing + } else if (OB_FAIL(SMART_CALL(collect_range_node_connect_info(cur_node->and_next_, + connect_info)))) { + LOG_WARN("failed to collect range node connect info", K(ret)); + } else { + int64_t cur_node_offset = cur_node->node_id_ * connect_info.per_node_info_len_; + int64_t next_node_offset = cur_node->and_next_->node_id_ * connect_info.per_node_info_len_; + for (int64_t i = 0; OB_SUCC(ret) && i < connect_info.per_node_info_len_; ++i) { + connect_info.data_[cur_node_offset + i] |= connect_info.data_[next_node_offset + i]; + } + if (OB_SUCC(ret) && cur_node != range_node) { + for (int64_t i = 0; OB_SUCC(ret) && i < connect_info.per_node_info_len_; ++i) { + connect_info.data_[range_node_offset + i] |= connect_info.data_[cur_node_offset + i]; + } + } + } + } + if (OB_SUCC(ret)) { + connect_info.data_[flag_index] |= 128; + } + } + return ret; +} + +int ObRangeGraphGenerator::check_crop_range_node_valid( + ObRangeNode *range_node, + ObRangeNode *next_range_node, + RangeNodeConnectInfo &connect_info) +{ + int ret = OB_SUCCESS; + for (ObRangeNode *check_node = range_node; OB_SUCC(ret) && check_node != nullptr; check_node = check_node->or_next_) { + if (next_range_node == nullptr) { + // do nothing + } else if (OB_ISNULL(check_node->and_next_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range graph", K(ret)); + } else if (next_range_node == check_node->and_next_) { + // do nothing + } else { + int64_t offset = check_node->and_next_->node_id_ * connect_info.per_node_info_len_ + + (next_range_node->node_id_ / 8); + uint8_t bit_mask = 1 << (next_range_node->node_id_ % 8); + if ((connect_info.data_[offset] & bit_mask ) != bit_mask) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected range graph", K(ret)); + } + } + } + return ret; +} + +int ObRangeGraphGenerator::get_max_offset(const ObRangeNode *range_node, int64_t &max_offset) +{ + int ret = OB_SUCCESS; + for (const ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr ; cur_node = cur_node->or_next_) { + max_offset = std::max(max_offset, cur_node->max_offset_); + if (cur_node->and_next_ == nullptr) { + // do nothing + } else if (OB_FAIL(SMART_CALL(get_max_offset(cur_node->and_next_, max_offset)))) { + LOG_WARN("failed to get max offset", K(ret)); + } + } + return ret; +} + +int ObRangeGraphGenerator::get_start_from_zero(const ObRangeNode *range_node, bool &start_from_zero) +{ + int ret = OB_SUCCESS; + for (const ObRangeNode *cur_node = range_node; OB_SUCC(ret) && cur_node != nullptr && !start_from_zero; + cur_node = cur_node->or_next_) { + if (nullptr == cur_node->or_next_ || + cur_node->min_offset_ != cur_node->or_next_->min_offset_ || + cur_node->or_next_->and_next_ != cur_node->and_next_) { + if (cur_node->min_offset_ <= 0) { + start_from_zero = true; + } + if (cur_node->and_next_ != nullptr && !start_from_zero) { + if (OB_FAIL(SMART_CALL(get_start_from_zero(cur_node->and_next_, start_from_zero)))) { + LOG_WARN("failed to collect graph infos"); + } + } + + } + } + return ret; +} + +int ObRangeGraphGenerator::check_can_fast_nlj_range_extraction(const ObRangeNode *range_node, + const ObRangeMap &range_map, + bool is_equal_range, + bool &fast_nlj_range) +{ + int ret = OB_SUCCESS; + fast_nlj_range = false; + if (OB_ISNULL(range_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (!is_equal_range) { + // do nothing + } else if (range_node->contain_in_ || + range_node->is_not_in_node_|| + range_node->is_domain_node_) { + // do nothing + } else if (OB_NOT_NULL(range_node->or_next_) || + OB_NOT_NULL(range_node->and_next_)) { + // do nothing + } else if (range_node->always_false_ || + range_node->always_true_) { + // do nothing + } else { + fast_nlj_range = true; + for (int64_t i = 0; OB_SUCC(ret) && fast_nlj_range && i < range_map.expr_final_infos_.count(); ++i) { + if (range_map.expr_final_infos_.at(i).is_const_ || + range_map.expr_final_infos_.at(i).is_param_) { + // do nothing + } else { + fast_nlj_range = false; + } + } + } + return ret; +} + +int ObRangeGraphGenerator::formalize_one_range_node(ObRangeNode &range_node) +{ + int ret = OB_SUCCESS; + if (range_node.always_true_ || + range_node.always_false_ || + range_node.or_next_ != NULL || + range_node.is_domain_node_ || + range_node.is_not_in_node_) { + // do nothing + } else { + const int64_t* start = range_node.start_keys_; + const int64_t* end = range_node.end_keys_; + bool always_false = false; + for (int64_t i = range_node.min_offset_; i < range_node.column_cnt_; ++i) { + if (start[i] != end[i]) { + break; + } else if (i == range_node.column_cnt_ - 1 && + !(range_node.include_start_ && range_node.include_end_)) { + always_false = true; + } + } + if (OB_SUCC(ret) && always_false) { + range_node.set_always_false(); + } + } + return ret; +} + +} +} \ No newline at end of file diff --git a/src/sql/rewrite/ob_range_graph_generator.h b/src/sql/rewrite/ob_range_graph_generator.h new file mode 100644 index 000000000..35ce18dbb --- /dev/null +++ b/src/sql/rewrite/ob_range_graph_generator.h @@ -0,0 +1,204 @@ +/** + * 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_REWRITE_OB_RANGE_GRAPH_GENERATOR_H_ +#define OCEANBASE_SQL_REWRITE_OB_RANGE_GRAPH_GENERATOR_H_ + +#include "sql/rewrite/ob_query_range_define.h" +#include "sql/rewrite/ob_expr_range_converter.h" + + + +namespace oceanbase +{ +namespace sql +{ + +struct ObPriciseExprItem +{ + ObPriciseExprItem() + : expr_(nullptr), max_offset_(-1) {} + ObPriciseExprItem(ObRawExpr *expr, int64_t max_offset) + : expr_(expr), max_offset_(max_offset) {} + TO_STRING_KV(KPC(expr_), K(max_offset_)); + const ObRawExpr *expr_; + int64_t max_offset_; +}; + +struct RangeNodeCmp +{ + inline bool operator()(const ObRangeNode *left, const ObRangeNode *right) + { + bool bret = false; + if (left != nullptr && right != nullptr) { + if (left->always_false_ || right->always_false_) { + bret = !right->always_false_; + } else if (left->always_true_ || right->always_true_) { + bret = !right->always_true_; + } else { + bret = left->min_offset_ < right->min_offset_; + } + } + return bret; + } +}; + +struct RangeNodeConnectInfo +{ + RangeNodeConnectInfo() + : inited_(false), + data_(nullptr), + node_count_(0), + per_node_info_len_(0) { + } + bool inited_; + uint8_t* data_; + uint64_t node_count_; + uint64_t per_node_info_len_; +}; + +class ObRangeGraphGenerator +{ +public: + ObRangeGraphGenerator(ObIAllocator &allocator, + ObQueryRangeCtx &ctx, + ObPreRangeGraph *pre_range_graph, + int64_t column_cnt) + : allocator_(allocator), + ctx_(ctx), + pre_range_graph_(pre_range_graph), + max_precise_offset_(column_cnt), + ss_max_precise_offset_(column_cnt) + {} + + int generate_range_graph(const ObIArray &exprs, + ObExprRangeConverter &range_node_generator); + static int and_range_nodes(ObIArray &range_nodes, + const int64_t column_cnt, + ObRangeNode *&range_node); + static int or_range_nodes(ObExprRangeConverter &range_node_generator, + ObIArray &range_nodes, + const int64_t column_cnt, + ObRangeNode *&range_node); +private: + int generate_range_node(ObRawExpr* expr, + ObExprRangeConverter &range_node_generator, + ObRangeNode *&range_node, + int64_t expr_depth, + bool &is_precise, + int64_t &max_offset); + int generate_and_range_node(ObRawExpr *and_expr, + ObExprRangeConverter &range_node_generator, + ObRangeNode *&range_node, + int64_t expr_depth, + bool &is_precise, + int64_t &max_offset); + + static void set_new_start_key(ObRangeNode &l_node, ObRangeNode &r_node, const int64_t column_cnt, int64_t start_offset); + static void set_new_end_key(ObRangeNode &l_node, ObRangeNode &r_node, const int64_t column_cnt, int64_t start_offset); + + int generate_or_range_node(ObRawExpr *or_expr, + ObExprRangeConverter &range_node_generator, + ObRangeNode *&range_node, + int64_t expr_depth, + bool &is_precise, + int64_t &max_offset); + + static int and_two_range_node(ObRangeNode *&l_node, + ObRangeNode *&r_node, + const int64_t column_cnt, + bool &is_merge); + + static int or_two_range_node(ObRangeNode *&l_node, + ObRangeNode *&r_node, + const int64_t column_cnt); + + static int and_link_range_node(ObRangeNode *&l_node, ObRangeNode *&r_node); + static int get_and_tails(ObRangeNode *range_node, ObIArray &and_tails); + + int formalize_final_range_node(ObRangeNode *&range_node); + int collect_graph_infos(ObRangeNode *range_node, + uint64_t *total_range_sizes, + uint64_t *range_sizes, + bool &start_from_zero, + int64_t &min_offset); + int check_skip_scan_valid(ObRangeNode *range_node, + ObRangeNode *&ss_head); + static int generate_node_id(ObRangeNode *range_node, uint64_t &node_count); + + int check_graph_type(ObRangeNode *range_node); + + bool is_precise_get(ObRangeNode *range_node) const; + bool is_standard_range(ObRangeNode *range_node) const; + int get_max_precise_pos(ObRangeNode *range_node, int64_t &max_precise_pos, int64_t start_pos = 0) const; + int inner_get_max_precise_pos(const ObRangeNode *range_node, bool* equals, int64_t &max_offset, int64_t start_pos) const; + int remove_useless_range_node(ObRangeNode *range_node, int64_t start_pos = 0) const; + int is_strict_equal_graph(const ObRangeNode *range_node, bool &is_strict_equal, bool &is_get) const; + int inner_is_strict_equal_graph(const ObRangeNode *range_node, + bool* equals, + int64_t &max_offset, + int64_t &max_node_offset, + bool &is_strict_equal) const; + int get_new_equal_idx(const ObRangeNode *range_node, bool* equals, ObIArray &new_idx) const; + bool is_strict_equal_node(const ObRangeNode *range_node) const; + bool is_equal_node(const ObRangeNode *range_node) const; + + int fill_range_exprs(ObIArray &pricise_exprs, + ObIArray &unpricise_exprs); + int generate_expr_final_info(); + + inline void update_max_precise_offset(int64_t offset) { max_precise_offset_ = std::min(max_precise_offset_, offset); } + inline void update_ss_max_precise_offset(int64_t offset) { ss_max_precise_offset_ = std::min(ss_max_precise_offset_, offset); } + inline bool is_const_expr_or_null(int64_t idx) const + { + return idx < OB_RANGE_EXTEND_VALUE || OB_RANGE_NULL_VALUE == idx; + } + int relink_standard_range_if_needed(ObRangeNode *&range_node); + static int crop_final_range_node(ObRangeNode *&range_node, int64_t crop_offset); + static int crop_final_range_node(ObRangeNode *&range_node, int64_t crop_offset, + RangeNodeConnectInfo &connect_info, + common::hash::ObHashMap &refined_ranges, + common::hash::ObHashSet &shared_ranges); + static int check_crop_range_node_valid(ObRangeNode *range_node, + ObRangeNode *next_range_node, + RangeNodeConnectInfo &connect_info); + static int reset_node_id(ObRangeNode *range_node); + static int generate_range_node_connect_info(ObIAllocator &allocator, + ObRangeNode *range_node, + uint64_t node_count, + RangeNodeConnectInfo &connect_info); + static int collect_range_node_connect_info(ObRangeNode *range_node, + RangeNodeConnectInfo &connect_info); + + static int get_max_offset(const ObRangeNode *range_node, int64_t &max_offset); + + static int get_start_from_zero(const ObRangeNode *range_node, bool &start_from_zero); + + static int check_can_fast_nlj_range_extraction(const ObRangeNode *range_node, + const ObRangeMap &range_map, + bool is_equal_range, + bool &fast_nlj_range); + + static int formalize_one_range_node(ObRangeNode &range_node); +private: + ObRangeGraphGenerator(); +private: + ObIAllocator &allocator_; + ObQueryRangeCtx &ctx_; + ObPreRangeGraph *pre_range_graph_; + int64_t max_precise_offset_; + int64_t ss_max_precise_offset_; +}; + + +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_REWRITE_OB_RANGE_GRAPH_GENERATOR_H_ diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index a0f47b1be..9f5b0db2d 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -39,8 +39,10 @@ #include "sql/parser/ob_parser.h" #include "sql/rewrite/ob_transform_pre_process.h" #include "sql/rewrite/ob_expand_aggregate_utils.h" +#include "sql/ob_sql_utils.h" #include "share/stat/ob_opt_stat_manager.h" + namespace oceanbase { using namespace common; using namespace share::schema; @@ -3043,9 +3045,13 @@ int ObTransformUtils::get_simple_filter_column(const ObDMLStmt *stmt, OB_ISNULL(right = expr->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexcept null param expr", K(ret)); - } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(left, left)) || - OB_FAIL(ObOptimizerUtil::get_expr_without_lossless_cast(right, right))) { + } else if (OB_FAIL(ObOptimizerUtil::get_expr_without_unprecise_and_lossless_cast(left, left)) || + OB_FAIL(ObOptimizerUtil::get_expr_without_unprecise_and_lossless_cast(right, right))) { LOG_WARN("failed to get expr without lossless cast", K(ret)); + } else if (IS_BASIC_CMP_OP(expr->get_expr_type()) && + (OB_FAIL(ObOptimizerUtil::get_column_expr_without_nvl(left, left)) || + OB_FAIL(ObOptimizerUtil::get_column_expr_without_nvl(right, right)))) { + LOG_WARN("failed to get column expr without nvl", K(ret)); } else if (left->is_column_ref_expr() && table_id == static_cast(left)->get_table_id()) { if (right->get_relation_ids().has_member(stmt->get_table_bit_index(table_id))) { @@ -3485,27 +3491,50 @@ int ObTransformUtils::check_index_extract_query_range(const ObDMLStmt *stmt, ObRawExpr *condition_expr = NULL; ObArenaAllocator alloc(ObMemAttr(MTL_ID(), "RewriteMinMax")); void *tmp_ptr = NULL; - ObQueryRange *query_range = NULL; const ParamStore *params = NULL; ObQueryCtx *query_ctx = NULL; + ObSQLSessionInfo *session = NULL; if (OB_ISNULL(stmt) || OB_ISNULL(ctx) || OB_ISNULL(ctx->exec_ctx_) || OB_ISNULL(ctx->exec_ctx_->get_physical_plan_ctx()) - || OB_ISNULL(query_ctx = stmt->get_query_ctx())) { + || OB_ISNULL(query_ctx = stmt->get_query_ctx()) + || OB_ISNULL(session = ctx->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have null", K(ret), K(stmt), K(ctx)); + } else if (OB_FAIL(get_range_column_items_by_ids(stmt, + table_id, + index_cols, + range_columns))) { + LOG_WARN("failed to get index column items by index cols", K(ret)); + } else if (session->is_enable_new_query_range() && + ObSQLUtils::is_min_cluster_version_ge_425_or_435() && + ObSQLUtils::is_opt_feature_version_ge_425_or_435(query_ctx->optimizer_features_enable_version_)) { + ObPreRangeGraph *pre_range_graph = NULL; + params = &ctx->exec_ctx_->get_physical_plan_ctx()->get_param_store(); + if (OB_ISNULL(tmp_ptr = alloc.alloc(sizeof(ObPreRangeGraph))) || + OB_ISNULL(pre_range_graph = new(tmp_ptr)ObPreRangeGraph(alloc))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for pre range graph", K(ret)); + } else if (OB_FAIL(pre_range_graph->preliminary_extract_query_range(range_columns, + predicate_exprs, + ctx->exec_ctx_, + NULL, + params))) { + LOG_WARN("failed to extract query range", K(ret)); + } else if (pre_range_graph->get_range_exprs().count() != predicate_exprs.count()) { + is_match = false; + } + if (OB_NOT_NULL(pre_range_graph)) { + pre_range_graph->~ObPreRangeGraph(); + pre_range_graph = NULL; + } } else { + ObQueryRange *query_range = NULL; const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(ctx->session_info_); params = &ctx->exec_ctx_->get_physical_plan_ctx()->get_param_store(); - if (OB_FAIL(ret)) { - } else if (OB_ISNULL(tmp_ptr = alloc.alloc(sizeof(ObQueryRange))) - || OB_ISNULL(query_range = new(tmp_ptr)ObQueryRange(alloc))) { + if (OB_ISNULL(tmp_ptr = alloc.alloc(sizeof(ObQueryRange))) || + OB_ISNULL(query_range = new(tmp_ptr)ObQueryRange(alloc))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory for query range", K(ret)); - } else if (OB_FAIL(get_range_column_items_by_ids(stmt, - table_id, - index_cols, - range_columns))) { - LOG_WARN("failed to get index column items by index cols", K(ret)); } else if (OB_FAIL(query_range->preliminary_extract_query_range(range_columns, predicate_exprs, dtc_params, diff --git a/src/sql/session/ob_basic_session_info.cpp b/src/sql/session/ob_basic_session_info.cpp index 843690045..4c05ab5bf 100644 --- a/src/sql/session/ob_basic_session_info.cpp +++ b/src/sql/session/ob_basic_session_info.cpp @@ -5700,8 +5700,8 @@ int ObBasicSessionInfo::get_auto_increment_cache_size(int64_t &auto_increment_ca int ObBasicSessionInfo::get_optimizer_features_enable_version(uint64_t &version) const { int ret = OB_SUCCESS; - // if OPTIMIZER_FEATURES_ENABLE is set as '', use LASTED_COMPAT_VERSION - version = LASTED_COMPAT_VERSION; + // if OPTIMIZER_FEATURES_ENABLE is set as '', use COMPAT_VERSION_4_2_1 where this variable is introduced. + version = COMPAT_VERSION_4_2_1; ObString version_str; uint64_t tmp_version = 0; if (OB_FAIL(get_string_sys_var(SYS_VAR_OPTIMIZER_FEATURES_ENABLE, version_str))) { @@ -5709,7 +5709,7 @@ int ObBasicSessionInfo::get_optimizer_features_enable_version(uint64_t &version) } else if (version_str.empty() || OB_FAIL(ObClusterVersion::get_version(version_str, tmp_version)) || !ObGlobalHint::is_valid_opt_features_version(tmp_version)) { - LOG_WARN("fail invalid optimizer features version", K(ret), K(version_str), K(tmp_version)); + LOG_TRACE("fail invalid optimizer features version", K(ret), K(version_str), K(tmp_version)); ret = OB_SUCCESS; } else { version = tmp_version; diff --git a/src/sql/session/ob_sql_session_info.cpp b/src/sql/session/ob_sql_session_info.cpp index 26e9ac73d..138b22f75 100644 --- a/src/sql/session/ob_sql_session_info.cpp +++ b/src/sql/session/ob_sql_session_info.cpp @@ -659,6 +659,17 @@ int ObSQLSessionInfo::get_spm_mode(int64_t &spm_mode) return ret; } +bool ObSQLSessionInfo::is_enable_new_query_range() const +{ + bool bret = false; + int64_t tenant_id = get_effective_tenant_id(); + omt::ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_id)); + if (tenant_config.is_valid()) { + bret = tenant_config->_enable_new_query_range_extraction; + } + return bret; +} + void ObSQLSessionInfo::destroy(bool skip_sys_var) { if (is_inited_) { diff --git a/src/sql/session/ob_sql_session_info.h b/src/sql/session/ob_sql_session_info.h index e69db29c0..e7e16ab56 100644 --- a/src/sql/session/ob_sql_session_info.h +++ b/src/sql/session/ob_sql_session_info.h @@ -1315,6 +1315,7 @@ public: bool is_spf_mlj_group_rescan_enabled() const; int is_preserve_order_for_pagination_enabled(bool &enabled) const; int get_spm_mode(int64_t &spm_mode); + bool is_enable_new_query_range() const; ObSessionDDLInfo &get_ddl_info() { return ddl_info_; } const ObSessionDDLInfo &get_ddl_info() const { return ddl_info_; } diff --git a/tools/deploy/mysql_test/test_suite/column_store_encoding/r/mysql/basic_cs_encoding.result b/tools/deploy/mysql_test/test_suite/column_store_encoding/r/mysql/basic_cs_encoding.result index 46bba4996..2b9107f99 100644 --- a/tools/deploy/mysql_test/test_suite/column_store_encoding/r/mysql/basic_cs_encoding.result +++ b/tools/deploy/mysql_test/test_suite/column_store_encoding/r/mysql/basic_cs_encoding.result @@ -42,10 +42,10 @@ Query Plan ========================================================== |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| ---------------------------------------------------------- -|0 |SORT | |5 |35 | +|0 |SORT | |5 |36 | |1 |└─NESTED-LOOP JOIN | |5 |35 | |2 | ├─COLUMN TABLE FULL SCAN|t4 |2 |3 | -|3 | └─TABLE RANGE SCAN |t3 |3 |16 | +|3 | └─TABLE RANGE SCAN |t3 |10 |16 | ========================================================== Outputs & filters: ------------------------------------- diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result index 1ad659de6..77e64ec6d 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result @@ -352,6 +352,7 @@ _enable_kv_feature _enable_log_cache _enable_memleak_light_backtrace _enable_newsort +_enable_new_query_range_extraction _enable_new_sql_nio _enable_nlj_spf_use_rich_format _enable_optimizer_qualify_filter diff --git a/tools/deploy/mysql_test/test_suite/skyline/r/mysql/skyline_basic_mysql.result b/tools/deploy/mysql_test/test_suite/skyline/r/mysql/skyline_basic_mysql.result index ec790b080..b335a7303 100644 --- a/tools/deploy/mysql_test/test_suite/skyline/r/mysql/skyline_basic_mysql.result +++ b/tools/deploy/mysql_test/test_suite/skyline/r/mysql/skyline_basic_mysql.result @@ -626,7 +626,7 @@ Outputs & filters: 0 - output([t1.a], [t1.b], [t1.c]), filter([t1.a > 0], [t1.a < 100]), rowset=16 access([t1.b], [t1.a], [t1.c]), partitions(p0) is_index_back=false, is_global_index=false, filter_before_indexback[false,false], - range_key([t1.b], [t1.c], [t1.a], [t1.pk1]), range(100,100,MAX,MAX ; 100,MAX,100,MIN), + range_key([t1.b], [t1.c], [t1.a], [t1.pk1]), range(100,100,MAX,MAX ; 100,MAX,MAX,MAX), range_cond([t1.b = 100], [t1.c > 100]) explain select a, b, c from t1 where b = 100 and a > 0 and a < 100 and c = 200; Query Plan @@ -1539,42 +1539,44 @@ Outputs & filters: range_cond([t1.b = 100], [t1.c < 100], [t1.c > 100]) explain select a, b, c from t1 where b = 100 or (b = 200 and c = 300) order by c desc limit 0, 100; Query Plan -============================================================ -|ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| ------------------------------------------------------------- -|0 |LIMIT | |1 |5 | -|1 |└─TOP-N SORT | |1 |5 | -|2 | └─TABLE FULL SCAN|t1(idx_b_c_a)|1 |5 | -============================================================ +============================================================= +|ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| +------------------------------------------------------------- +|0 |LIMIT | |1 |5 | +|1 |└─TOP-N SORT | |1 |5 | +|2 | └─TABLE RANGE SCAN|t1(idx_b_c_a)|1 |5 | +============================================================= Outputs & filters: ------------------------------------- 0 - output([t1.a], [t1.b], [t1.c]), filter(nil), rowset=16 limit(100), offset(0) 1 - output([t1.a], [t1.b], [t1.c]), filter(nil), rowset=16 sort_keys([t1.c, DESC]), topn(100 + 0) - 2 - output([t1.b], [t1.c], [t1.a]), filter([t1.b = 100 OR t1.b = 200 AND t1.c = 300]), rowset=16 + 2 - output([t1.b], [t1.c], [t1.a]), filter(nil), rowset=16 access([t1.b], [t1.c], [t1.a]), partitions(p0) - is_index_back=false, is_global_index=false, filter_before_indexback[false], - range_key([t1.b], [t1.c], [t1.a], [t1.pk1]), range(100,MIN,MIN,MIN ; 100,MAX,MAX,MAX), (200,300,MIN,MIN ; 200,300,MAX,MAX) + is_index_back=false, is_global_index=false, + range_key([t1.b], [t1.c], [t1.a], [t1.pk1]), range(100,MIN,MIN,MIN ; 100,MAX,MAX,MAX), (200,300,MIN,MIN ; 200,300,MAX,MAX), + range_cond([t1.b = 100 OR t1.b = 200 AND t1.c = 300]) explain select a, b, c from t1 where (b = 200 and c = 300) or (b = 100) order by c desc limit 0, 100; Query Plan -============================================================ -|ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| ------------------------------------------------------------- -|0 |LIMIT | |1 |5 | -|1 |└─TOP-N SORT | |1 |5 | -|2 | └─TABLE FULL SCAN|t1(idx_b_c_a)|1 |5 | -============================================================ +============================================================= +|ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| +------------------------------------------------------------- +|0 |LIMIT | |1 |5 | +|1 |└─TOP-N SORT | |1 |5 | +|2 | └─TABLE RANGE SCAN|t1(idx_b_c_a)|1 |5 | +============================================================= Outputs & filters: ------------------------------------- 0 - output([t1.a], [t1.b], [t1.c]), filter(nil), rowset=16 limit(100), offset(0) 1 - output([t1.a], [t1.b], [t1.c]), filter(nil), rowset=16 sort_keys([t1.c, DESC]), topn(100 + 0) - 2 - output([t1.b], [t1.c], [t1.a]), filter([t1.b = 200 AND t1.c = 300 OR t1.b = 100]), rowset=16 + 2 - output([t1.b], [t1.c], [t1.a]), filter(nil), rowset=16 access([t1.b], [t1.c], [t1.a]), partitions(p0) - is_index_back=false, is_global_index=false, filter_before_indexback[false], - range_key([t1.b], [t1.c], [t1.a], [t1.pk1]), range(200,300,MIN,MIN ; 200,300,MAX,MAX), (100,MIN,MIN,MIN ; 100,MAX,MAX,MAX) + is_index_back=false, is_global_index=false, + range_key([t1.b], [t1.c], [t1.a], [t1.pk1]), range(100,MIN,MIN,MIN ; 100,MAX,MAX,MAX), (200,300,MIN,MIN ; 200,300,MAX,MAX), + range_cond([t1.b = 200 AND t1.c = 300 OR t1.b = 100]) explain select a1, a2, b, min(c), max(c) from t4 group by a1, a2, b; Query Plan ========================================================= diff --git a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/table_scan.result b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/table_scan.result index 1d03a42bb..31914223f 100644 --- a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/table_scan.result +++ b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/table_scan.result @@ -258,7 +258,7 @@ Outputs & filters: 0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c1 < 4]), rowset=16 access([t1.c1], [t1.c2], [t1.c3]), partitions(p0) is_index_back=true, is_global_index=false, filter_before_indexback[true], - range_key([t1.c2], [t1.c1]), range(1,MAX ; MAX,4), + range_key([t1.c2], [t1.c1]), range(1,MAX ; MAX,MAX), range_cond([t1.c2 > 1]) select /*+index(t1 idx)*/ c1, c2, c3 from t1 where c2 > 1 and c1 < 4; +----+------+------+ diff --git a/unittest/sql/resolver/expr/test_raw_expr_resolver.result b/unittest/sql/resolver/expr/test_raw_expr_resolver.result index 4c216a0ce..ebf5a711c 100644 --- a/unittest/sql/resolver/expr/test_raw_expr_resolver.result +++ b/unittest/sql/resolver/expr/test_raw_expr_resolver.result @@ -55,6 +55,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -86,6 +87,7 @@ "value": { "DECIMAL":"1" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -119,6 +121,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -183,6 +186,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -216,6 +220,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -249,6 +254,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -313,6 +319,7 @@ "value": { "BIGINT":2 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -371,6 +378,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -402,6 +410,7 @@ "value": { "BIGINT":2 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -433,6 +442,7 @@ "value": { "BIGINT":3 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -500,6 +510,7 @@ "value": { "BIGINT":2 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -558,6 +569,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -589,6 +601,7 @@ "value": { "BIGINT":2 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -620,6 +633,7 @@ "value": { "BIGINT":3 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -715,6 +729,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -777,6 +792,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -870,6 +886,7 @@ "value": { "BIGINT":100 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -932,6 +949,7 @@ "value": { "BIGINT":0 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -1027,6 +1045,7 @@ "value": { "BIGINT":100 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -1116,6 +1135,7 @@ "value": { "BIGINT":0 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -1178,6 +1198,7 @@ "value": { "BIGINT":100 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -1296,6 +1317,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, "when": [ @@ -1330,6 +1352,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -1363,6 +1386,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -1398,6 +1422,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -1431,6 +1456,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -1496,6 +1522,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, "when": [ @@ -1555,6 +1582,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -1586,6 +1614,7 @@ "value": { "BIGINT":0 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -1624,6 +1653,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -1774,6 +1804,7 @@ "value": { "DECIMAL":"3.14" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -2104,6 +2135,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -2376,6 +2408,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 } [18] @@auto_increment_increment @@ -2440,6 +2473,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"SYSCONST" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -2471,6 +2505,7 @@ "value": { "BIGINT":0 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -2666,6 +2701,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -2697,6 +2733,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -2789,6 +2826,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -3189,6 +3227,7 @@ "value": { "BIGINT":3 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -3301,6 +3340,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -3570,6 +3610,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -3601,6 +3642,7 @@ "value": { "BIGINT":2 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -3632,6 +3674,7 @@ "value": { "BIGINT":3 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -3663,6 +3706,7 @@ "value": { "BIGINT":4 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -3805,6 +3849,7 @@ "value": { "BIGINT":2 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -3916,6 +3961,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -4009,6 +4055,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -4040,6 +4087,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -4232,6 +4280,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -4263,6 +4312,7 @@ "value": { "BIGINT":2 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -4434,6 +4484,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -4465,6 +4516,7 @@ "value": { "BIGINT":10 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -4579,6 +4631,7 @@ "value": { "BIGINT":30 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -4732,6 +4785,7 @@ "value": { "BIGINT":1 }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -4817,6 +4871,7 @@ "value": { "UNKNOWN":0 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -4881,6 +4936,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -4997,6 +5053,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -5157,6 +5214,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 }, { @@ -5188,6 +5246,7 @@ "value": { "BIGINT":45 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -5229,6 +5288,7 @@ "value": { "BIGINT":46 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -5270,6 +5330,7 @@ "value": { "BIGINT":-4290838506 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -5311,6 +5372,7 @@ "value": { "BIGINT":-4290838506 }, + "is_dynamic_questionmark":false, "expr_hash":0 } ], @@ -5509,6 +5571,7 @@ "collation":"utf8mb4_general_ci", "coercibility":"COERCIBLE" }, + "is_dynamic_questionmark":false, "expr_hash":0 } ],