diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index c5cedfd8e4..7e93bcb80c 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -1274,6 +1274,7 @@ ob_set_subtarget(ob_sql rewrite rewrite/ob_transformer_impl.cpp rewrite/ob_transform_dblink.cpp rewrite/ob_union_find.cpp + rewrite/ob_transform_decorrelate.cpp ) ob_set_subtarget(ob_sql session diff --git a/src/sql/optimizer/ob_join_order.cpp b/src/sql/optimizer/ob_join_order.cpp index f7da907b2d..332ab0f957 100644 --- a/src/sql/optimizer/ob_join_order.cpp +++ b/src/sql/optimizer/ob_join_order.cpp @@ -7630,6 +7630,8 @@ int ObJoinOrder::init_base_join_order(const TableItem *table_item) set_type(JSON_TABLE_ACCESS); } else if (table_item->is_values_table()) { set_type(VALUES_TABLE_ACCESS); + } else if (table_item->is_lateral_table()) { + set_type(SUBQUERY); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid type of table item", K(table_item->type_), K(ret)); @@ -11669,15 +11671,10 @@ int ObJoinOrder::get_valid_path_info(const ObJoinOrder &left_tree, } //check depend function table if (OB_SUCC(ret)) { - if (OB_FAIL(check_depend_function_table(left_tree, - right_tree, - join_type, - path_info))) { - LOG_WARN("failed to check depend function table", K(ret)); - } else if (OB_FAIL(check_depend_json_table(left_tree, - right_tree, - join_type, - path_info))) { + if (OB_FAIL(check_depend_table(left_tree, + right_tree, + join_type, + path_info))) { LOG_WARN("failed to check depend function table", K(ret)); } else if (OB_FAIL(check_subquery_in_join_condition(join_type, join_conditions, @@ -11733,19 +11730,19 @@ int ObJoinOrder::get_valid_path_info(const ObJoinOrder &left_tree, return ret; } -int ObJoinOrder::check_depend_function_table(const ObJoinOrder &left_tree, - const ObJoinOrder &right_tree, - const ObJoinType join_type, - ValidPathInfo &path_info) +int ObJoinOrder::check_depend_table(const ObJoinOrder &left_tree, + const ObJoinOrder &right_tree, + const ObJoinType join_type, + ValidPathInfo &path_info) { int ret = OB_SUCCESS; if (OB_ISNULL(get_plan())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Input argument error", K(get_plan()), K(ret)); } else { - const ObIArray &infos = get_plan()->get_function_table_depend_infos(); + const ObIArray &infos = get_plan()->get_table_depend_infos(); for (int64_t i = 0; OB_SUCC(ret) && i < infos.count(); ++i) { - const FunctionTableDependInfo &info = infos.at(i); + const TableDependInfo &info = infos.at(i); if (left_tree.get_tables().has_member(info.table_idx_) && info.depend_table_set_.is_subset(right_tree.get_tables())) { path_info.local_methods_ = 0; @@ -11767,36 +11764,6 @@ int ObJoinOrder::check_depend_function_table(const ObJoinOrder &left_tree, return ret; } -int ObJoinOrder::check_depend_json_table(const ObJoinOrder &left_tree, - const ObJoinOrder &right_tree, - const ObJoinType join_type, - ValidPathInfo &path_info) -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(get_plan())) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("Input argument error", K(get_plan()), K(ret)); - } else { - const ObIArray &infos = get_plan()->get_json_table_depend_infos(); - for (int64_t i = 0; OB_SUCC(ret) && i < infos.count(); ++i) { - const JsonTableDependInfo &info = infos.at(i); - if (left_tree.get_tables().has_member(info.table_idx_) && - info.depend_table_set_.is_subset(right_tree.get_tables())) { - path_info.local_methods_ = 0; - } else if (right_tree.get_tables().has_member(info.table_idx_) && - info.depend_table_set_.is_subset(left_tree.get_tables())) { - if (RIGHT_OUTER_JOIN == join_type || FULL_OUTER_JOIN == join_type) { - ret = OB_NOT_SUPPORTED; - } else { - path_info.local_methods_ &= NESTED_LOOP_JOIN; - path_info.force_inner_nl_ = true; - } - } - } - } - return ret; -} - int ObJoinOrder::check_subquery_in_join_condition(const ObJoinType join_type, const ObIArray &join_conditions, ValidPathInfo &path_info) @@ -14014,6 +13981,9 @@ int ObJoinOrder::generate_inner_subquery_paths(const ObDMLStmt &parent_stmt, helper.filters_, can_pushdown))) { LOG_WARN("failed to pushdown filter into subquery", K(ret)); + } else if (table_item->is_lateral_table() && + OB_FAIL(append(nl_params, table_item->exec_params_))) { + LOG_WARN("failed to append exec params", K(ret)); } else if (!inner_path_info.force_inner_nl_ && !can_pushdown) { //do thing LOG_TRACE("can not pushdown any filter into subquery"); diff --git a/src/sql/optimizer/ob_join_order.h b/src/sql/optimizer/ob_join_order.h index e53d0c9283..eaadd05d8e 100644 --- a/src/sql/optimizer/ob_join_order.h +++ b/src/sql/optimizer/ob_join_order.h @@ -2300,14 +2300,10 @@ struct NullAwareAntiJoinInfo { bool contain_fake_cte, ValidPathInfo &path_info); - int check_depend_function_table(const ObJoinOrder &left_tree, - const ObJoinOrder &right_tree, - const ObJoinType join_type, - ValidPathInfo &path_info); - int check_depend_json_table(const ObJoinOrder &left_tree, - const ObJoinOrder &right_tree, - const ObJoinType join_type, - ValidPathInfo &path_info); + int check_depend_table(const ObJoinOrder &left_tree, + const ObJoinOrder &right_tree, + const ObJoinType join_type, + ValidPathInfo &path_info); int check_subquery_in_join_condition(const ObJoinType join_type, const ObIArray &join_conditions, ValidPathInfo &path_info); diff --git a/src/sql/optimizer/ob_log_join.cpp b/src/sql/optimizer/ob_log_join.cpp index ce8226d5ef..f390364437 100644 --- a/src/sql/optimizer/ob_log_join.cpp +++ b/src/sql/optimizer/ob_log_join.cpp @@ -91,6 +91,10 @@ int ObLogJoin::get_op_exprs(ObIArray &all_exprs) LOG_WARN("failed to generate join partition id expr", K(ret)); } else if (NULL != partition_id_expr_ && OB_FAIL(all_exprs.push_back(partition_id_expr_))) { LOG_WARN("failed to push back expr", K(ret)); + // lateral derived table exec params may eliminate by group by, add exec_params to all_exprs here + // otherwise, will report 4002 in cg + } else if (OB_FAIL(append(all_exprs, nl_params_))) { + LOG_WARN("failed to append exprs", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < nl_params_.count(); i++) { if (OB_ISNULL(nl_params_.at(i)) || diff --git a/src/sql/optimizer/ob_log_plan.cpp b/src/sql/optimizer/ob_log_plan.cpp index 7ac0843e90..e15596b4c0 100644 --- a/src/sql/optimizer/ob_log_plan.cpp +++ b/src/sql/optimizer/ob_log_plan.cpp @@ -753,6 +753,8 @@ int ObLogPlan::generate_join_orders() LOG_WARN("failed to init function table depend infos", K(ret)); } else if (OB_FAIL(init_json_table_depend_info(base_table_items))) { LOG_WARN("failed to init json table depend infos", K(ret)); + } else if (OB_FAIL(init_lateral_table_depend_info(base_table_items))) { + LOG_WARN("failed to init lateral table depend info", K(ret)); } else if (OB_FAIL(generate_conflict_detectors(from_table_items, stmt->get_semi_infos(), quals, @@ -1913,8 +1915,7 @@ int ObLogPlan::generate_cross_product_conflict_rule(ConflictDetector *cross_prod } else if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); - } else if (has_depend_function_table(expr->get_relation_ids()) - || has_depend_json_table(expr->get_relation_ids())) { + } else if (has_depend_table(expr->get_relation_ids())) { //do nothing } else { used_infos.reuse(); @@ -2609,7 +2610,7 @@ int ObLogPlan::init_function_table_depend_info(const ObIArray &table } for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { TableItem *table = table_items.at(i); - FunctionTableDependInfo info; + TableDependInfo info; if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); @@ -2623,12 +2624,12 @@ int ObLogPlan::init_function_table_depend_info(const ObIArray &table } else if (OB_FAIL(info.depend_table_set_.add_members(table->function_table_expr_->get_relation_ids()))) { LOG_WARN("failed to assign table ids", K(ret)); } else if (OB_FALSE_IT(info.table_idx_ = stmt->get_table_bit_index(table->table_id_))) { - } else if (OB_FAIL(function_table_depend_infos_.push_back(info))) { + } else if (OB_FAIL(table_depend_infos_.push_back(info))) { LOG_WARN("failed to push back info", K(ret)); } } if (OB_SUCC(ret)) { - LOG_TRACE("succeed to init function table depend info", K(function_table_depend_infos_)); + LOG_TRACE("succeed to init function table depend info", K(table_depend_infos_)); } return ret; } @@ -2722,7 +2723,7 @@ int ObLogPlan::init_json_table_depend_info(const ObIArray &table_ite } for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { TableItem *table = table_items.at(i); - JsonTableDependInfo info; + TableDependInfo info; if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); @@ -2736,12 +2737,12 @@ int ObLogPlan::init_json_table_depend_info(const ObIArray &table_ite } else if (OB_FAIL(info.depend_table_set_.add_members(table->json_table_def_->doc_expr_->get_relation_ids()))) { LOG_WARN("failed to assign table ids", K(ret)); } else if (OB_FALSE_IT(info.table_idx_ = stmt->get_table_bit_index(table->table_id_))) { - } else if (OB_FAIL(json_table_depend_infos_.push_back(info))) { + } else if (OB_FAIL(table_depend_infos_.push_back(info))) { LOG_WARN("failed to push back info", K(ret)); } } if (OB_SUCC(ret)) { - LOG_TRACE("succeed to init function table depend info", K(json_table_depend_infos_)); + LOG_TRACE("succeed to init function table depend info", K(table_depend_infos_)); } return ret; } @@ -7781,17 +7782,8 @@ int ObLogPlan::check_join_legal(const ObRelIds &left_set, } } //检查dependent function table的约束 - for (int64_t i = 0; OB_SUCC(ret) && legal && i < function_table_depend_infos_.count(); ++i) { - FunctionTableDependInfo &info = function_table_depend_infos_.at(i); - if (left_set.has_member(info.table_idx_)) { - legal = info.depend_table_set_.is_subset(left_set); - } else if (right_set.has_member(info.table_idx_)) { - legal = info.depend_table_set_.is_subset(left_set) || info.depend_table_set_.is_subset(right_set); - } - } - - for (int64_t i = 0; OB_SUCC(ret) && legal && i < json_table_depend_infos_.count(); ++i) { - JsonTableDependInfo &info = json_table_depend_infos_.at(i); + for (int64_t i = 0; OB_SUCC(ret) && legal && i < table_depend_infos_.count(); ++i) { + TableDependInfo &info = table_depend_infos_.at(i); if (left_set.has_member(info.table_idx_)) { legal = info.depend_table_set_.is_subset(left_set); } else if (right_set.has_member(info.table_idx_)) { @@ -12883,11 +12875,11 @@ int ObLogPlan::get_cached_hash_sharding_info(const ObIArray &hash_ex return ret; } -bool ObLogPlan::has_depend_function_table(const ObRelIds& table_ids) +bool ObLogPlan::has_depend_table(const ObRelIds& table_ids) { bool b_ret = false; - for (int64_t i = 0; !b_ret && i < function_table_depend_infos_.count(); ++i) { - FunctionTableDependInfo &info = function_table_depend_infos_.at(i); + for (int64_t i = 0; !b_ret && i < table_depend_infos_.count(); ++i) { + TableDependInfo &info = table_depend_infos_.at(i); if (table_ids.has_member(info.table_idx_)) { b_ret = true; } @@ -12895,17 +12887,6 @@ bool ObLogPlan::has_depend_function_table(const ObRelIds& table_ids) return b_ret; } -bool ObLogPlan::has_depend_json_table(const ObRelIds& table_ids) -{ - bool b_ret = false; - for (int64_t i = 0; !b_ret && i < json_table_depend_infos_.count(); ++i) { - JsonTableDependInfo &info = json_table_depend_infos_.at(i); - if (table_ids.has_member(info.table_idx_)) { - b_ret = true; - } - } - return b_ret; -} int ObLogPlan::allocate_output_expr_for_values_op(ObLogicalOperator &values_op) { @@ -14950,3 +14931,44 @@ int ObLogPlan::compute_duplicate_table_replicas(ObLogicalOperator *op) } return ret; } + +int ObLogPlan::init_lateral_table_depend_info(const ObIArray &table_items) +{ + int ret = OB_SUCCESS; + const ObDMLStmt *stmt = get_stmt(); + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null stmt", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { + TableItem *table = table_items.at(i); + TableDependInfo info; + if (OB_ISNULL(table)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null table item", K(ret)); + } else if (!table->is_lateral_table() || + table->exec_params_.empty()) { + //do nothing + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < table->exec_params_.count(); ++j) { + if (OB_ISNULL(table->exec_params_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(info.depend_table_set_.add_members( + table->exec_params_.at(j)->get_ref_expr()->get_relation_ids()))) { + LOG_WARN("failed to add table ids", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FALSE_IT(info.table_idx_ = stmt->get_table_bit_index(table->table_id_))) { + } else if (OB_FAIL(table_depend_infos_.push_back(info))) { + LOG_WARN("failed to push back info", K(ret)); + } + } + + } + if (OB_SUCC(ret)) { + LOG_TRACE("succeed to init function table depend info", K(table_depend_infos_)); + } + return ret; +} diff --git a/src/sql/optimizer/ob_log_plan.h b/src/sql/optimizer/ob_log_plan.h index b990aec586..cf2ccc76f5 100644 --- a/src/sql/optimizer/ob_log_plan.h +++ b/src/sql/optimizer/ob_log_plan.h @@ -72,7 +72,7 @@ class ObOptimizerContext; class ObLogJoin; struct JoinInfo; struct ConflictDetector; -struct FunctionTableDependInfo; +struct TableDependInfo; class ObLogSort; class ObLogJoinFilter; class ObLogSubPlanFilter; @@ -88,7 +88,7 @@ class ValuesTablePath; class ObSelectLogPlan; class ObThreeStageAggrInfo; -struct FunctionTableDependInfo { +struct TableDependInfo { TO_STRING_KV( K_(depend_table_set), K_(table_idx) @@ -96,7 +96,6 @@ struct FunctionTableDependInfo { ObRelIds depend_table_set_; //function table expr所依赖的表 int64_t table_idx_; //function table的bit index }; -typedef struct FunctionTableDependInfo JsonTableDependInfo; #undef KYES_DEF @@ -1295,14 +1294,9 @@ public: const EqualSets &equal_sets, ObShardingInfo *&cached_sharding); - inline const common::ObIArray &get_function_table_depend_infos() const + inline const common::ObIArray &get_table_depend_infos() const { - return function_table_depend_infos_; - } - - inline const common::ObIArray &get_json_table_depend_infos() const - { - return json_table_depend_infos_; + return table_depend_infos_; } int allocate_output_expr_for_values_op(ObLogicalOperator &values_op); @@ -1748,6 +1742,8 @@ protected: int create_hash_sortkey(const int64_t part_cnt, const common::ObIArray &order_keys, OrderItem &hash_sortkey); + + int init_lateral_table_depend_info(const ObIArray &table_items); private: // member functions static int strong_select_replicas(const common::ObAddr &local_server, common::ObIArray &phy_tbl_loc_info_list, @@ -1784,7 +1780,7 @@ private: // member functions const common::ObIArray &base_location_cons, ObStrictPwjComparer &pwj_comparer, PWJTabletIdMap &pwj_map) const; - bool has_depend_function_table(const ObRelIds& table_ids); + bool has_depend_table(const ObRelIds& table_ids); int get_histogram_by_join_exprs(ObOptimizerContext &optimizer_ctx, const ObDMLStmt *stmt, const ObRawExpr &expr, @@ -1792,7 +1788,6 @@ private: // member functions int get_popular_values_hash(common::ObIAllocator &allocator, ObOptColumnStatHandle &handle, common::ObIArray &popular_values) const; - bool has_depend_json_table(const ObRelIds& table_ids); int adjust_expr_properties_for_external_table(ObRawExpr *col_expr, ObRawExpr *&expr) const; int compute_duplicate_table_replicas(ObLogicalOperator *op); @@ -1902,8 +1897,7 @@ private: uint64_t outline_print_flags_; // used print outline common::ObSEArray bushy_tree_infos_; common::ObSEArray onetime_exprs_; // allocated onetime exprs - common::ObSEArray function_table_depend_infos_; - common::ObSEArray json_table_depend_infos_; + common::ObSEArray table_depend_infos_; common::ObSEArray conflict_detectors_; ObJoinOrder *join_order_; IdOrderMapAllocer id_order_map_allocer_; diff --git a/src/sql/optimizer/ob_optimizer_util.cpp b/src/sql/optimizer/ob_optimizer_util.cpp index 62b5ce1246..97b7205b7e 100644 --- a/src/sql/optimizer/ob_optimizer_util.cpp +++ b/src/sql/optimizer/ob_optimizer_util.cpp @@ -3555,25 +3555,33 @@ int ObOptimizerUtil::convert_subplan_scan_equal_sets(ObIAllocator *allocator, int ret = OB_SUCCESS; EqualSets dummy_equal_sets; ObSEArray raw_eset; - for (int64_t i = 0; OB_SUCC(ret) && i < input_equal_sets.count(); ++i) { - const EqualSet *input_eset = input_equal_sets.at(i); - raw_eset.reuse(); - if (OB_ISNULL(input_eset)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(ret)); - } else if (OB_FAIL(ObOptimizerUtil::convert_subplan_scan_expr(expr_factory, - dummy_equal_sets, - table_id, - parent_stmt, - child_stmt, - true, - *input_eset, - raw_eset))) { - LOG_WARN("failed to convert subplan scan expr", K(ret)); - } else if (raw_eset.count() > 1 && - OB_FAIL(ObRawExprSetUtils::add_expr_set(allocator, raw_eset, output_equal_sets))) { - LOG_WARN("failed to push back equal set", K(ret)); - } else { /*do nothing*/ } + TableItem *table_item = NULL; + if (OB_ISNULL(table_item = parent_stmt.get_table_item_by_id(table_id))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->is_lateral_table()) { + // do nothing + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < input_equal_sets.count(); ++i) { + const EqualSet *input_eset = input_equal_sets.at(i); + raw_eset.reuse(); + if (OB_ISNULL(input_eset)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::convert_subplan_scan_expr(expr_factory, + dummy_equal_sets, + table_id, + parent_stmt, + child_stmt, + true, + *input_eset, + raw_eset))) { + LOG_WARN("failed to convert subplan scan expr", K(ret)); + } else if (raw_eset.count() > 1 && + OB_FAIL(ObRawExprSetUtils::add_expr_set(allocator, raw_eset, output_equal_sets))) { + LOG_WARN("failed to push back equal set", K(ret)); + } else { /*do nothing*/ } + } } return ret; } @@ -3591,70 +3599,79 @@ int ObOptimizerUtil::convert_subplan_scan_fd_item_sets(ObFdItemFactory &fd_facto int ret = OB_SUCCESS; ObSEArray new_parent_exprs; ObRelIds tables; + TableItem* table_item = NULL; if (OB_FAIL(tables.add_member(parent_stmt.get_table_bit_index(table_id)))) { LOG_WARN("failed to add relid", K(ret), K(parent_stmt), K(table_id)); - } - for (int64_t i = 0; OB_SUCC(ret) && i < input_fd_item_sets.count(); ++i) { - const ObFdItem *old_fd_item = NULL; - new_parent_exprs.reuse(); - if (OB_ISNULL(old_fd_item = input_fd_item_sets.at(i)) || - OB_ISNULL(old_fd_item->get_parent_exprs())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(ret), K(old_fd_item)); - } else if (OB_FAIL(convert_subplan_scan_fd_parent_exprs(expr_factory, - equal_sets, - const_exprs, - table_id, - parent_stmt, - child_stmt, - *old_fd_item->get_parent_exprs(), - new_parent_exprs))) { - LOG_WARN("failed to convert subplan scan expr", K(ret)); - } else if (new_parent_exprs.empty()) { - /*do nothing*/ - } else if (old_fd_item->is_unique()) { - ObTableFdItem *table_fd_item = NULL; - if (OB_FAIL(fd_factory.create_table_fd_item(table_fd_item, true, new_parent_exprs, tables))) { - LOG_WARN("failed to create fd item", K(ret)); - } else if (OB_FAIL(output_fd_item_sets.push_back(table_fd_item))) { - LOG_WARN("failed to push back fd item", K(ret)); - } - } else { - ObRawExpr *temp_expr = NULL; - ObSEArray child_select_exprs; - ObSEArray new_child_exprs; - ObExprFdItem *expr_fd_item = NULL; - if (OB_FAIL(child_stmt.get_select_exprs(child_select_exprs))) { - LOG_WARN("failed to get select exprs", K(ret)); - } else { - for (int64_t j = 0; OB_SUCC(ret) && j < child_select_exprs.count(); ++j) { - bool is_in_child = false; - if (OB_FAIL(old_fd_item->check_expr_in_child(child_select_exprs.at(j), - equal_sets, - is_in_child))) { - LOG_WARN("failed to check expr in child"); - } else if (!is_in_child) { - /*do nothing*/ - } else if (NULL == (temp_expr = parent_stmt.get_column_expr_by_id( - table_id, - OB_APP_MIN_COLUMN_ID + j))) { - /*do nothing*/ - } else if (OB_FAIL(new_child_exprs.push_back(temp_expr))) { - LOG_WARN("failed to push back exprs", K(ret)); - } else { /*do nothing*/ } + } else if (OB_ISNULL(table_item = parent_stmt.get_table_item_by_id(table_id))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(table_item)); + } else if (table_item->is_lateral_table()) { + // do nothing + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < input_fd_item_sets.count(); ++i) { + const ObFdItem *old_fd_item = NULL; + bool contain_exec_param = false; + new_parent_exprs.reuse(); + if (OB_ISNULL(old_fd_item = input_fd_item_sets.at(i)) || + OB_ISNULL(old_fd_item->get_parent_exprs())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(old_fd_item)); + } else if (OB_FAIL(convert_subplan_scan_fd_parent_exprs(expr_factory, + equal_sets, + const_exprs, + table_id, + parent_stmt, + child_stmt, + *old_fd_item->get_parent_exprs(), + new_parent_exprs))) { + LOG_WARN("failed to convert subplan scan expr", K(ret)); + } else if (new_parent_exprs.empty()) { + /*do nothing*/ + } else if (old_fd_item->is_unique()) { + ObTableFdItem *table_fd_item = NULL; + if (OB_FAIL(fd_factory.create_table_fd_item(table_fd_item, true, new_parent_exprs, tables))) { + LOG_WARN("failed to create fd item", K(ret)); + } else if (OB_FAIL(output_fd_item_sets.push_back(table_fd_item))) { + LOG_WARN("failed to push back fd item", K(ret)); } - if (OB_SUCC(ret) && !new_child_exprs.empty()) { - if (OB_FAIL(fd_factory.create_expr_fd_item(expr_fd_item, false, - new_parent_exprs, - new_child_exprs))) { - LOG_WARN("failed to create fd item", K(ret)); - } else if (OB_FAIL(output_fd_item_sets.push_back(expr_fd_item))) { - LOG_WARN("failed to push back fd item", K(ret)); - } else { /*do nothing*/} + } else { + ObRawExpr *temp_expr = NULL; + ObSEArray child_select_exprs; + ObSEArray new_child_exprs; + ObExprFdItem *expr_fd_item = NULL; + if (OB_FAIL(child_stmt.get_select_exprs(child_select_exprs))) { + LOG_WARN("failed to get select exprs", K(ret)); + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < child_select_exprs.count(); ++j) { + bool is_in_child = false; + if (OB_FAIL(old_fd_item->check_expr_in_child(child_select_exprs.at(j), + equal_sets, + is_in_child))) { + LOG_WARN("failed to check expr in child"); + } else if (!is_in_child) { + /*do nothing*/ + } else if (NULL == (temp_expr = parent_stmt.get_column_expr_by_id( + table_id, + OB_APP_MIN_COLUMN_ID + j))) { + /*do nothing*/ + } else if (OB_FAIL(new_child_exprs.push_back(temp_expr))) { + LOG_WARN("failed to push back exprs", K(ret)); + } else { /*do nothing*/ } + } + if (OB_SUCC(ret) && !new_child_exprs.empty()) { + if (OB_FAIL(fd_factory.create_expr_fd_item(expr_fd_item, false, + new_parent_exprs, + new_child_exprs))) { + LOG_WARN("failed to create fd item", K(ret)); + } else if (OB_FAIL(output_fd_item_sets.push_back(expr_fd_item))) { + LOG_WARN("failed to push back fd item", K(ret)); + } else { /*do nothing*/} + } } } } } + return ret; } @@ -5041,24 +5058,34 @@ int ObOptimizerUtil::get_subplan_const_column(const ObDMLStmt &parent_stmt, ObIArray &output_exprs) { int ret = OB_SUCCESS; - for (int64_t i = 0; OB_SUCC(ret) && i < child_stmt.get_select_item_size(); ++i) { - const ObRawExpr *expr = child_stmt.get_select_item(i).expr_; - ObRawExpr *parent_expr = NULL; - bool is_const = false; - if (OB_ISNULL(expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("expr is null", K(ret), K(expr)); - } else if (OB_FAIL(is_const_expr_recursively(expr, exec_ref_exprs, is_const))) { - LOG_WARN("failed to check expr is const expr", K(ret)); - } else if (!is_const) { - // do nothing - } else if (NULL == (parent_expr = parent_stmt.get_column_expr_by_id(table_id, - OB_APP_MIN_COLUMN_ID + i))) { - // parent expr is prunned - } else if (OB_FAIL(add_var_to_array_no_dup(output_exprs, parent_expr))) { - LOG_WARN("failed to add parent expr into output", K(ret)); + TableItem *table_item = parent_stmt.get_table_item_by_id(table_id); + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->is_lateral_table()) { + // do nothing + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < child_stmt.get_select_item_size(); ++i) { + const ObRawExpr *expr = child_stmt.get_select_item(i).expr_; + ObRawExpr *parent_expr = NULL; + bool is_const = false; + bool contains = false; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr is null", K(ret), K(expr)); + } else if (OB_FAIL(is_const_expr_recursively(expr, exec_ref_exprs, is_const))) { + LOG_WARN("failed to check expr is const expr", K(ret)); + } else if (!is_const) { + // do nothing + } else if (NULL == (parent_expr = parent_stmt.get_column_expr_by_id(table_id, + OB_APP_MIN_COLUMN_ID + i))) { + // parent expr is prunned + } else if (OB_FAIL(add_var_to_array_no_dup(output_exprs, parent_expr))) { + LOG_WARN("failed to add parent expr into output", K(ret)); + } } } + return ret; } @@ -5074,34 +5101,42 @@ int ObOptimizerUtil::convert_subplan_scan_expr(ObRawExprFactory &expr_factory, int ret = OB_SUCCESS; bool is_valid = true; ObSEArray temp_exprs; + TableItem *table_item = parent_stmt.get_table_item_by_id(table_id); ObRawExprCopier copier(expr_factory); - for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < input_exprs.count(); i++) { - ObRawExpr *expr = NULL; - if (OB_ISNULL(input_exprs.at(i))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("null expr", K(input_exprs.at(i)), K(ret)); - } else if (OB_FAIL(convert_subplan_scan_expr(copier, - equal_sets, - table_id, - parent_stmt, - child_stmt, - input_exprs.at(i), - expr))) { - LOG_WARN("failed to generate subplan scan expr", K(ret)); - } else if (OB_ISNULL(expr)) { - if (!skip_invalid) { - is_valid = false; + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->is_lateral_table()) { + // do nothing + } else { + for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < input_exprs.count(); i++) { + ObRawExpr *expr = NULL; + if (OB_ISNULL(input_exprs.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null expr", K(input_exprs.at(i)), K(ret)); + } else if (OB_FAIL(convert_subplan_scan_expr(copier, + equal_sets, + table_id, + parent_stmt, + child_stmt, + input_exprs.at(i), + expr))) { + LOG_WARN("failed to generate subplan scan expr", K(ret)); + } else if (OB_ISNULL(expr)) { + if (!skip_invalid) { + is_valid = false; + } + } else if (OB_FAIL(add_var_to_array_no_dup(temp_exprs, expr))) { + LOG_WARN("failed to push back expr", K(ret)); + } else { /*do nothing*/ } + } + if (OB_SUCC(ret) && is_valid && !temp_exprs.empty()) { + if (OB_FAIL(output_exprs.assign(temp_exprs))) { + LOG_WARN("failed to push back exprs", K(ret)); + } else { + LOG_TRACE("succeed to convert subplan scan expr", K(input_exprs), + K(output_exprs)); } - } else if (OB_FAIL(add_var_to_array_no_dup(temp_exprs, expr))) { - LOG_WARN("failed to push back expr", K(ret)); - } else { /*do nothing*/ } - } - if (OB_SUCC(ret) && is_valid && !temp_exprs.empty()) { - if (OB_FAIL(output_exprs.assign(temp_exprs))) { - LOG_WARN("failed to push back exprs", K(ret)); - } else { - LOG_TRACE("succeed to convert subplan scan expr", K(input_exprs), - K(output_exprs)); } } return ret; @@ -8568,7 +8603,7 @@ int ObOptimizerUtil::expr_calculable_by_exprs(ObRawExpr *src_expr, return ret; } -int ObOptimizerUtil::check_contain_my_exec_param(ObRawExpr* expr, const common::ObIArray & my_exec_params, bool &contain) +int ObOptimizerUtil::check_contain_my_exec_param(const ObRawExpr* expr, const common::ObIArray & my_exec_params, bool &contain) { int ret = OB_SUCCESS; bool is_stack_overflow = false; @@ -9534,7 +9569,26 @@ bool ObOptimizerUtil::find_superset(const ObRelIds &rel_ids, } return bret; } -int ObOptimizerUtil::check_is_static_false_expr(ObOptimizerContext &opt_ctx, ObRawExpr &expr, bool &is_static_false) + +int ObOptimizerUtil::check_contain_my_exec_param(const ObIArray &exprs, + const ObIArray &my_exec_params, + bool &contain) +{ + int ret = OB_SUCCESS; + contain = false; + for (int64_t i = 0; OB_SUCC(ret) && !contain && i < exprs.count(); ++i) { + const ObRawExpr* expr = exprs.at(i); + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(check_contain_my_exec_param(expr, + my_exec_params, + contain))) { + LOG_WARN("failed to check contain my exec param", K(ret)); + } + } + return ret; +}int ObOptimizerUtil::check_is_static_false_expr(ObOptimizerContext &opt_ctx, ObRawExpr &expr, bool &is_static_false) { int ret = OB_SUCCESS; ObObj const_value; diff --git a/src/sql/optimizer/ob_optimizer_util.h b/src/sql/optimizer/ob_optimizer_util.h index 73588df570..59036ee9cb 100644 --- a/src/sql/optimizer/ob_optimizer_util.h +++ b/src/sql/optimizer/ob_optimizer_util.h @@ -1489,7 +1489,11 @@ public: ObOptimizerContext &opt_ctx, ObRawExpr *&calc_part_id_expr); - static int check_contain_my_exec_param(ObRawExpr* expr, const common::ObIArray & my_exec_params, bool &contain); + static int check_contain_my_exec_param(const ObRawExpr* expr, const common::ObIArray & my_exec_params, bool &contain); + + static int check_contain_my_exec_param(const ObIArray &exprs, + const ObIArray &my_exec_params, + bool &contain); static int generate_pseudo_trans_info_expr(ObOptimizerContext &opt_ctx, const common::ObString &table_name, diff --git a/src/sql/parser/non_reserved_keywords_mysql_mode.c b/src/sql/parser/non_reserved_keywords_mysql_mode.c index 888255415c..12c98c9b05 100644 --- a/src/sql/parser/non_reserved_keywords_mysql_mode.c +++ b/src/sql/parser/non_reserved_keywords_mysql_mode.c @@ -413,6 +413,7 @@ static const NonReservedKeyword Mysql_none_reserved_keywords[] = {"language", LANGUAGE}, {"last", LAST}, {"last_value", LAST_VALUE}, + {"lateral", LATERAL}, {"lead", LEAD}, {"leader", LEADER}, {"leading", LEADING}, diff --git a/src/sql/parser/sql_parser_mysql_mode.l b/src/sql/parser/sql_parser_mysql_mode.l index 549ffef878..30ad0e8f35 100644 --- a/src/sql/parser/sql_parser_mysql_mode.l +++ b/src/sql/parser/sql_parser_mysql_mode.l @@ -1147,6 +1147,8 @@ Timestamp{whitespace}?\"[^\"]*\" { DYNAMIC_SAMPLING { return DYNAMIC_SAMPLING; } BLOCKING { return BLOCKING; } PUSHDOWN { return PUSHDOWN; } +DECORRELATE { return DECORRELATE; } +NO_DECORRELATE { return NO_DECORRELATE; } {identifier} { if (!(IS_FAST_PARAMETERIZE)) { check_value(yylval); diff --git a/src/sql/parser/sql_parser_mysql_mode.y b/src/sql/parser/sql_parser_mysql_mode.y index 88223b12fe..801aae368d 100644 --- a/src/sql/parser/sql_parser_mysql_mode.y +++ b/src/sql/parser/sql_parser_mysql_mode.y @@ -175,6 +175,7 @@ PROJECT_PRUNE NO_PROJECT_PRUNE SIMPLIFY_SET NO_SIMPLIFY_SET OUTER_TO_INNER NO_OU COALESCE_SQ NO_COALESCE_SQ COUNT_TO_EXISTS NO_COUNT_TO_EXISTS LEFT_TO_ANTI NO_LEFT_TO_ANTI ELIMINATE_JOIN NO_ELIMINATE_JOIN PUSH_LIMIT NO_PUSH_LIMIT PULLUP_EXPR NO_PULLUP_EXPR WIN_MAGIC NO_WIN_MAGIC AGGR_FIRST_UNNEST NO_AGGR_FIRST_UNNEST JOIN_FIRST_UNNEST NO_JOIN_FIRST_UNNEST +DECORRELATE NO_DECORRELATE // optimize hint INDEX_HINT FULL_HINT NO_INDEX_HINT USE_DAS_HINT NO_USE_DAS_HINT INDEX_SS_HINT INDEX_SS_ASC_HINT INDEX_SS_DESC_HINT @@ -299,7 +300,7 @@ END_P SET_VAR DELIMITER KEY_BLOCK_SIZE KEY_VERSION KVCACHE KV_ATTRIBUTES - LAG LANGUAGE LAST LAST_VALUE LEAD LEADER LEAVES LESS LEAK LEAK_MOD LEAK_RATE LIB LINESTRING LIST_ + LAG LANGUAGE LAST LAST_VALUE LATERAL LEAD LEADER LEAVES LESS LEAK LEAK_MOD LEAK_RATE LIB LINESTRING LIST_ LISTAGG LOB_INROW_THRESHOLD LOCAL LOCALITY LOCATION LOCKED LOCKS LOGFILE LOGONLY_REPLICA_NUM LOGS LOCK_ LOGICAL_READS LEVEL LN LOG LS LINK LOG_RESTORE_SOURCE LINE_DELIMITER @@ -10437,6 +10438,14 @@ NO_REWRITE opt_qb_name { malloc_non_terminal_node($$, result->malloc_pool_, T_NO_JOIN_FIRST_UNNEST, 1, $2); } +| DECORRELATE opt_qb_name +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_DECORRELATE, 1, $2); +} +| NO_DECORRELATE opt_qb_name +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_NO_DECORRELATE, 1, $2); +} ; multi_qb_name_list: @@ -11414,6 +11423,11 @@ tbl_name { $$ = $1; } +| LATERAL table_subquery +{ + $$ = $2; + $$->value_ = 1; //lateral +} | select_with_parens %prec LOWER_PARENS { ParseNode *unname_node = NULL; @@ -11421,6 +11435,14 @@ tbl_name malloc_non_terminal_node($$, result->malloc_pool_, T_ALIAS, 2, $1, unname_node); unname_node->sql_str_off_ = @1.first_column; } +| LATERAL select_with_parens %prec LOWER_PARENS +{ + ParseNode *unname_node = NULL; + make_name_node(unname_node, result->malloc_pool_, ""); + malloc_non_terminal_node($$, result->malloc_pool_, T_ALIAS, 2, $2, unname_node); + unname_node->sql_str_off_ = @2.first_column; + $$->value_ = 1; //lateral +} | select_with_parens use_flashback %prec LOWER_PARENS { ParseNode *unname_node = NULL; @@ -11428,6 +11450,14 @@ tbl_name malloc_non_terminal_node($$, result->malloc_pool_, T_ALIAS, 6, $1, unname_node, unname_node, unname_node, unname_node, $2); unname_node->sql_str_off_ = @1.first_column; } +| LATERAL select_with_parens use_flashback %prec LOWER_PARENS +{ + ParseNode *unname_node = NULL; + make_name_node(unname_node, result->malloc_pool_, ""); + malloc_non_terminal_node($$, result->malloc_pool_, T_ALIAS, 6, $2, unname_node, unname_node, unname_node, unname_node, $3); + unname_node->sql_str_off_ = @2.first_column; + $$->value_ = 1; //lateral +} | '(' table_references ')' { $$ = $2; @@ -20147,6 +20177,7 @@ ACCOUNT | KEY_BLOCK_SIZE | KEY_VERSION | LAG +| LATERAL %prec LOWER_PARENS | LANGUAGE | LAST | LAST_VALUE diff --git a/src/sql/printer/ob_dml_stmt_printer.cpp b/src/sql/printer/ob_dml_stmt_printer.cpp index 724c4a1484..19d76baa3a 100644 --- a/src/sql/printer/ob_dml_stmt_printer.cpp +++ b/src/sql/printer/ob_dml_stmt_printer.cpp @@ -260,7 +260,10 @@ int ObDMLStmtPrinter::print_table_with_subquery(const TableItem *table_item) const uint64_t subquery_print_params = PRINT_BRACKET | (stmt_->is_select_stmt() ? FORCE_COL_ALIAS : 0); - if (OB_FAIL(print_subquery(table_item->ref_query_, + if (table_item->is_lateral_table()) { + DATA_PRINTF("lateral "); + } + if (OB_SUCC(ret) && OB_FAIL(print_subquery(table_item->ref_query_, subquery_print_params))) { LOG_WARN("failed to print subquery", K(ret)); } else if (!table_item->alias_name_.empty()) { @@ -403,6 +406,7 @@ int ObDMLStmtPrinter::print_table(const TableItem *table_item, } break; } + case TableItem::LATERAL_TABLE: case TableItem::GENERATED_TABLE: { if (OB_ISNULL(table_item->ref_query_)) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/resolver/dml/ob_aggr_expr_push_up_analyzer.cpp b/src/sql/resolver/dml/ob_aggr_expr_push_up_analyzer.cpp index 4cf53431d0..79e4659cc0 100644 --- a/src/sql/resolver/dml/ob_aggr_expr_push_up_analyzer.cpp +++ b/src/sql/resolver/dml/ob_aggr_expr_push_up_analyzer.cpp @@ -73,7 +73,7 @@ int ObAggrExprPushUpAnalyzer::analyze_and_push_up_aggr_expr(ObRawExprFactory &ex } else if (final_aggr_resolver == &cur_resolver_) { final_aggr = aggr_expr; } else if (OB_FAIL(ObRawExprUtils::get_exec_param_expr(expr_factory, - final_aggr_resolver->get_subquery(), + final_aggr_resolver->get_query_ref_exec_params(), aggr_expr, final_aggr))) { LOG_WARN("failed to get exec param expr", K(ret)); @@ -431,13 +431,13 @@ int ObAggrExprPushUpAnalyzer::get_exec_params(ObDMLResolver *resolver, ObIArray &my_exec_params) { int ret = OB_SUCCESS; - ObQueryRefRawExpr *query_ref = NULL; - if (OB_ISNULL(resolver) || OB_ISNULL(query_ref = resolver->get_subquery())) { + ObIArray *query_ref_exec_params = NULL; + if (OB_ISNULL(resolver) || OB_ISNULL(query_ref_exec_params = resolver->get_query_ref_exec_params())) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("params have null", K(ret), K(resolver), K(query_ref)); + LOG_WARN("params have null", K(ret), K(resolver), K(query_ref_exec_params)); } for (int64_t i = 0; OB_SUCC(ret) && i < all_exec_params.count(); ++i) { - if (!ObRawExprUtils::find_expr(query_ref->get_exec_params(), all_exec_params.at(i))) { + if (!ObRawExprUtils::find_expr(*query_ref_exec_params, all_exec_params.at(i))) { // do nothing } else if (OB_FAIL(my_exec_params.push_back(all_exec_params.at(i)))) { LOG_WARN("failed to push back exec param", K(ret)); diff --git a/src/sql/resolver/dml/ob_column_namespace_checker.cpp b/src/sql/resolver/dml/ob_column_namespace_checker.cpp index b62d6bdf7a..030fe3ad4f 100644 --- a/src/sql/resolver/dml/ob_column_namespace_checker.cpp +++ b/src/sql/resolver/dml/ob_column_namespace_checker.cpp @@ -29,7 +29,8 @@ namespace sql const TableItem *ObColumnNamespaceChecker::ObTableItemIterator::get_next_table_item() { const TableItem *table_item = NULL; - if (table_container_.cur_joined_table_ != NULL) { + if (table_container_.cur_joined_table_ != NULL && + !table_container_.params_.is_resolve_lateral_derived_table_) { //current_table_ is not null, means that we are resolving join table at present //so we can't touch the attribute of table in the current level if (0 == next_table_item_idx_) { @@ -41,6 +42,11 @@ const TableItem *ObColumnNamespaceChecker::ObTableItemIterator::get_next_table_i } else { if (next_table_item_idx_ < table_container_.all_table_refs_.count()) { table_item = table_container_.all_table_refs_.at(next_table_item_idx_++); + } else if (next_table_item_idx_ == table_container_.all_table_refs_.count() && + table_container_.params_.is_resolve_lateral_derived_table_ && + table_container_.cur_joined_table_ != NULL) { + ++next_table_item_idx_; + table_item = table_container_.cur_joined_table_; } else { table_item = NULL; } @@ -262,7 +268,7 @@ int ObColumnNamespaceChecker::check_column_exists(const TableItem &table_item, c params_.session_info_->get_effective_tenant_id(), table_id, col_name, is_exist))) { LOG_WARN("check column exists failed", K(ret)); } - } else if (table_item.is_generated_table() || table_item.is_temp_table()) { + } else if (table_item.is_generated_table() || table_item.is_temp_table() || table_item.is_lateral_table()) { ObSelectStmt *ref_stmt = table_item.ref_query_; if (OB_ISNULL(ref_stmt)) { ret = OB_NOT_INIT; diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index 7af8fe2160..b21e8fcb1d 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -81,7 +81,7 @@ ObDMLResolver::ObDMLResolver(ObResolverParams ¶ms) sequence_namespace_checker_(params), gen_col_exprs_(), from_items_order_(), - query_ref_(NULL), + query_ref_exec_params_(NULL), has_ansi_join_(false), has_oracle_join_(false), with_clause_without_record_(false), @@ -4072,7 +4072,11 @@ int ObDMLResolver::resolve_table(const ParseNode &parse_tree, } else { bool tmp_have_same_table = params_.have_same_table_name_; params_.have_same_table_name_ = false; - if (OB_FAIL(resolve_generate_table(*table_node, alias_node, table_item))) { + if (parse_tree.value_ == 1 && + OB_FAIL(resolve_lateral_generated_table(*table_node, alias_node, table_item))) { + LOG_WARN("failed to resolve lateral generate table", K(ret)); + } else if (parse_tree.value_ != 1 && + OB_FAIL(resolve_generate_table(*table_node, alias_node, table_item))) { LOG_WARN("resolve generate table failed", K(ret)); } else if (OB_FAIL(resolve_transpose_table(transpose_node, table_item))) { LOG_WARN("resolve_transpose_table failed", K(ret)); @@ -4581,7 +4585,7 @@ int ObDMLResolver::resolve_single_table_column_item(const TableItem &table_item, if (OB_FAIL(resolve_basic_column_item(table_item, column_name, include_hidden, col_item))) { LOG_WARN("resolve basic column item failed", K(ret)); } else { /*do nothing*/ } - } else if (table_item.is_generated_table() || table_item.is_temp_table()) { + } else if (table_item.is_generated_table() || table_item.is_temp_table() || table_item.is_lateral_table()) { if (OB_FAIL(resolve_generated_table_column_item(table_item, column_name, col_item))) { LOG_WARN("resolve generated table column failed", K(ret)); } @@ -4640,18 +4644,23 @@ int ObDMLResolver::resolve_joined_table_item(const ParseNode &parse_node, Joined JoinedTable *child_table = NULL; TableItem *table_item = NULL; ObSelectStmt *select_stmt = static_cast(stmt_); - + bool reverse_parse = false; if (OB_ISNULL(select_stmt) || OB_UNLIKELY(parse_node.type_ != T_JOINED_TABLE)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(select_stmt), K_(parse_node.type)); } else if (OB_FAIL(alloc_joined_table_item(cur_table))) { LOG_WARN("create joined table item failed", K(ret)); + } else if (parse_node.children_[0]->type_ == T_JOIN_RIGHT && + OB_FAIL(check_contain_lateral_node(&parse_node, + reverse_parse))) { + LOG_WARN("failed to check contain lateral node", K(ret)); } else { cur_table->table_id_ = generate_table_id(); cur_table->type_ = TableItem::JOINED_TABLE; } /* resolve table */ - for (uint64_t i = 1; OB_SUCC(ret) && i <= 2; i++) { + for (uint64_t index = 1; OB_SUCC(ret) && index <= 2; index++) { + uint64_t i = reverse_parse ? 3 - index : index; table_node = parse_node.children_[i]; // nested join case or normal join case if (T_JOINED_TABLE == table_node->type_) { @@ -4688,7 +4697,8 @@ int ObDMLResolver::resolve_joined_table_item(const ParseNode &parse_node, Joined * cte不能出现在right join的左面,不能出现在left join的右边,不能使用full join, * 可以出现在inner join的两边 * */ - if (1 == i) { + if ((!reverse_parse && 1 == i) || + (reverse_parse && 2 == i)) { column_namespace_checker_.add_current_joined_table(NULL); } if (OB_FAIL(resolve_table(*table_node, table_item))) { @@ -4697,9 +4707,14 @@ int ObDMLResolver::resolve_joined_table_item(const ParseNode &parse_node, Joined LOG_WARN("check special join table failed", K(ret), K(i)); } else if (1 == i) { cur_table->left_table_ = table_item; - column_namespace_checker_.add_current_joined_table(table_item); + if (!reverse_parse) { + column_namespace_checker_.add_current_joined_table(table_item); + } } else { cur_table->right_table_ = table_item; + if (reverse_parse) { + column_namespace_checker_.add_current_joined_table(table_item); + } } if (OB_SUCC(ret)) { if (OB_FAIL(cur_table->single_table_ids_.push_back(table_item->table_id_))) { @@ -4790,6 +4805,90 @@ int ObDMLResolver::resolve_generate_table(const ParseNode &table_node, return ret; } +int ObDMLResolver::resolve_lateral_generated_table(const ParseNode &table_node, + const ParseNode *alias_node, + TableItem *&table_item) +{ + int ret = OB_SUCCESS; + ObSEArray exec_params; + ObDMLStmt *stmt = get_stmt(); + ObSelectResolver select_resolver(params_); + select_resolver.set_current_level(current_level_ + 1); + select_resolver.set_current_view_level(current_view_level_); + select_resolver.set_parent_namespace_resolver(this); + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (!(GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_4_3_1_0 || + (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_4_2_2_0 && + GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_4_3_0_0))) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "lateral derived table cluster version"); + } else if (stmt->is_select_stmt() || + (is_mysql_mode() && (stmt->is_delete_stmt() || stmt->is_update_stmt()))) { + //resolve with cte table + select_resolver.set_is_sub_stmt(true); + if (OB_FAIL(select_resolver.set_cte_ctx(cte_ctx_, true, true))) { + LOG_WARN("failed to set cte ctx in mysql mode", K(ret)); + } else if (OB_FAIL(add_cte_table_to_children(select_resolver))) { + LOG_WARN("failed to add cte table to children in mysql mode", K(ret)); + } + } else { } + + if (OB_FAIL(ret)) { + } else if (OB_FALSE_IT(set_query_ref_exec_params(&exec_params))) { + } else if (OB_FALSE_IT(params_.is_resolve_lateral_derived_table_ = true)) { + } else if (OB_FAIL(select_resolver.add_parent_gen_col_exprs(gen_col_exprs_))) { + LOG_WARN("failed to add gen col exprs", K(ret)); + } else if (OB_FAIL(do_resolve_generate_table(table_node, alias_node, select_resolver, table_item))) { + LOG_WARN("do resolve generated table failed", K(ret)); + } else if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FALSE_IT(params_.is_resolve_lateral_derived_table_ = false)) { + } else if (OB_FAIL(table_item->exec_params_.assign(exec_params))) { + LOG_WARN("failed to assign exec params", K(ret)); + } else { + set_query_ref_exec_params(NULL); + table_item->type_ = TableItem::LATERAL_TABLE; + } + return ret; +} + +int ObDMLResolver::check_contain_lateral_node(const ParseNode *parse_tree, bool &is_contain) +{ + int ret = OB_SUCCESS; + const ParseNode *table_node = parse_tree; + is_contain = false; + if (OB_ISNULL(parse_tree)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (T_ORG == parse_tree->type_) { + table_node = parse_tree->children_[0]; + } else if (T_ALIAS == parse_tree->type_) { + table_node = parse_tree->children_[0]; + } + if (OB_ISNULL(table_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_node->type_ == T_SELECT) { + is_contain = parse_tree->value_ == 1; + } else if (table_node->type_ == T_JOINED_TABLE) { + if (OB_UNLIKELY(table_node->num_child_ < 3)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(SMART_CALL(check_contain_lateral_node(table_node->children_[1], + is_contain)))) { + LOG_WARN("failed to check contain lateral node", K(ret)); + } else if (!is_contain && + OB_FAIL(SMART_CALL(check_contain_lateral_node(table_node->children_[2], + is_contain)))) { + LOG_WARN("failed to check contain lateral node", K(ret)); + } + } + return ret; +} + int ObDMLResolver::do_resolve_generate_table(const ParseNode &table_node, const ParseNode *alias_node, ObChildStmtResolver &child_resolver, @@ -7175,7 +7274,7 @@ int ObDMLResolver::resolve_subquery_info(const ObIArray &subquer subquery_resolver.set_current_level(current_level_ + 1); subquery_resolver.set_current_view_level(current_view_level_); subquery_resolver.set_parent_namespace_resolver(this); - set_query_ref_expr(info.ref_expr_); + set_query_ref_exec_params(info.ref_expr_ == NULL ? NULL : &info.ref_expr_->get_exec_params()); if (OB_FAIL(add_cte_table_to_children(subquery_resolver))) { LOG_WARN("add CTE table to children failed", K(ret)); } else if (OB_FAIL(subquery_resolver.add_parent_gen_col_exprs(gen_col_exprs_))) { @@ -7188,7 +7287,7 @@ int ObDMLResolver::resolve_subquery_info(const ObIArray &subquer LOG_WARN("do resolve subquery info failed", K(ret)); } } - set_query_ref_expr(NULL); + set_query_ref_exec_params(NULL); } return ret; } @@ -10223,7 +10322,8 @@ int ObDMLResolver::resolve_generated_table_column_item(const TableItem &table_it LOG_WARN("schema checker is null", K(stmt), K_(schema_checker), K_(params_.expr_factory)); } else if (OB_UNLIKELY(!table_item.is_generated_table() && !table_item.is_fake_cte_table() && - !table_item.is_temp_table())) { + !table_item.is_temp_table() && + !table_item.is_lateral_table())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("not generated table", K_(table_item.type)); } @@ -12753,8 +12853,8 @@ int ObDMLResolver::resolve_rowid_pseudo_column( const TableItem *table_item = NULL; ObDMLStmt *cur_stmt = NULL; int32_t cur_level = current_level_; - ObQueryRefRawExpr *query_ref = NULL; - if (OB_FAIL(check_rowid_table_column_in_all_namespace(q_name, table_item, cur_stmt, cur_level, query_ref))) { + ObIArray *query_ref_exec_params = NULL; + if (OB_FAIL(check_rowid_table_column_in_all_namespace(q_name, table_item, cur_stmt, cur_level, query_ref_exec_params))) { LOG_WARN("failed to check rowid table column in all namespace", K(ret)); } else if (OB_ISNULL(table_item) || OB_ISNULL(cur_stmt)) { ret = OB_ERR_BAD_FIELD_ERROR; @@ -12788,11 +12888,11 @@ int ObDMLResolver::resolve_rowid_pseudo_column( if (OB_SUCC(ret)) { if (cur_level != current_level_) { ObRawExpr *exec_param = NULL; - if (OB_ISNULL(query_ref)) { + if (OB_ISNULL(query_ref_exec_params)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("no subquery is found", K(ret), K(query_ref)); + LOG_WARN("no subquery is found", K(ret), K(query_ref_exec_params)); } else if (OB_FAIL(ObRawExprUtils::get_exec_param_expr(*params_.expr_factory_, - query_ref, + query_ref_exec_params, real_ref_expr, exec_param))) { LOG_WARN("failed to get exec param expr", K(ret)); @@ -13112,7 +13212,7 @@ int ObDMLResolver::check_rowid_table_column_in_all_namespace(const ObQualifiedNa const TableItem *&table_item, ObDMLStmt *&dml_stmt, int32_t &cur_level, - ObQueryRefRawExpr *&query_ref) + ObIArray *&query_ref_exec_params) { int ret = OB_SUCCESS; //first check current resolver @@ -13125,19 +13225,19 @@ int ObDMLResolver::check_rowid_table_column_in_all_namespace(const ObQualifiedNa } else if (table_item != NULL) { dml_stmt = get_stmt(); cur_level = current_level_; - query_ref = get_subquery(); + query_ref_exec_params = get_query_ref_exec_params(); } else if (get_stmt()->is_select_stmt()) { //if don't find table item and current resolver is select resolver then try to find table from // parent namespace resolver. if (OB_ISNULL(get_parent_namespace_resolver())) { /*do nothing*/ } else if (OB_FAIL(SMART_CALL(get_parent_namespace_resolver()-> - check_rowid_table_column_in_all_namespace(q_name, table_item, dml_stmt, cur_level, query_ref)))) { + check_rowid_table_column_in_all_namespace(q_name, table_item, dml_stmt, cur_level, query_ref_exec_params)))) { LOG_WARN("failed to check rowid table column in all namespace", K(ret), K(q_name)); } else {/*do nothing*/} } LOG_TRACE("Succeed to check rowid table column in all namespace", K(q_name), KPC(table_item), - KPC(dml_stmt), K(cur_level), KPC(query_ref)); + KPC(dml_stmt), K(cur_level), KPC(query_ref_exec_params)); return ret; } @@ -13786,7 +13886,9 @@ int ObDMLResolver::resolve_transform_hint(const ParseNode &hint_node, case T_AGGR_FIRST_UNNEST: case T_NO_AGGR_FIRST_UNNEST: case T_JOIN_FIRST_UNNEST: - case T_NO_JOIN_FIRST_UNNEST: { + case T_NO_JOIN_FIRST_UNNEST: + case T_DECORRELATE: + case T_NO_DECORRELATE: { if (OB_FAIL(resolve_normal_transform_hint(hint_node, trans_hint))) { LOG_WARN("failed to resolve hint with qb name param.", K(ret)); } diff --git a/src/sql/resolver/dml/ob_dml_resolver.h b/src/sql/resolver/dml/ob_dml_resolver.h index e3d094d258..c36a82b66d 100644 --- a/src/sql/resolver/dml/ob_dml_resolver.h +++ b/src/sql/resolver/dml/ob_dml_resolver.h @@ -304,8 +304,11 @@ public: const ObResolverUtils::PureFunctionCheckStatus check_status); - void set_query_ref_expr(ObQueryRefRawExpr *query_ref) { query_ref_ = query_ref; } - ObQueryRefRawExpr *get_subquery() { return query_ref_; } + void set_query_ref_exec_params(ObIArray *query_ref_exec_params) + { + query_ref_exec_params_ = query_ref_exec_params; + } + ObIArray *get_query_ref_exec_params() { return query_ref_exec_params_; } int build_heap_table_hidden_pk_expr(ObRawExpr *&expr, const ObColumnRefRawExpr *ref_expr); static int copy_schema_expr(ObRawExprFactory &factory, ObRawExpr *expr, @@ -358,6 +361,13 @@ protected: virtual int resolve_generate_table(const ParseNode &table_node, const ParseNode *alias_node, TableItem *&tbl_item); + + int resolve_lateral_generated_table(const ParseNode &table_node, + const ParseNode *alias_node, + TableItem *&tbl_item); + + int check_contain_lateral_node(const ParseNode *parse_tree, bool &is_contain); + int check_stmt_has_flashback_query(ObDMLStmt *stmt, bool check_all, bool &has_fq); virtual int resolve_basic_table(const ParseNode &parse_tree, TableItem *&table_item); int resolve_flashback_query_node(const ParseNode *time_node, TableItem *table_item); @@ -807,7 +817,7 @@ protected: const TableItem *&table_item, ObDMLStmt *&dml_stmt, int32_t &cur_level, - ObQueryRefRawExpr *&query_ref); + ObIArray *&query_ref_exec_params); int get_view_id_for_trigger(const TableItem &view_item, uint64_t &view_id); bool get_joininfo_by_id(int64_t table_id, ResolverJoinInfo *&join_info); int get_json_table_column_by_id(uint64_t table_id, ObDmlJtColDef *&col_def); @@ -1002,7 +1012,7 @@ protected: common::ObArray gen_col_exprs_; common::ObArray from_items_order_; - ObQueryRefRawExpr *query_ref_; + ObIArray *query_ref_exec_params_; // for oracle style outer join bool has_ansi_join_; diff --git a/src/sql/resolver/dml/ob_dml_stmt.cpp b/src/sql/resolver/dml/ob_dml_stmt.cpp index b72e0cabdf..2f777dcda4 100644 --- a/src/sql/resolver/dml/ob_dml_stmt.cpp +++ b/src/sql/resolver/dml/ob_dml_stmt.cpp @@ -284,6 +284,23 @@ int TableItem::deep_copy(ObIRawExprCopier &expr_copier, LOG_WARN("failed to assign part names", K(ret)); } else if (OB_FAIL(expr_copier.copy(other.table_values_, table_values_))) { LOG_WARN("failed to deep copy table values", K(ret)); + } else { + exec_params_.reuse(); + for (int64_t i = 0; OB_SUCC(ret) && i < other.exec_params_.count(); ++i) { + ObRawExpr *exec_param = other.exec_params_.at(i); + ObRawExpr *new_expr = NULL; + if (OB_FAIL(expr_copier.do_copy_expr(exec_param, new_expr))) { + LOG_WARN("failed to copy exec param", K(ret)); + } else if (OB_ISNULL(new_expr) || + OB_UNLIKELY(!new_expr->is_exec_param_expr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec param is invalid", K(ret), K(new_expr)); + } else if (OB_FAIL(expr_copier.copy(static_cast(new_expr)->get_ref_expr()))) { + LOG_WARN("failed to copy expr", K(ret)); + } else if (OB_FAIL(exec_params_.push_back(static_cast(new_expr)))) { + LOG_WARN("failed to push back exec params", K(ret)); + } + } } return ret; } @@ -856,9 +873,20 @@ int ObDMLStmt::iterate_stmt_expr(ObStmtExprVisitor &visitor) OB_FAIL(visitor.visit(table_items_.at(i)->json_table_def_->doc_expr_, SCOPE_FROM))) { LOG_WARN("failed to add json table doc expr", K(ret)); - } else if (OB_FAIL(visitor.visit(table_items_.at(i)->table_values_, - SCOPE_FROM))) { + } else if (OB_FAIL(visitor.visit(table_items_.at(i)->table_values_, + SCOPE_FROM))) { LOG_WARN("failed to visit table values", K(ret)); + } else if (table_items_.at(i)->is_lateral_table()) { + TableItem *table_item = table_items_.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < table_item->exec_params_.count(); ++j) { + if (OB_ISNULL(table_item->exec_params_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(visitor.visit(table_item->exec_params_.at(j)->get_ref_expr(), + SCOPE_FROM))) { + LOG_WARN("failed to add lateral ref expr", K(ret)); + } + } } else { /*do nothing*/ } } @@ -1075,6 +1103,13 @@ int ObDMLStmt::update_stmt_table_id(ObIAllocator *allocator, const ObDMLStmt &ot OB_FAIL(table_items_.at(i)->ref_query_->update_stmt_table_id(allocator, *other.table_items_.at(i)->ref_query_))) { LOG_WARN("failed to update table id for generated table", K(ret)); + } else if (table_items_.at(i)->is_lateral_table() && + other.table_items_.at(i)->is_lateral_table() && + NULL != table_items_.at(i)->ref_query_ && + NULL != other.table_items_.at(i)->ref_query_ && + OB_FAIL(table_items_.at(i)->ref_query_->update_stmt_table_id(allocator, + *other.table_items_.at(i)->ref_query_))) { + LOG_WARN("failed to update table id for generated table", K(ret)); } else { /*do nothing*/ } } //recursively update table id for subquery exprs @@ -2199,7 +2234,8 @@ int ObDMLStmt::get_from_subquery_stmts(ObIArray &child_stmts) con if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_item is null", K(i)); - } else if (table_item->is_generated_table()) {// to remove temp table + } else if (table_item->is_generated_table() || + table_item->is_lateral_table()) {// to remove temp table if (OB_FAIL(child_stmts.push_back(table_item->ref_query_))) { LOG_WARN("adjust parent namespace stmt failed", K(ret)); } @@ -3238,7 +3274,8 @@ int ObDMLStmt::get_child_stmts(ObIArray &child_stmts) const if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_item is null", K(i)); - } else if (table_item->is_generated_table()) { + } else if (table_item->is_generated_table() || + table_item->is_lateral_table()) { if (OB_FAIL(child_stmts.push_back(table_item->ref_query_))) { LOG_WARN("store child stmt failed", K(ret)); } @@ -3278,7 +3315,8 @@ int ObDMLStmt::set_child_stmt(const int64_t child_num, ObSelectStmt* child_stmt) if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_item is null", K(i)); - } else if (table_item->is_generated_table()) { + } else if (table_item->is_generated_table() || + table_item->is_lateral_table()) { if (child_num == pos) { is_find = true; table_item->ref_query_ = child_stmt; @@ -3320,7 +3358,9 @@ bool ObDMLStmt::has_link_table() const bool bret = false; for (int i = 0; !bret && i < table_items_.count(); i++) { if (OB_NOT_NULL(table_items_.at(i))) { - if (table_items_.at(i)->is_generated_table() || table_items_.at(i)->is_temp_table()) { + if (table_items_.at(i)->is_generated_table() || + table_items_.at(i)->is_temp_table() || + table_items_.at(i)->is_lateral_table()) { if (OB_NOT_NULL(table_items_.at(i)->ref_query_)) { bret = table_items_.at(i)->ref_query_->has_link_table(); } @@ -4644,7 +4684,6 @@ int ObDMLStmt::do_formalize_query_ref_exprs_pre() LOG_WARN("unexpected null", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < ref_query->get_exec_params().count(); ++i) { - bool is_happened = false; int64_t idx = -1; if (OB_ISNULL(exec_param = ref_query->get_exec_param(i))) { ret = OB_ERR_UNEXPECTED; @@ -4706,7 +4745,6 @@ int ObDMLStmt::formalize_query_ref_exec_params(ObStmtExecParamFormatter &formatt bool need_replace) { int ret = OB_SUCCESS; - ObQueryRefRawExpr *ref_query = NULL; ObSEArray subquerys; if (need_replace && OB_FAIL(iterate_stmt_expr(formatter))) { LOG_WARN("failed to iterate stmt expr"); @@ -4714,6 +4752,8 @@ int ObDMLStmt::formalize_query_ref_exec_params(ObStmtExecParamFormatter &formatt LOG_WARN("failed to get child stmts", K(ret)); } else if (OB_FAIL(do_formalize_query_ref_exprs_pre())) { LOG_WARN("failed to do formalize query ref exprs pre", K(ret)); + } else if (OB_FAIL(do_formalize_lateral_derived_table_pre())) { + LOG_WARN("failed to do formalize lateral derived table pre", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < subquerys.count(); ++i) { if (OB_ISNULL(subquerys.at(i))) { @@ -4723,8 +4763,12 @@ int ObDMLStmt::formalize_query_ref_exec_params(ObStmtExecParamFormatter &formatt LOG_WARN("failed to formalize subquery exec params", K(ret)); } } - if (OB_SUCC(ret) && OB_FAIL(do_formalize_query_ref_exprs_post())) { - LOG_WARN("failed to do formalize query ref exprs post", K(ret)); + if (OB_SUCC(ret)) { + if (OB_FAIL(do_formalize_query_ref_exprs_post())) { + LOG_WARN("failed to do formalize query ref exprs post", K(ret)); + } else if (OB_FAIL(do_formalize_lateral_derived_table_post())) { + LOG_WARN("failed to do formalize lateral derived table post", K(ret)); + } } return ret; } @@ -4753,6 +4797,71 @@ bool ObDMLStmt::is_values_table_query() const table_items_.at(0)->is_values_table(); } +int ObDMLStmt::do_formalize_lateral_derived_table_pre() +{ + int ret = OB_SUCCESS; + ObExecParamRawExpr *exec_param = NULL; + ObSEArray ref_exprs; + ObSEArray ref_exec_idxs; + for (int64_t j = 0; OB_SUCC(ret) && j < table_items_.count(); ++j) { + TableItem *table_item = NULL; + ref_exprs.reuse(); + ref_exec_idxs.reuse(); + if (OB_ISNULL(table_item = table_items_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < table_item->exec_params_.count(); ++i) { + int64_t idx = -1; + if (OB_ISNULL(exec_param = table_item->exec_params_.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FALSE_IT(exec_param->clear_explicited_referece())) { + } else if (ObOptimizerUtil::find_item(ref_exprs, + exec_param->get_ref_expr(), + &idx)) { + exec_param->set_ref_expr(table_item->exec_params_.at(ref_exec_idxs.at(idx))); + } else if (OB_FAIL(ref_exprs.push_back(exec_param->get_ref_expr()))) { + LOG_WARN("failed to push back ref exprs"); + } else if (OB_FAIL(ref_exec_idxs.push_back(i))) { + LOG_WARN("failed to push back ref exec idxs", K(ret)); + } + } + } + return ret; +} + +int ObDMLStmt::do_formalize_lateral_derived_table_post() +{ + int ret = OB_SUCCESS; + ObRawExpr *exec_param = NULL; + TableItem *table_item = NULL; + for (int64_t j = 0; OB_SUCC(ret) && j < table_items_.count(); ++j) { + if (OB_ISNULL(table_item = table_items_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } + for (int64_t i = table_item->exec_params_.count() - 1; OB_SUCC(ret) && i >= 0; --i) { + int64_t idx = -1; + if (OB_ISNULL(exec_param = table_item->exec_params_.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (exec_param->is_explicited_reference()) { + // do nothing + } else if (OB_FAIL(table_item->exec_params_.remove(i))) { + LOG_WARN("failed to remove exec param", K(ret)); + } else { + LOG_TRACE("succeed to remove exec param expr", K(*exec_param)); + } + } + if (OB_SUCC(ret) && table_item->is_lateral_table() && + table_item->exec_params_.empty()) { + table_item->type_ = TableItem::GENERATED_TABLE; + } + } + return ret; +} + ObJtColBaseInfo::ObJtColBaseInfo() : col_type_(0), truncate_(0), diff --git a/src/sql/resolver/dml/ob_dml_stmt.h b/src/sql/resolver/dml/ob_dml_stmt.h index 2a8efcff5f..e5da5c402e 100644 --- a/src/sql/resolver/dml/ob_dml_stmt.h +++ b/src/sql/resolver/dml/ob_dml_stmt.h @@ -205,7 +205,8 @@ struct TableItem K_(is_view_table), K_(part_ids), K_(part_names), K_(cte_type), KPC_(function_table_expr), K_(flashback_query_type), KPC_(flashback_query_expr), K_(table_type), - K(table_values_)); + K(table_values_), + K_(exec_params)); enum TableType { @@ -220,7 +221,8 @@ struct TableItem LINK_TABLE, JSON_TABLE, EXTERNAL_TABLE, - VALUES_TABLE + VALUES_TABLE, + LATERAL_TABLE, }; /** @@ -257,6 +259,8 @@ struct TableItem bool is_link_type() const { return LINK_TABLE == type_; } // after dblink transformer, LINK_TABLE will be BASE_TABLE, BASE_TABLE will be LINK_TABLE bool is_json_table() const { return JSON_TABLE == type_; } bool is_values_table() const { return VALUES_TABLE == type_; }//used to mark values statement: values row(1,2), row(3,4); + + bool is_lateral_table() const { return LATERAL_TABLE == type_; } bool is_synonym() const { return !synonym_name_.empty(); } bool is_oracle_all_or_user_sys_view() const { @@ -338,6 +342,7 @@ struct TableItem // table partition common::ObSEArray part_ids_; common::ObSEArray part_names_; + common::ObSEArray exec_params_; // json table ObJsonTableDef* json_table_def_; // values table @@ -1164,6 +1169,10 @@ public: int do_formalize_query_ref_exprs_post(); + int do_formalize_lateral_derived_table_pre(); + + int do_formalize_lateral_derived_table_post(); + protected: int create_table_item(TableItem *&table_item); //获取到stmt中所有查询相关的表达式(由查询语句中指定的属性生成的表达式)的root expr diff --git a/src/sql/resolver/dml/ob_hint.cpp b/src/sql/resolver/dml/ob_hint.cpp index 082dd1026e..e669db5ea0 100644 --- a/src/sql/resolver/dml/ob_hint.cpp +++ b/src/sql/resolver/dml/ob_hint.cpp @@ -972,6 +972,7 @@ ObItemType ObHint::get_hint_type(ObItemType type) case T_NO_PULLUP_EXPR : return T_PULLUP_EXPR; case T_NO_AGGR_FIRST_UNNEST: return T_AGGR_FIRST_UNNEST; case T_NO_JOIN_FIRST_UNNEST: return T_JOIN_FIRST_UNNEST; + case T_NO_DECORRELATE : return T_DECORRELATE; // optimize hint case T_NO_USE_DAS_HINT: return T_USE_DAS_HINT; @@ -1028,6 +1029,7 @@ const char* ObHint::get_hint_name(ObItemType type, bool is_enable_hint /* defaul case T_PULLUP_EXPR : return is_enable_hint ? "PULLUP_EXPR" : "NO_PULLUP_EXPR"; case T_AGGR_FIRST_UNNEST: return is_enable_hint ? "AGGR_FIRST_UNNEST" : "NO_AGGR_FIRST_UNNEST"; case T_JOIN_FIRST_UNNEST: return is_enable_hint ? "JOIN_FIRST_UNNEST" : "NO_JOIN_FIRST_UNNEST"; + case T_DECORRELATE : return is_enable_hint ? "DECORRELATE" : "NO_DECORRELATE"; // optimize hint case T_INDEX_HINT: return "INDEX"; case T_FULL_HINT: return "FULL"; diff --git a/src/sql/resolver/dml/ob_hint.h b/src/sql/resolver/dml/ob_hint.h index b5710db27f..20ade5672b 100644 --- a/src/sql/resolver/dml/ob_hint.h +++ b/src/sql/resolver/dml/ob_hint.h @@ -521,6 +521,7 @@ public: bool is_project_prune_hint() const { return T_PROJECT_PRUNE == hint_type_; } bool is_table_dynamic_sampling_hint() const { return T_TABLE_DYNAMIC_SAMPLING == hint_type_; } bool is_pq_subquery_hint() const { return T_PQ_SUBQUERY == hint_type_; } + bool is_decorrelate_hint() const { return T_DECORRELATE == hint_type_; } VIRTUAL_TO_STRING_KV("hint_type", get_type_name(hint_type_), K_(hint_class), K_(qb_name), diff --git a/src/sql/resolver/dml/ob_select_resolver.cpp b/src/sql/resolver/dml/ob_select_resolver.cpp index 3858504ca6..3c99835fd3 100644 --- a/src/sql/resolver/dml/ob_select_resolver.cpp +++ b/src/sql/resolver/dml/ob_select_resolver.cpp @@ -2319,7 +2319,9 @@ int ObSelectResolver::expand_target_list( if (OB_FAIL(resolve_all_basic_table_columns(table_item, false, &column_items))) { LOG_WARN("resolve all basic table columns failed", K(ret), K(table_item)); } - } else if (table_item.is_generated_table() || table_item.is_temp_table()) { + } else if (table_item.is_generated_table() || + table_item.is_temp_table() || + table_item.is_lateral_table()) { if (OB_FAIL(resolve_all_generated_table_columns(table_item, &column_items))) { LOG_WARN("resolve all generated table columns failed", K(ret)); } @@ -4936,6 +4938,7 @@ int ObSelectResolver::resolve_column_ref_in_all_namespace( OB_ERR_BAD_FIELD_ERROR == ret && cur_resolver != NULL; cur_resolver = cur_resolver->get_parent_namespace_resolver()) { ObRawExpr *exec_param = NULL; + ObIArray *query_ref_exec_params = NULL; //for insert into t1 values((select c1 from dual)) ==> can't check column c1 in t1; if (cur_resolver->get_basic_stmt() != NULL && cur_resolver->get_basic_stmt()->is_insert_stmt()) { @@ -4951,11 +4954,11 @@ int ObSelectResolver::resolve_column_ref_in_all_namespace( } if (OB_FAIL(ret)) { //do nothing - } else if (OB_ISNULL(query_ref = cur_resolver->get_subquery())) { + } else if (OB_ISNULL(query_ref_exec_params = cur_resolver->get_query_ref_exec_params())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("no subquery is found", K(ret)); } else if (OB_FAIL(ObRawExprUtils::get_exec_param_expr(*params_.expr_factory_, - query_ref, + query_ref_exec_params, real_ref_expr, exec_param))) { LOG_WARN("failed to get exec param expr", K(ret)); @@ -5432,7 +5435,7 @@ int ObSelectResolver::resolve_subquery_info(const ObIArray &subq subquery_resolver.set_is_sub_stmt(true); subquery_resolver.set_parent_namespace_resolver(this); subquery_resolver.set_current_view_level(current_view_level_); - set_query_ref_expr(info.ref_expr_); + set_query_ref_exec_params(info.ref_expr_ == NULL ? NULL : &info.ref_expr_->get_exec_params()); resolve_alias_for_subquery_ = !(T_FIELD_LIST_SCOPE == current_scope_ && info.parents_expr_info_.has_member(IS_AGG)); if (OB_FAIL(subquery_resolver.add_parent_gen_col_exprs(gen_col_exprs_))) { @@ -5446,7 +5449,7 @@ int ObSelectResolver::resolve_subquery_info(const ObIArray &subq subquery_resolver.set_parent_aggr_level(parent_aggr_level_); } OZ ( do_resolve_subquery_info(info, subquery_resolver) ); - set_query_ref_expr(NULL); + set_query_ref_exec_params(NULL); } return ret; } diff --git a/src/sql/resolver/dml/ob_sql_hint.cpp b/src/sql/resolver/dml/ob_sql_hint.cpp index 38a03c041b..ee5d36b772 100644 --- a/src/sql/resolver/dml/ob_sql_hint.cpp +++ b/src/sql/resolver/dml/ob_sql_hint.cpp @@ -1270,7 +1270,7 @@ int ObStmtHint::replace_name_for_single_table_view(ObIAllocator *allocator, const ObDMLStmt *child_stmt = NULL; if (OB_ISNULL(query_hint_) || OB_ISNULL(stmt.get_table_item_by_id(view_table.table_id_)) - || OB_UNLIKELY(!view_table.is_generated_table()) + || OB_UNLIKELY(!view_table.is_generated_table() && !view_table.is_lateral_table()) || OB_ISNULL(child_stmt = view_table.ref_query_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected params", K(ret), K(query_hint_), K(target_table), K(child_stmt)); diff --git a/src/sql/resolver/dml/ob_view_table_resolver.cpp b/src/sql/resolver/dml/ob_view_table_resolver.cpp index 0036e16561..77e5517e37 100644 --- a/src/sql/resolver/dml/ob_view_table_resolver.cpp +++ b/src/sql/resolver/dml/ob_view_table_resolver.cpp @@ -223,7 +223,7 @@ int ObViewTableResolver::resolve_subquery_info(const ObIArray &s subquery_resolver.set_parent_namespace_resolver(this); subquery_resolver.set_parent_view_resolver(parent_view_resolver_); subquery_resolver.set_current_view_item(current_view_item); - set_query_ref_expr(info.ref_expr_); + set_query_ref_exec_params(info.ref_expr_ == NULL ? NULL : &info.ref_expr_->get_exec_params()); if (OB_FAIL(add_cte_table_to_children(subquery_resolver))) { LOG_WARN("add CTE table to children failed", K(ret)); } else if (is_only_full_group_by_on(session_info_->get_sql_mode())) { @@ -233,7 +233,7 @@ int ObViewTableResolver::resolve_subquery_info(const ObIArray &s if (OB_FAIL(do_resolve_subquery_info(info, subquery_resolver))) { LOG_WARN("do resolve subquery info failed", K(ret)); } - set_query_ref_expr(NULL); + set_query_ref_exec_params(NULL); } return ret; } diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index eac4168020..6f96035857 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -4706,6 +4706,7 @@ int ObRawExprUtils::get_exec_param_expr(ObRawExprFactory &expr_factory, ObRawExpr *¶m_expr) { int ret = OB_SUCCESS; + param_expr = NULL; if (OB_ISNULL(query_ref) || OB_ISNULL(outer_val_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid params", K(ret), K(query_ref), K(outer_val_expr)); @@ -4770,6 +4771,53 @@ int ObRawExprUtils::create_new_exec_param(ObRawExprFactory &expr_factory, return ret; } +int ObRawExprUtils::get_exec_param_expr(ObRawExprFactory &expr_factory, + ObIArray *query_ref_exec_params, + ObRawExpr *outer_val_expr, + ObRawExpr *¶m_expr) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(outer_val_expr) || OB_ISNULL(query_ref_exec_params)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid params", K(ret), K(outer_val_expr)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < query_ref_exec_params->count(); ++i) { + ObExecParamRawExpr *param = NULL; + if (OB_ISNULL(param = query_ref_exec_params->at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("param expr is null", K(ret), K(i)); + } else if (param->get_ref_expr() == outer_val_expr) { + param_expr = param; + break; + } + } + // the exec param is not found in the query ref, + // we create a new one here + if (OB_SUCC(ret) && NULL == param_expr) { + ObExecParamRawExpr *exec_param = NULL; + if (OB_FAIL(expr_factory.create_raw_expr(T_QUESTIONMARK, exec_param))) { + LOG_WARN("failed to create raw expr", K(ret)); + } else if (OB_ISNULL(exec_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec param is null", K(ret), K(exec_param)); + } else if (OB_FAIL(query_ref_exec_params->push_back(exec_param))) { + LOG_WARN("failed to add exec param expr", K(ret)); + } else if (OB_FAIL(exec_param->set_enum_set_values(outer_val_expr->get_enum_set_values()))) { + LOG_WARN("failed to set enum set values", K(ret)); + } else if (OB_FAIL(exec_param->add_flag(IS_CONST))) { + LOG_WARN("failed to add flag", K(ret)); + } else if (OB_FAIL(exec_param->add_flag(IS_DYNAMIC_PARAM))) { + LOG_WARN("failed to add flag", K(ret)); + } else { + exec_param->set_ref_expr(outer_val_expr); + exec_param->set_param_index(-1); + exec_param->set_result_type(outer_val_expr->get_result_type()); + param_expr = exec_param; + } + } + return ret; +} + int ObRawExprUtils::create_new_exec_param(ObQueryCtx *query_ctx, ObRawExprFactory &expr_factory, ObRawExpr *&expr, diff --git a/src/sql/resolver/expr/ob_raw_expr_util.h b/src/sql/resolver/expr/ob_raw_expr_util.h index 90a43b9d3a..a22efb470e 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.h +++ b/src/sql/resolver/expr/ob_raw_expr_util.h @@ -555,6 +555,10 @@ public: ObRawExpr *correlated_expr, ObRawExpr *&exec_param); + static int get_exec_param_expr(ObRawExprFactory &expr_factory, + ObIArray *query_ref_exec_params, + ObRawExpr *correlated_expr, + ObRawExpr *&exec_param); static int create_new_exec_param(ObQueryCtx *query_ctx, ObRawExprFactory &expr_factory, ObRawExpr *&expr, diff --git a/src/sql/resolver/ob_resolver_define.h b/src/sql/resolver/ob_resolver_define.h index a28b75b820..15ddfd8a03 100644 --- a/src/sql/resolver/ob_resolver_define.h +++ b/src/sql/resolver/ob_resolver_define.h @@ -352,6 +352,7 @@ struct ObResolverParams is_specified_col_name_(false), is_in_sys_view_(false), is_expanding_view_(false), + is_resolve_lateral_derived_table_(false), package_guard_(NULL) {} bool is_force_trace_log() { return force_trace_log_; } @@ -421,6 +422,7 @@ public: bool is_specified_col_name_;//mark if specify the column name in create view or create table as.. bool is_in_sys_view_; bool is_expanding_view_; + bool is_resolve_lateral_derived_table_; // used to mark resolve lateral derived table. pl::ObPLPackageGuard *package_guard_; }; } // end namespace sql diff --git a/src/sql/rewrite/ob_stmt_comparer.cpp b/src/sql/rewrite/ob_stmt_comparer.cpp index 427fbd4a19..31d6ef0e0c 100644 --- a/src/sql/rewrite/ob_stmt_comparer.cpp +++ b/src/sql/rewrite/ob_stmt_comparer.cpp @@ -1231,8 +1231,10 @@ int ObStmtComparer::compare_table_item(const ObDMLStmt *first, } } //TODO:jiangxiu.wt 后续打开flashback query针对view和generated table的支持,这里需要处理 - } else if (first_table->is_generated_table() && - second_table->is_generated_table()) { + } else if ((first_table->is_generated_table() && + second_table->is_generated_table()) || + (first_table->is_lateral_table() && + second_table->is_lateral_table())) { ObStmtMapInfo ref_query_map_info; const int32_t first_table_index = first->get_table_bit_index(first_table->table_id_); const int32_t second_table_index = second->get_table_bit_index(second_table->table_id_); diff --git a/src/sql/rewrite/ob_transform_aggr_subquery.cpp b/src/sql/rewrite/ob_transform_aggr_subquery.cpp index a98e3036c5..4cfd80fbbb 100644 --- a/src/sql/rewrite/ob_transform_aggr_subquery.cpp +++ b/src/sql/rewrite/ob_transform_aggr_subquery.cpp @@ -493,7 +493,7 @@ int ObTransformAggrSubquery::check_aggr_first_validity(ObQueryRefRawExpr &query_ LOG_TRACE("select list is invalid", K(is_valid)); OPT_TRACE("subquery select item contain subquery"); // 3. check from list is not correlated - } else if (OB_FAIL(ObTransformUtils::is_table_item_correlated(query_ref, + } else if (OB_FAIL(ObTransformUtils::is_table_item_correlated(query_ref.get_exec_params(), *subquery, is_correlated))) { LOG_WARN("failed to check table item correlated or not", K(ret)); @@ -502,7 +502,7 @@ int ObTransformAggrSubquery::check_aggr_first_validity(ObQueryRefRawExpr &query_ OPT_TRACE("subquery`s table item is correlated"); // 4. check correlated join on contiditons // 5. check correlated semi contiditons - } else if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(query_ref, + } else if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(query_ref.get_exec_params(), subquery, is_correlated))) { LOG_WARN("failed to check is join condition correlated", K(ret)); @@ -660,7 +660,7 @@ int ObTransformAggrSubquery::check_join_first_condition_for_limit_1(ObQueryRefRa LOG_WARN("condition expr is null", K(ret)); } else if (has_equal_correlation) { // do nothing - } else if (OB_FAIL(ObTransformUtils::is_equal_correlation(query_ref, + } else if (OB_FAIL(ObTransformUtils::is_equal_correlation(query_ref.get_exec_params(), cond, is_eq_correlation))) { LOG_WARN("failed to check is equal correlation", K(ret)); @@ -739,7 +739,7 @@ int ObTransformAggrSubquery::check_subquery_conditions(ObQueryRefRawExpr &query_ } else if (!cond->has_flag(CNT_COLUMN) || cond->has_flag(CNT_SUB_QUERY)) { is_valid = false; OPT_TRACE("subquery`s condition has subquery"); - } else if (OB_FAIL(ObTransformUtils::is_equal_correlation(query_ref, + } else if (OB_FAIL(ObTransformUtils::is_equal_correlation(query_ref.get_exec_params(), cond, is_valid, &outer_expr, @@ -811,7 +811,7 @@ int ObTransformAggrSubquery::choose_pullup_method(ObIArray &filters } else if (OB_ISNULL(expr = subquery->get_select_item(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select expr is null", K(ret), K(expr)); - } else if (OB_FAIL(extract_nullable_exprs(expr, vars))) { + } else if (OB_FAIL(ObTransformUtils::extract_nullable_exprs(expr, vars))) { LOG_WARN("failed to extract nullable exprs", K(ret)); } else if (vars.count() <= 0) { // do nothing @@ -965,7 +965,12 @@ int ObTransformAggrSubquery::transform_upper_stmt(ObDMLStmt &stmt, TransformPara if (OB_SUCC(ret)) { // 2. 推导原始的子查询计算结果 - if (OB_FAIL(deduce_query_values(stmt, param, select_exprs, view_columns, real_values))) { + if (OB_FAIL(ObTransformUtils::deduce_query_values(*ctx_, + stmt, + param.is_null_prop_, + param.not_null_expr_, + use_outer_join(param.pullup_flag_), + select_exprs, view_columns, real_values))) { LOG_WARN("failed to deduce subquery output", K(ret)); } else if (OB_FAIL(stmt.replace_relation_exprs(param.query_refs_, real_values))) { LOG_WARN("failed to replace inner stmt expr", K(ret)); @@ -984,117 +989,6 @@ int ObTransformAggrSubquery::transform_upper_stmt(ObDMLStmt &stmt, TransformPara return ret; } -class ReplaceColumnsAndAggrs : public ObIRawExprReplacer -{ -public: - int generate_new_expr(ObRawExprFactory &expr_factory, - ObRawExpr *old_expr, - ObRawExpr *&new_expr) - { - int ret = OB_SUCCESS; - if (OB_ISNULL(old_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("expr is null", K(ret), K(old_expr)); - } else if (old_expr->get_expr_type() == T_FUN_COUNT) { - ObConstRawExpr *const_zero = NULL; - if (OB_FAIL(ObTransformUtils::build_const_expr_for_count(expr_factory, 0, const_zero))) { - LOG_WARN("failed to replace count with 0", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(&expr_factory, - session_, - *const_zero, - old_expr->get_result_type(), - new_expr))) { - LOG_WARN("failed to add cast expr above", K(ret)); - } - } else if (old_expr->is_column_ref_expr() || old_expr->is_aggr_expr()) { - // replace with NULL - ObRawExpr *null_expr = NULL; - if (OB_FAIL(ObRawExprUtils::build_null_expr(expr_factory, null_expr))) { - LOG_WARN("failed to replace variable with null", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(&expr_factory, - session_, - *null_expr, - old_expr->get_result_type(), - new_expr))) { - LOG_WARN("failed to add cast expr above", K(ret)); - } - } else if (old_expr->is_const_or_param_expr()) { - if (OB_FAIL(expr_factory.create_raw_expr(old_expr->get_expr_class(), - old_expr->get_expr_type(), - new_expr))) { - LOG_WARN("failed to create raw expr", K(ret)); - } else if (OB_FAIL(new_expr->assign(*old_expr))) { - LOG_WARN("failed to assign old expr", K(ret)); - } - } - return ret; - } - - ObSQLSessionInfo *session_; -}; - -int ObTransformAggrSubquery::deduce_query_values(ObDMLStmt &stmt, - TransformParam ¶m, - ObIArray &view_select, - ObIArray &view_columns, - ObIArray &real_values) -{ - int ret = OB_SUCCESS; - ObRawExpr *not_null_expr = param.not_null_expr_; - ObIArray &is_null_prop = param.is_null_prop_; - const bool is_outer_join = use_outer_join(param.pullup_flag_); - if (OB_ISNULL(ctx_) || - OB_ISNULL(ctx_->session_info_) || - OB_ISNULL(ctx_->expr_factory_) || - OB_UNLIKELY(is_null_prop.count() > view_select.count()) || - OB_UNLIKELY(is_null_prop.count() > view_columns.count())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid session or invalid array size", K(ret)); - } else { - ObRawExprCopier copier(*ctx_->expr_factory_); - ReplaceColumnsAndAggrs replacer; - replacer.session_ = ctx_->session_info_; - for (int64_t i = 0; OB_SUCC(ret) && i < is_null_prop.count(); ++i) { - // replace_columns_and_aggrs() may change expr result type, e.g.: sum() from ObNumberType - // to ObNullType. This may cause operand implicit cast be added twice, so we erase it first. - ObRawExpr *default_expr = NULL; - ObRawExpr *case_when_expr = NULL; - if (OB_FAIL(real_values.push_back(view_columns.at(i)))) { - LOG_WARN("failed to push back view columns", K(ret)); - } else if (is_null_prop.at(i) || !is_outer_join) { - continue; - } else if (OB_ISNULL(not_null_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("not null expr is null", K(ret)); - } else if (OB_FAIL(copier.copy_on_replace(view_select.at(i), - default_expr, - &replacer))) { - LOG_WARN("failed to generate default expr", K(ret)); - // link.zt, shall we add a cast here - } else if (OB_FAIL(default_expr->formalize(ctx_->session_info_))) { - LOG_WARN("failed to formalize default expr", K(ret)); - } else if (OB_FAIL(ObTransformUtils::build_case_when_expr(stmt, - not_null_expr, - view_columns.at(i), - default_expr, - case_when_expr, - ctx_))) { - LOG_WARN("failed to build case when expr", K(ret)); - } else if (OB_ISNULL(case_when_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("case when expr is null", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(ctx_->expr_factory_, - ctx_->session_info_, - *case_when_expr, - view_columns.at(i)->get_result_type(), - real_values.at(i)))) { - LOG_WARN("failed to add cast expr", K(ret)); - } - } - } - return ret; -} - int ObTransformAggrSubquery::transform_from_list(ObDMLStmt &stmt, TableItem *view_table_item, const ObIArray &joined_conds, @@ -1132,28 +1026,6 @@ int ObTransformAggrSubquery::transform_from_list(ObDMLStmt &stmt, return ret; } -int ObTransformAggrSubquery::extract_nullable_exprs( - const ObRawExpr *expr, ObIArray &vars) -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("expr is null", K(ret)); - } else if (expr->is_column_ref_expr() || - (expr->is_aggr_expr() && expr->get_expr_type() != T_FUN_COUNT)) { - if (OB_FAIL(vars.push_back(expr))) { - LOG_WARN("failed to push back expr", K(ret)); - } - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { - if (OB_FAIL(SMART_CALL(extract_nullable_exprs(expr->get_param_expr(i), vars)))) { - LOG_WARN("failed to extract nullable expr", K(ret)); - } - } - } - return ret; -} - /** * @brief ObTransformAggrSubquery::do_join_first_transform * STEP 1: 找到一个可改写的子查询 (同时确定改写的策略 INNER JON/ OUTER JOIN) @@ -1529,14 +1401,16 @@ int ObTransformAggrSubquery::check_join_first_validity(ObQueryRefRawExpr &query_ // never reach // 3. check from list is not correlated } else if (OB_FAIL(ObTransformUtils::is_table_item_correlated( - query_ref, *subquery, is_correlated))) { + query_ref.get_exec_params(), *subquery, is_correlated))) { LOG_WARN("failed to check subquery table item is correlated", K(ret)); } else if (is_correlated) { is_valid = false; OPT_TRACE("subquery`s table item is correlated"); // 4. check correlated join on contiditons // 5. check correlated semi contiditons - } else if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(query_ref, subquery, is_correlated))) { + } else if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(query_ref.get_exec_params(), + subquery, + is_correlated))) { LOG_WARN("failed to check join condition correlated", K(ret)); } else if (is_correlated) { is_valid = false; @@ -1676,7 +1550,7 @@ int ObTransformAggrSubquery::choose_pullup_method_for_exists(ObQueryRefRawExpr * } else if (!(IS_COMMON_COMPARISON_OP(cur_expr->get_expr_type()) && T_OP_NSEQ != cur_expr->get_expr_type())) { is_valid = false; - } else if (OB_FAIL(extract_nullable_exprs(cur_expr, vars))) { + } else if (OB_FAIL(ObTransformUtils::extract_nullable_exprs(cur_expr, vars))) { LOG_WARN("failed to extract nullable exprs", K(ret)); } else if (vars.count() <= 0) { // do nothing diff --git a/src/sql/rewrite/ob_transform_aggr_subquery.h b/src/sql/rewrite/ob_transform_aggr_subquery.h index f13f15ccef..b75dc7443b 100644 --- a/src/sql/rewrite/ob_transform_aggr_subquery.h +++ b/src/sql/rewrite/ob_transform_aggr_subquery.h @@ -139,12 +139,6 @@ private: ObSelectStmt &subquery, TransformParam ¶m); - int deduce_query_values(ObDMLStmt &stmt, - TransformParam ¶m, - ObIArray &select_exprs, - ObIArray &view_columns, - ObIArray &real_values); - int transform_upper_stmt(ObDMLStmt &stmt, TransformParam ¶m); int transform_from_list(ObDMLStmt &stmt, @@ -152,9 +146,6 @@ private: const ObIArray &joined_conds, const int64_t pullup_flag); - int extract_nullable_exprs(const ObRawExpr *expr, - ObIArray &vars); - inline bool use_outer_join(int64_t flag) { return 0 != (flag & USE_OUTER_JOIN); } diff --git a/src/sql/rewrite/ob_transform_decorrelate.cpp b/src/sql/rewrite/ob_transform_decorrelate.cpp new file mode 100644 index 0000000000..4b5dba53ee --- /dev/null +++ b/src/sql/rewrite/ob_transform_decorrelate.cpp @@ -0,0 +1,1050 @@ +/** + * 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_transform_decorrelate.h" +#include "sql/rewrite/ob_transform_utils.h" +#include "sql/resolver/expr/ob_raw_expr_util.h" +#include "sql/optimizer/ob_optimizer_util.h" +namespace oceanbase { +namespace sql { +/** + * @brief decorrelate lateral derived table + * + * 1. decorrelate normal lateral derived table or can create spj stmt + * select t1.*, v.* from t1, lateral (select * from t2 where t1.a = t2.a) v; + * => + * select t1.*, v.* from t1, (select * from t2) v where t1.a = v.a; + * + * select t1.*,v.* from t1, lateral (select count(t2.c1), t2.c2 from t2 group by c2 having t2.c2 = t1.c1 ) v; + * => + * select t1.*,v.* from test.t1,(select * from (select count(c1),c2 from t2 group by c2) VIEW1) v where (v.c2 = t1.c1); + * + * 2. decorrelate aggr lateral derived table + * select * from t1, lateral (select sum(b) from t2 where t1.a = t2.a); + * => + * select * from t1 left join (select sum(b) from t2 group by t2.a) v on v.a = t1.a; + * + * select * from t1, lateral (select count(b) from t2 where t1.a = t2.a); + * => + * select t1.*, case when v.a is null then 0 else v.`count(b)` from + * t1 left join (select a, count(b) from t2 group by t2.a) v on v.a = t1.a; + * + * select * from t3, +* lateral (select sum(b) from t2 where t2.a = t3.c1 group by b) v; + * => + * select * from t3, (select sum(b), a from t2 group by b,a) v where v.a = t3.c1; + */ +int ObTransformDecorrelate::transform_one_stmt(common::ObIArray &parent_stmts, + ObDMLStmt *&stmt, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + ObSEArray decorrelate_stmts; + bool is_lateral_trans_happened = false; + bool is_aggr_lateral_trans_happened = false; + trans_happened = false; + UNUSED(parent_stmts); + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(decorrelate_lateral_derived_table(stmt, + decorrelate_stmts, + is_lateral_trans_happened))) { + LOG_WARN("failed to decorrlate lateral derived table", K(ret)); + } else if (OB_FAIL(decorrelate_aggr_lateral_derived_table(stmt, + decorrelate_stmts, + is_aggr_lateral_trans_happened))) { + LOG_WARN("failed to decorrelate aggr lateral derived table", K(ret)); + } else if (!is_lateral_trans_happened && !is_aggr_lateral_trans_happened) { + // do nothing + } else if (OB_FAIL(stmt->formalize_query_ref_exprs())) { + LOG_WARN("failed to formalize query ref exprs", K(ret)); + } else if (OB_FAIL(add_transform_hint(*stmt, &decorrelate_stmts))) { + LOG_WARN("failed to add transform hint", K(ret)); + } else { + trans_happened = true; + LOG_TRACE("succeed to do decorrelate lateral derived table"); + } + return ret; +} + +int ObTransformDecorrelate::transform_one_stmt_with_outline(common::ObIArray &parent_stmts, + ObDMLStmt *&stmt, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + UNUSED(parent_stmts); + trans_happened = false; + bool is_happened = false; + ObSEArray decorrelate_stmts; + do { + is_happened = false; + if (OB_FAIL(decorrelate_lateral_derived_table(stmt, + decorrelate_stmts, + is_happened))) { + LOG_WARN("failed to decorrlate lateral derived table", K(ret)); + } else if (!is_happened && + OB_FAIL(decorrelate_aggr_lateral_derived_table(stmt, + decorrelate_stmts, + is_happened))) { + LOG_WARN("failed to decorrelate aggr lateral derived table", K(ret)); + } else if (!is_happened) { + LOG_TRACE("can not do decorrelate with outline", K(ctx_->src_qb_name_)); + } else { + ++ctx_->trans_list_loc_; + trans_happened = true; + LOG_TRACE("succeed to do decorrelate with outline", K(ctx_->src_qb_name_)); + } + } while (OB_SUCC(ret) && is_happened); + + if (OB_SUCC(ret) && trans_happened) { + if (OB_FAIL(stmt->formalize_query_ref_exprs())) { + LOG_WARN("failed to fromalize query ref exprs", K(ret)); + } else if (OB_FAIL(add_transform_hint(*stmt, &decorrelate_stmts))) { + LOG_WARN("failed to add transform hint", K(ret)); + } + } + return ret; +} + +int ObTransformDecorrelate::construct_transform_hint(ObDMLStmt &stmt, void *trans_params) +{ + int ret = OB_SUCCESS; + ObIArray *decorrelate_stmts = NULL; + UNUSED(stmt); + if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->allocator_) || OB_ISNULL(trans_params) + || OB_ISNULL(decorrelate_stmts = static_cast*>(trans_params)) + || OB_UNLIKELY(decorrelate_stmts->empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret), K(ctx_), K(trans_params)); + } else { + ObHint *hint = NULL; + ObDMLStmt *child_stmt = NULL; + ObString child_qb_name; + const ObHint *myhint = NULL; + for (int64_t i = 0; OB_SUCC(ret) && i < decorrelate_stmts->count(); ++i) { + if (OB_ISNULL(child_stmt = decorrelate_stmts->at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret), K(child_stmt)); + } else if (OB_FAIL(ObQueryHint::create_hint(ctx_->allocator_, T_DECORRELATE, hint))) { + LOG_WARN("failed to create hint", K(ret)); + } else if (OB_FAIL(child_stmt->get_qb_name(child_qb_name))) { + LOG_WARN("failed to get qb name", K(ret), K(child_stmt->get_stmt_id())); + } else if (OB_FAIL(ctx_->add_src_hash_val(child_qb_name))) { + LOG_WARN("failed to add src hash val", K(ret)); + } else if (OB_FAIL(ctx_->outline_trans_hints_.push_back(hint))) { + LOG_WARN("failed to push back hint", K(ret)); + } else if (NULL != (myhint = get_hint(child_stmt->get_stmt_hint())) + && myhint->is_enable_hint() + && OB_FAIL(ctx_->add_used_trans_hint(myhint))) { + LOG_WARN("failed to add used trans hint", K(ret)); + } else { + hint->set_qb_name(child_qb_name); + } + } + } + return ret; +} + +int ObTransformDecorrelate::decorrelate_lateral_derived_table(ObDMLStmt *stmt, + ObIArray &decorrelate_stmts, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(stmt)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_from_items().count(); ++i) { + TableItem *table_item = stmt->get_table_item(stmt->get_from_item(i)); + bool is_happened = false; + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->is_joined_table()) { + if (OB_FAIL(transform_joined_table(stmt, + static_cast(table_item), + true, + decorrelate_stmts, + is_happened))) { + LOG_WARN("failed to transform joined table", K(ret)); + } else { + trans_happened |= is_happened; + LOG_TRACE("succeed to do decorrelate for joined table", K(is_happened), + K(table_item->table_id_)); + } + } else if (table_item->is_lateral_table()) { + if (OB_FAIL(transform_lateral_inline_view(stmt, + table_item, + decorrelate_stmts, + true, + NULL, + is_happened))) { + LOG_WARN("failed to transform lateral table item", K(ret)); + } else { + trans_happened |= is_happened; + LOG_TRACE("succeed to do decorrelate for basic lateral derived table", + K(is_happened), + K(table_item->table_id_)); + } + } + } + return ret; +} + +int ObTransformDecorrelate::transform_joined_table(ObDMLStmt *parent_stmt, + JoinedTable *joined_table, + bool parent_can_push_where, + ObIArray &decorrelate_stmts, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + TableItem *left_table = NULL; + TableItem *right_table = NULL; + trans_happened = false; + if (OB_ISNULL(parent_stmt) || + OB_ISNULL(joined_table) || + OB_ISNULL(left_table = joined_table->left_table_) || + OB_ISNULL(right_table = joined_table->right_table_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(parent_stmt), K(joined_table)); + } else if (joined_table->joined_type_ == CONNECT_BY_JOIN) { + // do nothing + } else { + bool can_push_where = true; + bool can_be_decorrelate = true; + bool is_happened = false; + if (!parent_can_push_where || + joined_table->joined_type_ == FULL_OUTER_JOIN || + joined_table->joined_type_ == RIGHT_OUTER_JOIN) { + can_push_where = false; + if (joined_table->joined_type_ == LEFT_OUTER_JOIN || + joined_table->joined_type_ == INNER_JOIN || + joined_table->joined_type_ == FULL_OUTER_JOIN) { + can_be_decorrelate = false; + } + } + if (left_table->is_joined_table()) { + JoinedTable *j_table = static_cast(left_table); + if (OB_FAIL(SMART_CALL(transform_joined_table(parent_stmt, + j_table, + can_push_where, + decorrelate_stmts, + is_happened)))) { + LOG_WARN("failed to transform joined table", K(ret)); + } else { + trans_happened |= is_happened; + } + } else if (!can_be_decorrelate) { + // do nothing + } else if (!left_table->is_lateral_table()) { + // do nothing + } else if (OB_FAIL(transform_lateral_inline_view(parent_stmt, + left_table, + decorrelate_stmts, + can_push_where, + joined_table, + is_happened))) { + LOG_WARN("failed to transform basic table", K(ret)); + } else { + trans_happened |= is_happened; + } + //process right table + if (OB_SUCC(ret)) { + can_push_where = true; + can_be_decorrelate = true; + if (!parent_can_push_where || + joined_table->joined_type_ == FULL_OUTER_JOIN || + joined_table->joined_type_ == LEFT_OUTER_JOIN) { + can_push_where = false; + if (joined_table->joined_type_ == RIGHT_OUTER_JOIN || + joined_table->joined_type_ == INNER_JOIN || + joined_table->joined_type_ == FULL_OUTER_JOIN) { + can_be_decorrelate = false; + } + } + if (right_table->is_joined_table()) { + JoinedTable *j_table = static_cast(right_table); + if (OB_FAIL(SMART_CALL(transform_joined_table(parent_stmt, + j_table, + can_push_where, + decorrelate_stmts, + is_happened)))) { + LOG_WARN("failed to transform joined table", K(ret)); + } else { + trans_happened |= is_happened; + } + } else if (!can_be_decorrelate) { + // do nothing + } else if (!right_table->is_lateral_table()) { + // do nothing + } else if (OB_FAIL(transform_lateral_inline_view(parent_stmt, + right_table, + decorrelate_stmts, + can_push_where, + joined_table, + is_happened))) { + LOG_WARN("failed to transform basic table", K(ret)); + } else { + trans_happened |= is_happened; + } + } + } + return ret; +} + +int ObTransformDecorrelate::transform_lateral_inline_view(ObDMLStmt *parent_stmt, + TableItem *table_item, + ObIArray &decorrelate_stmts, + bool can_push_where, + JoinedTable *joined_table, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + bool is_valid = false; + bool need_create_spj = false; + ObSelectStmt *ref_query = NULL; + if (OB_ISNULL(parent_stmt) || + OB_ISNULL(table_item) || + OB_ISNULL(ref_query = table_item->ref_query_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(parent_stmt), K(table_item)); + } else if (OB_FAIL(check_transform_validity(parent_stmt, + table_item->ref_query_, + table_item, + can_push_where, + joined_table, + is_valid, + need_create_spj))) { + LOG_WARN("failed to check transform validaity", K(ret)); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(do_transform_lateral_inline_view(parent_stmt, + table_item->ref_query_, + table_item, + can_push_where, + joined_table, + need_create_spj))) { + LOG_WARN("failed to do transform lateral inline view", K(ret)); + } else if (OB_FAIL(decorrelate_stmts.push_back(ref_query))) { + LOG_WARN("failed to push back to array", K(ret)); + } else { + trans_happened = true; + } + return ret; +} + +int ObTransformDecorrelate::check_transform_validity(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + bool can_push_where, + JoinedTable *joined_table, + bool &is_valid, + bool &need_create_spj) +{ + int ret = OB_SUCCESS; + bool check_status = false; + bool can_be_decorrelate_direct = true; + bool has_rownum = false; + bool is_ref_outer = false; + is_valid = true; + need_create_spj = false; + OPT_TRACE("try to decorrelate lateral inline view :", ref_query); + if (OB_ISNULL(stmt) || OB_ISNULL(ref_query) || + OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("subquery is null", K(ret), K(ref_query)); + } else if (OB_FAIL(check_hint_allowed_decorrelate(*stmt, *ref_query, is_valid))) { + LOG_WARN("failed to check hint", K(ret)); + } else if (!is_valid) { + // do nothing + OPT_TRACE("hint reject decorrelate"); + } else if (!can_push_where && + OB_FAIL(ObTransformUtils::check_lateral_ref_outer_table(stmt, + joined_table, + table_item, + is_ref_outer))) { + LOG_WARN("failed to check lateral ref outer table", K(ret)); + } else if (is_ref_outer) { + is_valid = false; + OPT_TRACE("lateral ref outer table, cannot decorrelate"); + } else if (ref_query->is_set_stmt()) { + ObIArray &set_queries = ref_query->get_set_query(); + for (int64_t i = 0; is_valid && OB_SUCC(ret) && i < set_queries.count(); ++i) { + if (OB_FAIL(check_lateral_inline_view_validity(table_item, + set_queries.at(i), + is_valid))) { + LOG_WARN("failed to check subquery valid", K(ret)); + } + } + } else if (OB_FAIL(check_lateral_inline_view_validity(table_item, + ref_query, + is_valid))) { + LOG_WARN("failed to check subquery valid", K(ret)); + } + if (OB_FAIL(ret)) { + } else if (!is_valid) { + // do nothing + } else if (ref_query->has_distinct() + || ref_query->is_hierarchical_query() + || ref_query->has_group_by() + || ref_query->has_window_function() + || ref_query->is_set_stmt()) { + can_be_decorrelate_direct = false; + } else if (OB_FAIL(ref_query->has_rownum(has_rownum))) { + LOG_WARN("failed to check has rownum expr", K(ret)); + } else if (has_rownum) { + can_be_decorrelate_direct = false; + } else if (ref_query->has_limit()) { + can_be_decorrelate_direct = false; + } + if (OB_FAIL(ret)) { + } else if (!is_valid) { + // do nothing + } else if (can_be_decorrelate_direct) { + // do nothing + } else if (OB_FAIL(ObTransformUtils::check_correlated_exprs_can_pullup(table_item->exec_params_, + *ref_query, + is_valid))) { + LOG_WARN("failed to check can unnest with spj", K(ret)); + } else if (!is_valid) { + /*do nothing*/ + OPT_TRACE("lateral inline view cannot be pullup, will not transform"); + } else { + need_create_spj = true; + } + return ret; +} + +int ObTransformDecorrelate::check_hint_allowed_decorrelate(ObDMLStmt &stmt, + ObDMLStmt &ref_query, + bool &allowed) +{ + int ret = OB_SUCCESS; + allowed = true; + const ObQueryHint *query_hint = NULL; + const ObHint *myhint = get_hint(ref_query.get_stmt_hint()); + bool is_disable = NULL != myhint && myhint->is_disable_hint(); + const ObHint *no_rewrite1 = stmt.get_stmt_hint().get_no_rewrite_hint(); + const ObHint *no_rewrite2 = ref_query.get_stmt_hint().get_no_rewrite_hint(); + if (OB_ISNULL(ctx_) || OB_ISNULL(query_hint = stmt.get_stmt_hint().query_hint_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret), K(ctx_), K(query_hint)); + } else if (query_hint->has_outline_data()) { + // outline data allowed decorrelate + allowed = query_hint->is_valid_outline_transform(ctx_->trans_list_loc_, myhint); + } else if (NULL != myhint && myhint->is_enable_hint()) { + allowed = true; + } else if (is_disable || NULL != no_rewrite1 || NULL != no_rewrite2) { + allowed = false; + if (OB_FAIL(ctx_->add_used_trans_hint(no_rewrite1))) { + LOG_WARN("failed to add used trans hint", K(ret)); + } else if (OB_FAIL(ctx_->add_used_trans_hint(no_rewrite2))) { + LOG_WARN("failed to add used trans hint", K(ret)); + } else if (is_disable && OB_FAIL(ctx_->add_used_trans_hint(myhint))) { + LOG_WARN("failed to add used trans hint", K(ret)); + } + } + return ret; +} + +int ObTransformDecorrelate::check_lateral_inline_view_validity(TableItem *table_item, + ObSelectStmt *ref_query, + bool &is_valid) +{ + int ret = OB_SUCCESS; + bool check_status = false; + bool is_where_cond_correlated = false; + bool is_having_correlated = false; + is_valid = true; + if (OB_ISNULL(table_item) || + OB_ISNULL(ref_query)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(table_item), K(ref_query)); + } else if (OB_FAIL(ref_query->has_ref_assign_user_var(check_status))) { + LOG_WARN("failed to check stmt has assignment ref user var", K(ret)); + } else if (check_status) { + is_valid = false; + OPT_TRACE("lateral inline view has user var"); + } else if (OB_FAIL(ObTransformUtils::is_correlated_exprs(table_item->exec_params_, + ref_query->get_condition_exprs(), + is_where_cond_correlated))) { + LOG_WARN("failed to check correlated exprs", K(ret)); + } else if (OB_FAIL(ObTransformUtils::is_correlated_exprs(table_item->exec_params_, + ref_query->get_having_exprs(), + is_having_correlated))) { + LOG_WARN("failed to check correlated exprs", K(ret)); + } else if (!is_where_cond_correlated && !is_having_correlated) { + is_valid = false; + OPT_TRACE("lateral inline view no need decorrelate"); + } else if (OB_FAIL(ObTransformUtils::is_select_item_contain_subquery(ref_query, check_status))) { + LOG_WARN("failed to check select item contain subquery", K(ref_query), K(ret)); + } else if (check_status) { + is_valid = false; + OPT_TRACE("lateral inline view select expr contain subquery"); + } else if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(table_item->exec_params_, + ref_query, + check_status))) { + LOG_WARN("failed to is joined table conditions correlated", K(ret)); + } else if (check_status) { + is_valid = false; + OPT_TRACE("lateral inline view contain correlated on condition"); + } else if (OB_FAIL(ObTransformUtils::is_table_item_correlated(table_item->exec_params_, + *ref_query, + check_status))) { + LOG_WARN("failed to check if subquery contain correlated subquery", K(ret)); + } else if (check_status) { + is_valid = false; + OPT_TRACE("lateral inline view contain correlated table item"); + } else if (OB_FAIL(ObTransformUtils::is_where_subquery_correlated(table_item->exec_params_, + *ref_query, + check_status))) { + LOG_WARN("failed to check where condition subquery is correlated", K(ret)); + } else if (check_status) { + is_valid = false; + OPT_TRACE("lateral inline view where condition contain correlated subquery"); + } else if (OB_FAIL(ObTransformUtils::is_select_item_correlated(table_item->exec_params_, + *ref_query, + check_status))) { + LOG_WARN("failed to check select item is correlated", K(ret)); + } else if (check_status) { + is_valid = false; + OPT_TRACE("lateral inline view select item is correlated"); + } else if (OB_FAIL(ObTransformUtils::is_orderby_correlated(table_item->exec_params_, + *ref_query, + check_status))) { + LOG_WARN("failed to check order by is correlated", K(ret)); + } else if (check_status) { + is_valid = false; + OPT_TRACE("lateral inline view order by is correlated"); + } + return ret; +} + +int ObTransformDecorrelate::do_transform_lateral_inline_view(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + bool can_push_where, + JoinedTable *joined_table, + bool need_create_spj) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(stmt) || + OB_ISNULL(ref_query) || + OB_ISNULL(table_item) || + OB_ISNULL(ctx_) || + OB_ISNULL(ctx_->expr_factory_) || + OB_ISNULL(ctx_->allocator_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(stmt), K(ref_query), K(table_item), K(ctx_)); + } else if (!can_push_where && OB_ISNULL(joined_table)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(can_push_where), K(joined_table)); + } else if (need_create_spj) { + if (OB_FAIL(ObTransformUtils::create_spj_and_pullup_correlated_exprs(table_item->exec_params_, + ref_query, + ctx_))) { + LOG_WARN("failed to create spj and pullup correlated exprs", K(ret)); + } else { + table_item->ref_query_ = ref_query; + } + } + if (OB_SUCC(ret)) { + ObSEArray candi_pullup_conds; + ObSEArray column_exprs; + ObSEArray upper_column_exprs; + ObSEArray select_exprs; + ObSEArray new_column_exprs; + ObSEArray pullup_conds; + ObRawExprCopier copier(*ctx_->expr_factory_); + if (OB_FAIL(ObTransformUtils::get_correlated_conditions(table_item->exec_params_, + ref_query->get_condition_exprs(), + candi_pullup_conds))) { + LOG_WARN("failed to get semi conditions", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(candi_pullup_conds, + column_exprs))) { + LOG_WARN("failed to extract column exprs", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::remove_item(ref_query->get_condition_exprs(), + candi_pullup_conds))) { + LOG_WARN("failed to remove condition expr", K(ret)); + } else if (OB_FAIL(ref_query->get_select_exprs(select_exprs))) { + LOG_WARN("failed to get select exprs", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::except_exprs(column_exprs, + select_exprs, + new_column_exprs))) { + LOG_WARN("failed to except exprs", K(ret)); + } else if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, + new_column_exprs, + ref_query))) { + LOG_WARN("failed to create select item", K(ret)); + } else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *table_item, stmt, + upper_column_exprs))) { + LOG_WARN("failed to create columns for view", K(ret)); + } else if (OB_FALSE_IT(select_exprs.reuse())) { + // do nothing + } else if (OB_FAIL(ref_query->get_select_exprs(select_exprs))) { + LOG_WARN("failed to get select exprs", K(ret)); + } else if (OB_FAIL(copier.add_replaced_expr(select_exprs, upper_column_exprs))) { + LOG_WARN("failed to add replaced expr", K(ret)); + } else if (OB_FAIL(copier.copy_on_replace(candi_pullup_conds, pullup_conds))) { + LOG_WARN("failed to copy on replace expr", K(ret)); + } else if (OB_FAIL(ObTransformUtils::decorrelate(pullup_conds, table_item->exec_params_))) { + LOG_WARN("failed to decorrelate pullup conds", K(ret)); + } else if (can_push_where && OB_FAIL(append(stmt->get_condition_exprs(), pullup_conds))) { + LOG_WARN("failed to append condition exprs", K(ret)); + } else if (!can_push_where && OB_FAIL(append(joined_table->get_join_conditions(), pullup_conds))) { + LOG_WARN("failed to append on condition exprs", K(ret)); + } else if (OB_FAIL(stmt->adjust_subquery_list())) { + LOG_WARN("failed to adjust subquery list", K(ret)); + } else if (OB_FAIL(ref_query->adjust_subquery_list())) { + LOG_WARN("failed to adjust subquery list", K(ret)); + } else if (OB_FAIL(ref_query->formalize_stmt(ctx_->session_info_))) { + LOG_WARN("formalize child stmt failed", K(ret)); + } + } + return ret; +} + +int ObTransformDecorrelate::check_hint_status(const ObDMLStmt &stmt, bool &need_trans) +{ + int ret = OB_SUCCESS; + need_trans = false; + const ObQueryHint *query_hint = NULL; + const ObHint *cur_trans_hint = NULL; + if (OB_ISNULL(ctx_) || OB_ISNULL(query_hint = stmt.get_stmt_hint().query_hint_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret), K(ctx_), K(query_hint)); + } else if (!query_hint->has_outline_data()) { + need_trans = true; + } else if (NULL == (cur_trans_hint = query_hint->get_outline_trans_hint(ctx_->trans_list_loc_)) || + !cur_trans_hint->is_decorrelate_hint()) { + /*do nothing*/ + } else { + ObSelectStmt* select_stmt = NULL; + const TableItem *table_item = NULL; + for (int64_t i = 0; !need_trans && OB_SUCC(ret) && i < stmt.get_table_size(); ++i) { + if (OB_ISNULL(table_item = stmt.get_table_item(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (!table_item->is_lateral_table()) { + // do nothing + } else if (OB_ISNULL(select_stmt = table_item->ref_query_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else { + need_trans = query_hint->is_valid_outline_transform(ctx_->trans_list_loc_, + get_hint(select_stmt->get_stmt_hint())); + } + } + } + return ret; +} + +int ObTransformDecorrelate::decorrelate_aggr_lateral_derived_table(ObDMLStmt *stmt, + ObIArray &decorrelate_stmts, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + ObSEArray from_item_list; + ObSEArray joined_table_list; + trans_happened = false; + if (OB_ISNULL(stmt) || + OB_ISNULL(ctx_) || + OB_ISNULL(ctx_->session_info_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(stmt), K(ctx_)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_from_items().count(); ++i) { + TableItem *table_item = stmt->get_table_item(stmt->get_from_item(i)); + bool is_happened = false; + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->is_joined_table()) { + if (OB_FAIL(joined_table_list.push_back(static_cast(table_item)))) { + LOG_WARN("failed to push back joined table list", K(ret)); + } + } else if (table_item->is_lateral_table()) { + if (OB_FAIL(transform_aggr_lateral_inline_view(stmt, + table_item, + decorrelate_stmts, + from_item_list, + joined_table_list, + is_happened))) { + LOG_WARN("failed to transform aggr lateral inline view", K(ret)); + } else { + trans_happened |= is_happened; + LOG_TRACE("succeed to do decorrelate for aggr lateral derived table", + K(is_happened), + K(table_item->table_id_)); + } + } + if (OB_SUCC(ret) && !is_happened && + OB_FAIL(from_item_list.push_back(stmt->get_from_item(i)))) { + LOG_WARN("failed to push back array", K(ret)); + } + } + if (OB_SUCC(ret) && trans_happened) { + if (OB_FAIL(stmt->reset_from_item(from_item_list))) { + LOG_WARN("failed to reset table_items", K(ret)); + } else if (OB_FAIL(stmt->get_joined_tables().assign(joined_table_list))) { + LOG_WARN("failed to reset joined table container", K(ret)); + } else if (OB_FAIL(stmt->formalize_stmt(ctx_->session_info_))) { + LOG_WARN("failed to formalize stmt", K(ret)); + } else { + LOG_TRACE("succ to to do decorrelate aggr lateral inline view"); + } + } + return ret; +} + +int ObTransformDecorrelate::transform_aggr_lateral_inline_view(ObDMLStmt *parent_stmt, + TableItem *table_item, + ObIArray &decorrelate_stmts, + ObIArray &from_item_list, + ObIArray &joined_table_list, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + bool is_valid = false; + ObSEArray pullup_conds; + ObSelectStmt *ref_query = NULL; + if (OB_ISNULL(parent_stmt) || + OB_ISNULL(table_item) || + OB_ISNULL(ref_query = table_item->ref_query_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(parent_stmt), K(table_item)); + } else if (OB_FAIL(check_transform_aggr_validity(parent_stmt, + table_item->ref_query_, + table_item, + pullup_conds, + is_valid))) { + LOG_WARN("failed to check transform validaity", K(ret)); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(do_transform_aggr_lateral_inline_view(parent_stmt, + table_item->ref_query_, + table_item, + pullup_conds, + from_item_list, + joined_table_list))) { + LOG_WARN("failed to do transform aggr lateral inline view", K(ret)); + } else if (OB_FAIL(decorrelate_stmts.push_back(ref_query))) { + LOG_WARN("failed to push back to array", K(ret)); + } else { + trans_happened = true; + } + return ret; +} + +int ObTransformDecorrelate::check_transform_aggr_validity(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + ObIArray &pullup_conds, + bool &is_valid) +{ + int ret = OB_SUCCESS; + bool has_rownum = false; + bool has_ref_assign_user_var = false; + OPT_TRACE("try to decorrelate aggregate lateral inline view :", ref_query); + if (OB_ISNULL(stmt) || OB_ISNULL(ref_query) || + OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("subquery is null", K(ret), K(ref_query)); + } else if (OB_FAIL(check_hint_allowed_decorrelate(*stmt, *ref_query, is_valid))) { + LOG_WARN("failed to check hint", K(ret)); + } else if (!is_valid) { + // do nothing + OPT_TRACE("hint reject decorrelate"); + } else if (!is_valid_group_by(*ref_query)) { + is_valid = false; + OPT_TRACE("ref query is valid group by"); + } else if (ref_query->has_rollup() || + ref_query->has_having() || + NULL != ref_query->get_limit_percent_expr() || + NULL != ref_query->get_offset_expr() || + ref_query->has_window_function() || + ref_query->has_sequence() || + ref_query->is_set_stmt() || + ref_query->is_hierarchical_query()) { + is_valid = false; + OPT_TRACE("ref query has rollup/having/limit offset/limit percent/win_func/sequence"); + } else if (OB_FAIL(ref_query->has_rownum(has_rownum))) { + LOG_WARN("failed to check ref query has rownum", K(ret)); + } else if (has_rownum) { + is_valid = false; + OPT_TRACE("ref query has rownum"); + } else if (OB_FAIL(ObTransformUtils::check_is_basic_aggr_item(*ref_query, is_valid))) { + LOG_WARN("failed to check subquery select item", K(ret)); + } else if (!is_valid) { + OPT_TRACE("has not sum/count/min/max aggregation"); + } else if (OB_FAIL(check_lateral_inline_view_validity(table_item, + ref_query, + is_valid))) { + LOG_WARN("failed to check lateral inline view validity", K(ret)); + } else if (!is_valid) { + OPT_TRACE("ref query has no correlate expr"); + } else if (OB_FAIL(check_transform_aggr_condition_validity(stmt, + ref_query, + table_item, + pullup_conds, + is_valid))) { + LOG_WARN("failed to check transform aggr condition validity", K(ret)); + } else if (!is_valid) { + OPT_TRACE("ref query condition is not valid"); + } + return ret; +} + +int ObTransformDecorrelate::check_transform_aggr_condition_validity(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + ObIArray &pullup_conds, + bool &is_valid) +{ + int ret = OB_SUCCESS; + is_valid = true; + if (OB_ISNULL(stmt) || + OB_ISNULL(ref_query) || + OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(stmt), K(ref_query), K(table_item)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < ref_query->get_condition_size(); ++i) { + ObRawExpr *cond = NULL; + bool is_correlated = false; + if (OB_ISNULL(cond = ref_query->get_condition_expr(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("condition expr is null", K(ret)); + } else if (OB_FAIL(ObTransformUtils::is_correlated_expr(table_item->exec_params_, + cond, + is_correlated))) { + LOG_WARN("failed to check is correlated expr", K(ret)); + } else if (!is_correlated) { + // do nothing + } else if (!cond->has_flag(CNT_COLUMN) || cond->has_flag(CNT_SUB_QUERY)) { + is_valid = false; + OPT_TRACE("ref query condition has subquery"); + } else if (OB_FAIL(ObTransformUtils::is_equal_correlation(table_item->exec_params_, + cond, + is_valid))) { + LOG_WARN("failed to check is equal correlation", K(ret)); + } else if (!is_valid) { + OPT_TRACE("ref query correlated condition is not equal cond"); + } else if (OB_FAIL(pullup_conds.push_back(cond))) { + LOG_WARN("failed to push back nested conditions", K(ret)); + } + } + } + return ret; +} + +int ObTransformDecorrelate::do_transform_aggr_lateral_inline_view( + ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + ObIArray &pullup_conds, + ObIArray &from_item_list, + ObIArray &joined_table_list) +{ + int ret = OB_SUCCESS; + ObRawExpr* not_null_expr = NULL; + ObSEArray view_columns; + ObSEArray select_exprs; + ObSEArray real_values; + ObSEArray is_null_prop; + int64_t idx = 0; + if (OB_ISNULL(stmt) || + OB_ISNULL(ref_query) || + OB_ISNULL(table_item) || + OB_ISNULL(ctx_) || + OB_ISNULL(ctx_->allocator_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->table_name_.empty() && + OB_FAIL(stmt->generate_view_name(*ctx_->allocator_, + table_item->table_name_))) { + LOG_WARN("failed to generate view name", K(ret)); + } else if (table_item->alias_name_.empty() && + OB_FALSE_IT(table_item->alias_name_ = table_item->table_name_)) { + // do nothing + } + + for (int64_t i = 0; OB_SUCC(ret) && i < pullup_conds.count(); ++i) { + ObRawExpr *cond_expr = pullup_conds.at(i); + bool left_is_correlated = false; + if (OB_ISNULL(cond_expr) || OB_UNLIKELY(cond_expr->get_expr_type() != T_OP_EQ) || + OB_ISNULL(cond_expr->get_param_expr(0)) || + OB_ISNULL(cond_expr->get_param_expr(1))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("nested expr is invalid", K(ret), K(cond_expr)); + } else if (OB_FAIL(ObOptimizerUtil::remove_item(ref_query->get_condition_exprs(), + cond_expr))) { + LOG_WARN("failed to remove expr", K(ret)); + } else if (OB_FAIL(ObTransformUtils::is_correlated_expr(table_item->exec_params_, + cond_expr->get_param_expr(0), + left_is_correlated))) { + LOG_WARN("failed to check is left correlated", K(ret)); + } else { + // construct a pullup condition from a nested condition + int64_t inner_param_id = left_is_correlated ? 1 : 0; + ObRawExpr *group_expr = cond_expr->get_param_expr(inner_param_id); + if (group_expr->has_flag(IS_CONST)) { + // do nothing for const expr + } else if (ObOptimizerUtil::find_item(ref_query->get_group_exprs(), + group_expr)) { + // do nothing + } else if (OB_FAIL(ref_query->add_group_expr(group_expr))) { + LOG_WARN("failed to add group expr", K(ret)); + } else if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, + group_expr, + ref_query))) { + LOG_WARN("failed to create select item", K(ret)); + } else if (not_null_expr == NULL) { + not_null_expr = group_expr; + } + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObTransformUtils::create_columns_for_view( + ctx_, *table_item, stmt, view_columns))) { + LOG_WARN("failed to create columns for view stmt", K(ret)); + } else if (OB_FAIL(ref_query->get_select_exprs(select_exprs))) { + LOG_WARN("failed to get select exprs", K(ret)); + } else if (ObOptimizerUtil::find_item(select_exprs, not_null_expr, &idx)) { + not_null_expr = view_columns.at(idx); + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(gather_select_item_null_propagate(ref_query, is_null_prop))) { + LOG_WARN("failed to gather select item null propagate", K(ret)); + } else if (OB_FAIL(ObTransformUtils::deduce_query_values(*ctx_, + *stmt, + is_null_prop, + not_null_expr, + true, + select_exprs, + view_columns, + real_values))) { + LOG_WARN("failed to deduce query values", K(ret)); + } else if (OB_FAIL(stmt->replace_relation_exprs(view_columns, real_values))) { + LOG_WARN("failed to replace inner stmt expr", K(ret)); + } else if (OB_FAIL(ObTransformUtils::replace_exprs(select_exprs, view_columns, pullup_conds))) { + LOG_WARN("failed to replace exprs", K(ret)); + } else if (OB_FAIL(ObTransformUtils::decorrelate(pullup_conds, table_item->exec_params_))) { + LOG_WARN("failed to decorrelation", K(ret)); + } else if (OB_FAIL(transform_from_list(*stmt, + table_item, + ref_query->is_scala_group_by(), + pullup_conds, + from_item_list, + joined_table_list))) { + LOG_WARN("failed to transform from list", K(ret)); + } + return ret; +} + +int ObTransformDecorrelate::gather_select_item_null_propagate(ObSelectStmt *ref_query, + ObIArray &is_null_prop) +{ + int ret = OB_SUCCESS; + ObSEArray vars; + bool is_scala_group_by = false; + if (OB_ISNULL(ref_query)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(is_null_prop.prepare_allocate(ref_query->get_select_item_size()))) { + LOG_WARN("failed to prepare allocate case when array", K(ret)); + } else { + is_scala_group_by = ref_query->is_scala_group_by(); + } + for (int64_t i = 0; OB_SUCC(ret) && i < ref_query->get_select_item_size(); ++i) { + ObRawExpr *expr = NULL; + vars.reuse(); + is_null_prop.at(i) = false; + if (!is_scala_group_by) { + is_null_prop.at(i) = true; + } else if (OB_ISNULL(expr = ref_query->get_select_item(i).expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("select expr is null", K(ret), K(expr)); + } else if (OB_FAIL(ObTransformUtils::extract_nullable_exprs(expr, vars))) { + LOG_WARN("failed to extract nullable exprs", K(ret)); + } else if (vars.count() <= 0) { + // do nothing + } else if (OB_FAIL(ObTransformUtils::is_null_propagate_expr(expr, vars, is_null_prop.at(i)))) { + LOG_WARN("failed to check is null propagate expr", K(ret)); + } + } + return ret; +} + +int ObTransformDecorrelate::transform_from_list(ObDMLStmt &stmt, + TableItem *view_table_item, + bool use_outer_join, + const ObIArray &joined_conds, + ObIArray &from_item_list, + ObIArray &joined_table_list) +{ + int ret = OB_SUCCESS; + if (!use_outer_join) { + if (OB_FAIL(stmt.add_condition_exprs(joined_conds))) { + LOG_WARN("failed to add condition exprs", K(ret)); + } else { + FromItem item; + item.table_id_ = view_table_item->table_id_; + item.is_joined_ = false; + ret = from_item_list.push_back(item); + } + } else { + TableItem *joined_table = NULL; + if (OB_FAIL(ObTransformUtils::merge_from_items_as_inner_join( + ctx_, stmt, from_item_list, joined_table_list, joined_table))) { + LOG_WARN("failed to merge from items as inner join", K(ret)); + } else if (OB_FAIL(ObTransformUtils::add_new_joined_table(ctx_, + stmt, + LEFT_OUTER_JOIN, + joined_table, + view_table_item, + joined_conds, + joined_table, + false))) { + LOG_WARN("failed to add new joined table", K(ret)); + } else if (OB_ISNULL(joined_table)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("joined table is null", K(ret)); + } else if (OB_FAIL(joined_table_list.push_back(static_cast(joined_table)))) { + LOG_WARN("failed to push back joined table list", K(ret)); + } else { + FromItem item; + item.table_id_ = joined_table->table_id_; + item.is_joined_ = true; + ret = from_item_list.push_back(item); + } + } + return ret; +} + +bool ObTransformDecorrelate::is_valid_group_by(const ObSelectStmt &ref_query) +{ + bool is_valid = false; + if (ref_query.is_scala_group_by()) { + is_valid = true; + } else if (ref_query.get_group_expr_size() > 0 && + ref_query.get_rollup_expr_size() == 0) { + is_valid = true; + } + return is_valid; +} + +} +} \ No newline at end of file diff --git a/src/sql/rewrite/ob_transform_decorrelate.h b/src/sql/rewrite/ob_transform_decorrelate.h new file mode 100644 index 0000000000..d8200ea4f5 --- /dev/null +++ b/src/sql/rewrite/ob_transform_decorrelate.h @@ -0,0 +1,126 @@ +/** + * 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 _OB_TRANSFORMDECORRELATE_H +#define _OB_TRANSFORMDECORRELATE_H + +#include "sql/rewrite/ob_transform_rule.h" + +namespace oceanbase { +namespace sql { + +class ObTransformDecorrelate : public ObTransformRule +{ +public: + ObTransformDecorrelate(ObTransformerCtx *ctx) + : ObTransformRule(ctx, TransMethod::POST_ORDER, T_DECORRELATE) + {} + virtual ~ObTransformDecorrelate() {} + virtual int transform_one_stmt(common::ObIArray &parent_stmts, + ObDMLStmt *&stmt, + bool &trans_happened) override; + virtual int transform_one_stmt_with_outline(common::ObIArray &parent_stmts, + ObDMLStmt *&stmt, + bool &trans_happened) override; + virtual int construct_transform_hint(ObDMLStmt &stmt, void *trans_params) override; + virtual int check_hint_status(const ObDMLStmt &stmt, bool &need_trans) override; +protected: + + int decorrelate_lateral_derived_table(ObDMLStmt *stmt, + ObIArray &decorrelate_stmts, + bool &trans_happened); + + int decorrelate_aggr_lateral_derived_table(ObDMLStmt *stmt, + ObIArray &decorrelate_stmts, + bool &trans_happened); + + int transform_lateral_inline_view(ObDMLStmt *parent_stmt, + TableItem *table_item, + ObIArray &decorrelate_stmts, + bool can_push_where, + JoinedTable *joined_table, + bool &trans_happened); + + int transform_joined_table(ObDMLStmt *parent_stmt, + JoinedTable *joined_table, + bool parent_can_push_where, + ObIArray &decorrelate_stmts, + bool &trans_happened); + + int check_transform_validity(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + bool can_push_where, + JoinedTable *joined_table, + bool &is_valid, + bool &need_create_spj); + + int check_lateral_inline_view_validity(TableItem *table_item, + ObSelectStmt *ref_query, + bool &is_valid); + + int check_hint_allowed_decorrelate(ObDMLStmt &stmt, + ObDMLStmt &ref_query, + bool &allowed); + + int do_transform_lateral_inline_view(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + bool can_push_where, + JoinedTable *joined_table, + bool need_create_spj); + + int transform_aggr_lateral_inline_view(ObDMLStmt *parent_stmt, + TableItem *table_item, + ObIArray &decorrelate_stmts, + ObIArray &from_item_list, + ObIArray &joined_table_list, + bool &trans_happened); + + int check_transform_aggr_validity(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + ObIArray &pullup_conds, + bool &is_valid); + + int check_transform_aggr_condition_validity(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + ObIArray &pullup_conds, + bool &is_valid); + + int do_transform_aggr_lateral_inline_view(ObDMLStmt *stmt, + ObSelectStmt *ref_query, + TableItem *table_item, + ObIArray &pullup_conds, + ObIArray &from_item_list, + ObIArray &joined_table_list); + + int gather_select_item_null_propagate(ObSelectStmt *ref_query, + ObIArray &is_null_prop); + + int transform_from_list(ObDMLStmt &stmt, + TableItem *view_table_item, + bool use_outer_join, + const ObIArray &joined_conds, + ObIArray &from_item_list, + ObIArray &joined_table_list); + + bool is_valid_group_by(const ObSelectStmt &subquery); +private: + DISALLOW_COPY_AND_ASSIGN(ObTransformDecorrelate); +}; + +} +} + +#endif // _OB_TRANSFORMDECORRELATE_H \ No newline at end of file diff --git a/src/sql/rewrite/ob_transform_groupby_pushdown.cpp b/src/sql/rewrite/ob_transform_groupby_pushdown.cpp index 1ac14f9609..c9e1631df5 100644 --- a/src/sql/rewrite/ob_transform_groupby_pushdown.cpp +++ b/src/sql/rewrite/ob_transform_groupby_pushdown.cpp @@ -165,6 +165,7 @@ int ObTransformGroupByPushdown::check_groupby_push_down_validity(ObSelectStmt *s bool has_rownum = false; bool has_rand = false; bool contain_inner_table = false; + bool contain_lateral_table = false; is_valid = true; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; @@ -210,6 +211,11 @@ int ObTransformGroupByPushdown::check_groupby_push_down_validity(ObSelectStmt *s LOG_WARN("failed to check collation validity", K(ret)); } else if (!is_valid) { // do nothing + } else if (OB_FAIL(ObTransformUtils::check_contain_correlated_lateral_table(stmt, + contain_lateral_table))) { + LOG_WARN("failed to check contain correlated lateral table", K(ret)); + } else if (contain_lateral_table) { + is_valid = false; } for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < stmt->get_aggr_item_size(); ++i) { ObAggFunRawExpr *aggr_expr = NULL; diff --git a/src/sql/rewrite/ob_transform_join_limit_pushdown.cpp b/src/sql/rewrite/ob_transform_join_limit_pushdown.cpp index e5bf11d351..04b5c4fbff 100644 --- a/src/sql/rewrite/ob_transform_join_limit_pushdown.cpp +++ b/src/sql/rewrite/ob_transform_join_limit_pushdown.cpp @@ -337,10 +337,17 @@ int ObTransformJoinLimitPushDown::split_cartesian_tables(ObSelectStmt *select_st LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(check_contain_correlated_function_table(select_stmt, is_contain))) { LOG_WARN("failed to check contain correlated function table", K(ret)); + } else if (is_contain) { + OPT_TRACE("contain correlated function table, do not push down limit"); } else if (OB_FAIL(check_contain_correlated_json_table(select_stmt, is_contain))) { LOG_WARN("failed to check contain correlated function table", K(ret)); } else if (is_contain) { - //do nothing + OPT_TRACE("contain correlated json table, do not push down limit"); + } else if (OB_FAIL(ObTransformUtils::check_contain_correlated_lateral_table(select_stmt, + is_contain))) { + LOG_WARN("failed to check contain correlated lateral table", K(ret)); + } else if (is_contain) { + OPT_TRACE("contain correlated lateral derived table, do not push down limit"); } else { int64_t N = select_stmt->get_from_item_size(); UnionFind uf(N); diff --git a/src/sql/rewrite/ob_transform_left_join_to_anti.cpp b/src/sql/rewrite/ob_transform_left_join_to_anti.cpp index fc86dd1055..2ba62ed51b 100644 --- a/src/sql/rewrite/ob_transform_left_join_to_anti.cpp +++ b/src/sql/rewrite/ob_transform_left_join_to_anti.cpp @@ -497,6 +497,7 @@ int ObTransformLeftJoinToAnti::check_can_be_trans(ObDMLStmt *stmt, is_valid = false; TableItem *right_table = NULL; bool is_table_valid = true; + bool is_contain_lateral = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->schema_checker_)) { ret = OB_ERR_UNEXPECTED; @@ -506,6 +507,12 @@ int ObTransformLeftJoinToAnti::check_can_be_trans(ObDMLStmt *stmt, OB_ISNULL(right_table = joined_table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid joined table", K(ret), K(joined_table)); + } else if (OB_FAIL(ObTransformUtils::check_contain_correlated_lateral_table( + joined_table, is_contain_lateral))) { + LOG_WARN("failed to check contain correlated lateral table", K(ret)); + } else if (is_contain_lateral) { + is_table_valid = false; + OPT_TRACE("contain lateral derived table, cannot do left to anti"); } else if (stmt->is_delete_stmt() || stmt->is_update_stmt()) { // transformation is not allowed if the updated/deleted table is // on the right side of the join table diff --git a/src/sql/rewrite/ob_transform_pre_process.cpp b/src/sql/rewrite/ob_transform_pre_process.cpp index a3c59ce92a..34db567124 100644 --- a/src/sql/rewrite/ob_transform_pre_process.cpp +++ b/src/sql/rewrite/ob_transform_pre_process.cpp @@ -9544,6 +9544,23 @@ int ObTransformPreProcess::check_is_correlated_cte(ObSelectStmt *stmt, ObIArray< } if (!is_correlated) { // add flag to mark the exec param refer the same table + for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_table_items().count(); ++i) { + TableItem *table_item = stmt->get_table_items().at(i); + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->is_lateral_table()) { + for (int64_t j = 0; OB_SUCC(ret) && j < table_item->exec_params_.count(); ++j) { + ObRawExpr *exec_param = table_item->exec_params_.at(j); + if (OB_ISNULL(exec_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec param is null", K(ret)); + } else if (OB_FAIL(exec_param->add_flag(BE_USED))) { + LOG_WARN("failed to add flag", K(ret)); + } + } + } + } for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_subquery_expr_size(); ++i) { ObQueryRefRawExpr *query_ref = stmt->get_subquery_exprs().at(i); if (OB_ISNULL(query_ref)) { @@ -9583,6 +9600,23 @@ int ObTransformPreProcess::check_is_correlated_cte(ObSelectStmt *stmt, ObIArray< } // clear flag + for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_table_items().count(); ++i) { + TableItem *table_item = stmt->get_table_items().at(i); + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->is_lateral_table()) { + for (int64_t j = 0; OB_SUCC(ret) && j < table_item->exec_params_.count(); ++j) { + ObRawExpr *exec_param = table_item->exec_params_.at(j); + if (OB_ISNULL(exec_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec param is null", K(ret)); + } else if (OB_FAIL(exec_param->clear_flag(BE_USED))) { + LOG_WARN("failed to add flag", K(ret)); + } + } + } + } for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_subquery_expr_size(); ++i) { ObQueryRefRawExpr *query_ref = stmt->get_subquery_exprs().at(i); if (OB_ISNULL(query_ref)) { diff --git a/src/sql/rewrite/ob_transform_predicate_move_around.cpp b/src/sql/rewrite/ob_transform_predicate_move_around.cpp index 656a40edc2..015ff57a2f 100644 --- a/src/sql/rewrite/ob_transform_predicate_move_around.cpp +++ b/src/sql/rewrite/ob_transform_predicate_move_around.cpp @@ -412,7 +412,8 @@ int ObTransformPredicateMoveAround::pullup_predicates_from_view( } else if (table_item->is_fake_cte_table()) { OPT_TRACE("cte table can not pullup predicate"); } else if (!table_item->is_generated_table() && - !table_item->is_temp_table()) { + !table_item->is_temp_table() && + !table_item->is_lateral_table()) { // do nothing OPT_TRACE("not view table, can not pullup predicate"); } else if (OB_FAIL(ObOptimizerUtil::is_table_on_null_side( @@ -425,6 +426,9 @@ int ObTransformPredicateMoveAround::pullup_predicates_from_view( LOG_WARN("failed to get column exprs", K(ret)); } else if (OB_FAIL(SMART_CALL(pullup_predicates(table_item->ref_query_, view_sel_list, view_preds)))) { LOG_WARN("failed to pull up predicate", K(ret), K(view_sel_list), K(filter_columns), K(table_item->ref_query_->get_select_items())); + } else if (table_item->is_lateral_table() && + OB_FAIL(filter_lateral_correlated_preds(*table_item, view_preds))) { + LOG_WARN("failed to filter lateral correlated preds", K(ret)); } else if (OB_FAIL(rename_pullup_predicates( stmt, *table_item, view_sel_list, view_preds))) { LOG_WARN("failed to rename pullup predicates", K(ret)); @@ -1269,7 +1273,8 @@ int ObTransformPredicateMoveAround::pushdown_predicates( if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); - } else if (!table->is_generated_table()) { + } else if (!table->is_generated_table() && + !table->is_lateral_table()) { //do nothing } else if (OB_FAIL(SMART_CALL(pushdown_predicates(table->ref_query_, dummy_preds)))) { LOG_WARN("failed to push down predicates", K(ret)); @@ -1401,7 +1406,8 @@ int ObTransformPredicateMoveAround::pushdown_into_tables_skip_current_level_stmt if (OB_ISNULL(table_item = stmt.get_table_item(from_items.at(i)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have null", K(ret), K(table_item)); - } else if (table_item->is_generated_table()) { + } else if (table_item->is_generated_table() || + table_item->is_lateral_table()) { if (OB_FAIL(SMART_CALL(pushdown_predicates(table_item->ref_query_, dummy_preds)))) { LOG_WARN("failed to push down predicates", K(ret)); } @@ -1432,7 +1438,8 @@ int ObTransformPredicateMoveAround::pushdown_into_joined_table_skip_current_leve if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(table_item)); - } else if (table_item->is_generated_table()) { + } else if (table_item->is_generated_table() || + table_item->is_lateral_table()) { ObArray dummy_preds; if (OB_FAIL(SMART_CALL(pushdown_predicates(table_item->ref_query_, dummy_preds)))) { LOG_WARN("failed to push down predicates", K(ret)); @@ -2774,7 +2781,7 @@ int ObTransformPredicateMoveAround::get_pushdown_predicates( } else if (joined_table.is_inner_join()) { target_table = &joined_table; } - } else if (table.is_generated_table() || table.is_temp_table()) { + } else if (table.is_generated_table() || table.is_lateral_table() || table.is_temp_table()) { target_table = &table; } if (OB_FAIL(ret) || NULL == target_table) { @@ -3053,7 +3060,8 @@ int ObTransformPredicateMoveAround::pushdown_into_table(ObDMLStmt *stmt, LOG_WARN("unexpected null after create_view_with_table", K(ret), K(table_item)); } else if (!table_item->is_joined_table() && !table_item->is_generated_table() && - !table_item->is_temp_table()) { + !table_item->is_temp_table() && + !table_item->is_lateral_table()) { // do nothing } else if (table_item->is_generated_table() && NULL != table_item->ref_query_ && @@ -3067,7 +3075,7 @@ int ObTransformPredicateMoveAround::pushdown_into_table(ObDMLStmt *stmt, table_pullup_preds))) { LOG_WARN("failed to extract table predicates", K(ret)); } - if (OB_SUCC(ret) && table_item->is_generated_table()) { + if (OB_SUCC(ret) && (table_item->is_generated_table() || table_item->is_lateral_table())) { // if predicates are pushed into the view, we can remove them from the upper stmt ObSEArray invalid_preds; uint64_t old_candi_preds_count = 0; @@ -3127,7 +3135,9 @@ int ObTransformPredicateMoveAround::pushdown_into_table(ObDMLStmt *stmt, } } } - if (OB_SUCC(ret) && (table_item->is_generated_table() || table_item->is_joined_table())) { + if (OB_SUCC(ret) && (table_item->is_generated_table() || + table_item->is_lateral_table() || + table_item->is_joined_table())) { // remove a pred from preds if it is pushed into a joined table or a generated table for (int64_t i = 0; OB_SUCC(ret) && i < rename_preds.count(); ++i) { // check whether a table filter is pushed into a view @@ -3861,7 +3871,7 @@ int ObTransformPredicateMoveAround::is_column_expr_null(ObDMLStmt *stmt, LOG_WARN("unexpected null", K(ret), K(stmt), K(expr), K(table)); } else if (table->is_basic_table()) { //do nothing - } else if (table->is_generated_table() || table->is_temp_table()) { + } else if (table->is_generated_table() || table->is_lateral_table() || table->is_temp_table()) { int64_t idx = expr->get_column_id() - OB_APP_MIN_COLUMN_ID; ObRawExpr *child_expr = NULL; ObSelectStmt *child_stmt = table->ref_query_; @@ -4143,3 +4153,24 @@ bool ObTempTableColumnCheckContext::compare_column(const ObColumnRefRawExpr &lef } return bret; } + +int ObTransformPredicateMoveAround::filter_lateral_correlated_preds(TableItem &table_item, + ObIArray &preds) +{ + int ret = OB_SUCCESS; + if (table_item.is_lateral_table()) { + for (int64_t i = preds.count() - 1; OB_SUCC(ret) && i >= 0; --i) { + bool contains = false; + if (OB_FAIL(ObOptimizerUtil::check_contain_my_exec_param(preds.at(i), + table_item.exec_params_, + contains))) { + LOG_WARN("failed to check contain my exec param", K(ret)); + } else if (!contains) { + // do nothing + } else if (OB_FAIL(preds.remove(i))) { + LOG_WARN("failed to remove predicate", K(ret), K(i)); + } + } + } + return ret; +} diff --git a/src/sql/rewrite/ob_transform_predicate_move_around.h b/src/sql/rewrite/ob_transform_predicate_move_around.h index 925773c3d2..3929734150 100644 --- a/src/sql/rewrite/ob_transform_predicate_move_around.h +++ b/src/sql/rewrite/ob_transform_predicate_move_around.h @@ -382,7 +382,7 @@ private: int append_condition_array(ObIArray &conditions, int count, ObRawExprCondition *value); int gather_basic_qualify_filter(ObSelectStmt &stmt, ObIArray &preds); - + int filter_lateral_correlated_preds(TableItem &table_item, ObIArray &preds); private: typedef ObSEArray PullupPreds; ObArenaAllocator allocator_; diff --git a/src/sql/rewrite/ob_transform_project_pruning.cpp b/src/sql/rewrite/ob_transform_project_pruning.cpp index 90f8972598..c2875b6e81 100644 --- a/src/sql/rewrite/ob_transform_project_pruning.cpp +++ b/src/sql/rewrite/ob_transform_project_pruning.cpp @@ -84,7 +84,8 @@ int ObTransformProjectPruning::transform_table_items(ObDMLStmt *&stmt, if (OB_ISNULL(table_item = table_items.at(idx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Table item is NULL in table items", K(ret)); - } else if (table_item->is_generated_table()) { + } else if (table_item->is_generated_table() || + table_item->is_lateral_table()) { ObSelectStmt *ref_query = NULL; OPT_TRACE("try to prune preject for view:", table_item); if (OB_ISNULL(ref_query = table_item->ref_query_)) { @@ -232,7 +233,8 @@ int ObTransformProjectPruning::check_hint_status(const ObDMLStmt &stmt, bool &ne if (OB_ISNULL(table = stmt.get_table_item(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); - } else if (!table->is_generated_table()) { + } else if (!table->is_generated_table() && + !table->is_lateral_table()) { /*do nothing*/ } else if (OB_ISNULL(table->ref_query_)) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/rewrite/ob_transform_rule.cpp b/src/sql/rewrite/ob_transform_rule.cpp index 32ae675f03..8a81fdb224 100644 --- a/src/sql/rewrite/ob_transform_rule.cpp +++ b/src/sql/rewrite/ob_transform_rule.cpp @@ -134,6 +134,7 @@ const char* ObTransformerCtx::get_trans_type_string(uint64_t trans_type) TRANS_TYPE_TO_STR(SIMPLIFY_WINFUNC) TRANS_TYPE_TO_STR(SELECT_EXPR_PULLUP) TRANS_TYPE_TO_STR(PROCESS_DBLINK) + TRANS_TYPE_TO_STR(DECORRELATE) default: return NULL; } } diff --git a/src/sql/rewrite/ob_transform_rule.h b/src/sql/rewrite/ob_transform_rule.h index 2458205581..e889de5d8b 100644 --- a/src/sql/rewrite/ob_transform_rule.h +++ b/src/sql/rewrite/ob_transform_rule.h @@ -174,6 +174,7 @@ enum TRANSFORM_TYPE { COUNT_TO_EXISTS , SELECT_EXPR_PULLUP , PROCESS_DBLINK , + DECORRELATE , TRANSFORM_TYPE_COUNT_PLUS_ONE , }; diff --git a/src/sql/rewrite/ob_transform_simplify_orderby.cpp b/src/sql/rewrite/ob_transform_simplify_orderby.cpp index 9ad47f6ea4..04599763f4 100644 --- a/src/sql/rewrite/ob_transform_simplify_orderby.cpp +++ b/src/sql/rewrite/ob_transform_simplify_orderby.cpp @@ -148,7 +148,8 @@ int ObTransformSimplifyOrderby::remove_order_by_for_view_stmt(ObDMLStmt *stmt, b if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("joined table is null", K(ret)); - } else if (!table_item->is_generated_table()) { + } else if (!table_item->is_generated_table() && + !table_item->is_lateral_table()) { /*do nothing*/ } else if (OB_ISNULL(view_stmt = table_item->ref_query_)) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/rewrite/ob_transform_subquery_coalesce.cpp b/src/sql/rewrite/ob_transform_subquery_coalesce.cpp index d0313ea3ef..88fa41ea8e 100644 --- a/src/sql/rewrite/ob_transform_subquery_coalesce.cpp +++ b/src/sql/rewrite/ob_transform_subquery_coalesce.cpp @@ -1555,8 +1555,8 @@ int ObTransformSubqueryCoalesce::check_expr_can_be_coalesce(ObDMLStmt *stmt, can_be = true; } else if (OB_FAIL(ObTransformUtils::check_correlated_condition_isomorphic(l_subquery, r_subquery, - *l_subquery_expr, - *r_subquery_expr, + l_subquery_expr->get_exec_params(), + r_subquery_expr->get_exec_params(), can_be, left_exprs, right_exprs))) { @@ -1592,7 +1592,9 @@ int ObTransformSubqueryCoalesce::check_subquery_validity(ObQueryRefRawExpr *quer } else if (contain_subquery) { //do nothing LOG_WARN("select item contain subquery, can not be coalesced"); - } else if (OB_FAIL(ObTransformUtils::check_correlated_exprs_can_pullup(*query_ref, *subquery, valid))) { + } else if (OB_FAIL(ObTransformUtils::check_correlated_exprs_can_pullup(query_ref->get_exec_params(), + *subquery, + valid))) { LOG_WARN("failed to check correlated expr can be pullup", K(ret)); } else if (!valid) { OPT_TRACE("correlated exprs can not pullup, will not coalesce subquery"); diff --git a/src/sql/rewrite/ob_transform_temp_table.cpp b/src/sql/rewrite/ob_transform_temp_table.cpp index b755fddda9..7f5538148b 100644 --- a/src/sql/rewrite/ob_transform_temp_table.cpp +++ b/src/sql/rewrite/ob_transform_temp_table.cpp @@ -908,6 +908,31 @@ int ObTransformTempTable::get_non_correlated_subquery(ObDMLStmt *stmt, LOG_WARN("failed to check exec param level", K(ret)); } } + for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_table_items().count(); ++i) { + TableItem *table_item = stmt->get_table_item(i); + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table item is null", K(ret)); + } else if (!table_item->is_lateral_table()) { + // do nothing + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < table_item->exec_params_.count(); ++j) { + ObRawExpr *exec_param = table_item->exec_params_.at(j); + uint64_t key = reinterpret_cast(exec_param); + if (OB_ISNULL(exec_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec param is null", K(ret)); + } else if (OB_FAIL(param_level.set_refactored(key, recursive_level))) { + if (ret == OB_HASH_EXIST) { + ret = OB_SUCCESS; + } else { + LOG_WARN("failed to add exec param into map", K(ret)); + } + } + } + } + + } for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_subquery_expr_size(); ++i) { ObQueryRefRawExpr *query_ref = stmt->get_subquery_exprs().at(i); if (OB_ISNULL(query_ref)) { @@ -2283,7 +2308,8 @@ int ObTransformTempTable::get_stmt_pointers(ObDMLStmt &root_stmt, if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_item is null", K(i)); - } else if (table_item->is_generated_table()) { + } else if (table_item->is_generated_table() || + table_item->is_lateral_table()) { if (parent_stmt.pos_ == pos) { is_find = true; OZ(stmt_ptr.add_ref(&table_item->ref_query_)); diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index 7c0cff9801..6f35909ac6 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -739,6 +739,63 @@ int ObTransformUtils::merge_from_items_as_inner_join(ObTransformerCtx *ctx_, return ret; } +int ObTransformUtils::merge_from_items_as_inner_join(ObTransformerCtx *ctx, + ObDMLStmt &stmt, + ObIArray &from_item_list, + ObIArray &joined_table_list, + TableItem *&ret_table) +{ + int ret = OB_SUCCESS; + ObArray dummy_conds; + ret_table = NULL; + if (OB_ISNULL(ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < from_item_list.count(); ++i) { + const FromItem &item = from_item_list.at(i); + TableItem *table_item = NULL; + if (item.is_joined_) { + JoinedTable *joined_table = NULL; + bool found = false; + for (int64_t j = 0; !found && j < joined_table_list.count(); ++j) { + JoinedTable *cur_table = joined_table_list.at(j); + if (NULL != cur_table) { + if (cur_table->table_id_ == item.table_id_) { + joined_table = cur_table; + found = true; + } + } + } + table_item = joined_table; + if (OB_FAIL(ObOptimizerUtil::remove_item(joined_table_list, joined_table))) { + LOG_WARN("failed to remove joined table", K(ret)); + } + } else { + table_item = stmt.get_table_item_by_id(item.table_id_); + } + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table item is null", K(ret)); + } else if (OB_ISNULL(ret_table)) { + ret_table = table_item; + } else if (OB_FAIL(add_new_joined_table(ctx, stmt, INNER_JOIN, ret_table, + table_item, dummy_conds, ret_table, + false /* add_table */))) { + LOG_WARN("failed to add new joined table", K(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_ISNULL(ret_table)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("no associated table item is found", K(ret)); + } else { + from_item_list.reset(); + } + } + return ret; +} + int ObTransformUtils::create_columns_for_view(ObTransformerCtx *ctx, TableItem &view_table_item, ObDMLStmt *stmt, @@ -748,7 +805,8 @@ int ObTransformUtils::create_columns_for_view(ObTransformerCtx *ctx, uint64_t candi_column_id = OB_APP_MIN_COLUMN_ID; ObSelectStmt *subquery = NULL; if (OB_UNLIKELY(!view_table_item.is_generated_table() && - !view_table_item.is_temp_table())) { + !view_table_item.is_temp_table() && + !view_table_item.is_lateral_table())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected table type", K(view_table_item.type_), K(ret)); } else if (OB_ISNULL(subquery = view_table_item.ref_query_)) { @@ -2290,7 +2348,7 @@ int ObTransformUtils::is_column_expr_not_null(ObNotNullContext &ctx, } else { is_not_null = expr->get_result_type().has_result_flag(NOT_NULL_FLAG); } - } else if (table->is_generated_table() || table->is_temp_table()) { + } else if (table->is_generated_table() || table->is_temp_table() || table->is_lateral_table()) { int64_t idx = expr->get_column_id() - OB_APP_MIN_COLUMN_ID; ObRawExpr *child_expr = NULL; ObSelectStmt *child_stmt = table->ref_query_; @@ -5354,7 +5412,7 @@ int ObTransformUtils::get_from_item(ObDMLStmt *stmt, TableItem *table, FromItem return ret; } -int ObTransformUtils::is_equal_correlation(ObQueryRefRawExpr &query_ref, +int ObTransformUtils::is_equal_correlation(const ObIArray &exec_params, ObRawExpr *cond, bool &is_valid, ObRawExpr **outer_param, @@ -5374,11 +5432,11 @@ int ObTransformUtils::is_equal_correlation(ObQueryRefRawExpr &query_ref, OB_ISNULL(right = cond->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("equal operator is invalid", K(ret), K(left), K(right)); - } else if (OB_FAIL(ObTransformUtils::is_correlated_expr(query_ref.get_exec_params(), + } else if (OB_FAIL(ObTransformUtils::is_correlated_expr(exec_params, left, left_is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); - } else if (OB_FAIL(ObTransformUtils::is_correlated_expr(query_ref.get_exec_params(), + } else if (OB_FAIL(ObTransformUtils::is_correlated_expr(exec_params, right, right_is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); @@ -10980,14 +11038,14 @@ int ObTransformUtils::check_select_item_need_remove(const ObSelectStmt *stmt, /** * Check whether the current subquery can separate spj, and pull related expressions outside of spj * */ -int ObTransformUtils::check_correlated_exprs_can_pullup(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::check_correlated_exprs_can_pullup(const ObIArray &exec_params, const ObSelectStmt &subquery, bool &can_pullup) { int ret = OB_SUCCESS; can_pullup = false; if (subquery.is_set_stmt()) { - if (OB_FAIL(check_correlated_exprs_can_pullup_for_set(query_ref, subquery, can_pullup))) { + if (OB_FAIL(check_correlated_exprs_can_pullup_for_set(exec_params, subquery, can_pullup))) { LOG_WARN("failed to check correlated expr can pullup for set", K(ret)); } } else { @@ -10996,30 +11054,31 @@ int ObTransformUtils::check_correlated_exprs_can_pullup(const ObQueryRefRawExpr bool is_correlated = false; if (subquery.has_distinct() || subquery.is_hierarchical_query()) { //do nothing - } else if (OB_FAIL(check_fixed_expr_correlated(query_ref, subquery, can_pullup))) { + } else if (OB_FAIL(check_fixed_expr_correlated(exec_params, subquery, can_pullup))) { LOG_WARN("failed to check fixed expr validity", K(ret)); } else if (!can_pullup) { //do nothing } else if (OB_FAIL(check_can_pullup_conds(subquery, has_special_expr))) { LOG_WARN("failed to check can pullup conds", K(ret)); - } else if (OB_FAIL(is_table_item_correlated(query_ref, + } else if (OB_FAIL(is_table_item_correlated(exec_params, subquery, is_correlated))) { LOG_WARN("failed to check", K(ret)); } else if (is_correlated) { can_pullup = false; - } else if (OB_FAIL(is_join_conditions_correlated(query_ref, &subquery, is_correlated))) { + } else if (OB_FAIL(is_join_conditions_correlated(exec_params, + &subquery, is_correlated))) { LOG_WARN("failed to check join condition correlated", K(ret)); } else if (is_correlated) { can_pullup = false; - } else if (OB_FAIL(check_correlated_having_expr_can_pullup(query_ref, + } else if (OB_FAIL(check_correlated_having_expr_can_pullup(exec_params, subquery, has_special_expr, can_pullup))) { LOG_WARN("failed to check can pullup having expr", K(ret)); } else if (!can_pullup) { //do nothing - } else if (OB_FAIL(check_correlated_where_expr_can_pullup(query_ref, + } else if (OB_FAIL(check_correlated_where_expr_can_pullup(exec_params, subquery, has_special_expr, can_pullup))) { @@ -11040,7 +11099,7 @@ int ObTransformUtils::check_correlated_exprs_can_pullup(const ObQueryRefRawExpr if (OB_ISNULL(check_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("check expr is null", K(ret), K(check_exprs.at(i))); - } else if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), + } else if (OB_FAIL(is_correlated_expr(exec_params, check_exprs.at(i), is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); @@ -11057,7 +11116,7 @@ int ObTransformUtils::check_correlated_exprs_can_pullup(const ObQueryRefRawExpr * It is necessary to ensure that each set query can separate spj and pull related expressions outside of spj * At the same time, all related expressions of set query are isomorphic * */ -int ObTransformUtils::check_correlated_exprs_can_pullup_for_set(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::check_correlated_exprs_can_pullup_for_set(const ObIArray &exec_params, const ObSelectStmt &subquery, bool &can_pullup) { @@ -11080,7 +11139,7 @@ int ObTransformUtils::check_correlated_exprs_can_pullup_for_set(const ObQueryRef LOG_WARN("unexpect null stmt", K(ret)); } else if (right_query->is_set_stmt()) { can_pullup = false; - } else if (OB_FAIL(check_correlated_exprs_can_pullup(query_ref, *right_query, can_pullup))) { + } else if (OB_FAIL(check_correlated_exprs_can_pullup(exec_params, *right_query, can_pullup))) { LOG_WARN("failed to check correlated exprs can pullup", K(ret)); } else if (!can_pullup) { //do nothing @@ -11088,8 +11147,8 @@ int ObTransformUtils::check_correlated_exprs_can_pullup_for_set(const ObQueryRef first_query = right_query; } else if (OB_FAIL(check_correlated_condition_isomorphic(first_query, right_query, - query_ref, - query_ref, + exec_params, + exec_params, can_pullup, left_select_exprs, right_select_exprs))) { @@ -11107,8 +11166,8 @@ int ObTransformUtils::check_correlated_exprs_can_pullup_for_set(const ObQueryRef */ int ObTransformUtils::check_correlated_condition_isomorphic(ObSelectStmt *left_query, ObSelectStmt *right_query, - const ObQueryRefRawExpr &left_query_ref, - const ObQueryRefRawExpr &right_query_ref, + const ObIArray &left_exec_params, + const ObIArray &right_exec_params, bool &is_valid, ObIArray &left_new_select_exprs, ObIArray &right_new_select_exprs) @@ -11128,9 +11187,9 @@ int ObTransformUtils::check_correlated_condition_isomorphic(ObSelectStmt *left_q if (OB_ISNULL(left_query) || OB_ISNULL(right_query)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null stmt", K(ret)); - } else if (OB_FAIL(add_correlated_flag(left_query_ref.get_exec_params(), exprs))) { + } else if (OB_FAIL(add_correlated_flag(left_exec_params, exprs))) { LOG_WARN("failed to add mark flag", K(ret)); - } else if (OB_FAIL(add_correlated_flag(right_query_ref.get_exec_params(), exprs))) { + } else if (OB_FAIL(add_correlated_flag(right_exec_params, exprs))) { LOG_WARN("failed to add mark flag", K(ret)); } else if (OB_FAIL(mark_correlated_expr(left_query, is_correlated, exprs))) { LOG_WARN("failed to mark correlated expr", K(ret)); @@ -11148,11 +11207,11 @@ int ObTransformUtils::check_correlated_condition_isomorphic(ObSelectStmt *left_q } //check where conditions if (OB_SUCC(ret) && is_valid) { - if (OB_FAIL(get_correlated_conditions(left_query_ref.get_exec_params(), + if (OB_FAIL(get_correlated_conditions(left_exec_params, left_query->get_condition_exprs(), left_where_exprs))) { LOG_WARN("failed to get correlated exprs", K(ret)); - } else if (OB_FAIL(get_correlated_conditions(right_query_ref.get_exec_params(), + } else if (OB_FAIL(get_correlated_conditions(right_exec_params, right_query->get_condition_exprs(), right_where_exprs))) { LOG_WARN("failed to get correlated exprs", K(ret)); @@ -11165,11 +11224,11 @@ int ObTransformUtils::check_correlated_condition_isomorphic(ObSelectStmt *left_q } //check having conditions if (OB_SUCC(ret) && is_valid) { - if (OB_FAIL(get_correlated_conditions(left_query_ref.get_exec_params(), + if (OB_FAIL(get_correlated_conditions(left_exec_params, left_query->get_having_exprs(), left_having_exprs))) { LOG_WARN("failed to get correlated exprs", K(ret)); - } else if (OB_FAIL(get_correlated_conditions(right_query_ref.get_exec_params(), + } else if (OB_FAIL(get_correlated_conditions(right_exec_params, right_query->get_having_exprs(), right_having_exprs))) { LOG_WARN("failed to get correlated exprs", K(ret)); @@ -11187,27 +11246,27 @@ int ObTransformUtils::check_correlated_condition_isomorphic(ObSelectStmt *left_q } //Align select exprs if (OB_SUCC(ret) && is_valid) { - if (OB_FAIL(pullup_correlated_exprs(left_query_ref, + if (OB_FAIL(pullup_correlated_exprs(left_exec_params, left_select_exprs, left_new_select_exprs))) { LOG_WARN("failed to pullup correlated exprs", K(ret)); - } else if (OB_FAIL(pullup_correlated_exprs(left_query_ref, + } else if (OB_FAIL(pullup_correlated_exprs(left_exec_params, left_where_exprs, left_new_select_exprs))) { LOG_WARN("failed to pullup correlated exprs", K(ret)); - } else if (OB_FAIL(pullup_correlated_exprs(left_query_ref, + } else if (OB_FAIL(pullup_correlated_exprs(left_exec_params, left_having_exprs, left_new_select_exprs))) { LOG_WARN("failed to pullup correlated exprs", K(ret)); - } else if (OB_FAIL(pullup_correlated_exprs(right_query_ref, + } else if (OB_FAIL(pullup_correlated_exprs(right_exec_params, right_select_exprs, right_new_select_exprs))) { LOG_WARN("failed to pullup correlated exprs", K(ret)); - } else if (OB_FAIL(pullup_correlated_exprs(right_query_ref, + } else if (OB_FAIL(pullup_correlated_exprs(right_exec_params, right_where_exprs, right_new_select_exprs))) { LOG_WARN("failed to pullup correlated exprs", K(ret)); - } else if (OB_FAIL(pullup_correlated_exprs(right_query_ref, + } else if (OB_FAIL(pullup_correlated_exprs(right_exec_params, right_having_exprs, right_new_select_exprs))) { LOG_WARN("failed to pullup correlated exprs", K(ret)); @@ -11332,7 +11391,7 @@ int ObTransformUtils::is_correlated_expr_isomorphic(ObRawExpr *left_expr, /// a expr is fixed if it can only be produced by current stmt /// Given a fixed correlated expr, we must firstly produce the exec param, /// secondly produce the fixed expr, hence such expr can not be pulled up. -int ObTransformUtils::check_fixed_expr_correlated(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::check_fixed_expr_correlated(const ObIArray &exec_params, const ObSelectStmt &stmt, bool &is_valid) { @@ -11350,7 +11409,7 @@ int ObTransformUtils::check_fixed_expr_correlated(const ObQueryRefRawExpr &query } for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < fixed_exprs.count(); ++i) { bool is_correlated = false; - if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), + if (OB_FAIL(is_correlated_expr(exec_params, fixed_exprs.at(i), is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); @@ -11378,7 +11437,7 @@ int ObTransformUtils::check_can_pullup_conds(const ObSelectStmt &view, bool &has // link.zt why not considering set stmt ? int ObTransformUtils::is_table_item_correlated( - const ObQueryRefRawExpr &query_ref, const ObSelectStmt &subquery, bool &contains) + const ObIArray &exec_params, const ObSelectStmt &subquery, bool &contains) { int ret = OB_SUCCESS; int64_t N = subquery.get_table_size(); @@ -11388,24 +11447,25 @@ int ObTransformUtils::is_table_item_correlated( if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table should not be NULL", K(ret), K(table)); - } else if (table->is_generated_table()) { - if (OB_FAIL(is_correlated_subquery(query_ref.get_exec_params(), table->ref_query_, contains))) { + } else if (table->is_generated_table() || + table->is_lateral_table()) { + if (OB_FAIL(is_correlated_subquery(exec_params, table->ref_query_, contains))) { LOG_WARN("check if subquery correlated failed", K(ret)); } } else if (table->is_function_table()) { - if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), table->function_table_expr_, contains))) { + if (OB_FAIL(is_correlated_expr(exec_params, table->function_table_expr_, contains))) { LOG_WARN("failed to check function table expr correlated", K(ret)); } } else if (table->is_json_table()) { if (OB_ISNULL(table->json_table_def_->doc_expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); - } else if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), table->json_table_def_->doc_expr_, contains))) { + } else if (OB_FAIL(is_correlated_expr(exec_params, table->json_table_def_->doc_expr_, contains))) { LOG_WARN("failed to check function table expr correlated", K(ret)); } } else if (table->is_values_table()) { for (int64_t j = 0; OB_SUCC(ret) && !contains && j < table->table_values_.count(); ++j) { - if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), table->table_values_.at(j), contains))) { + if (OB_FAIL(is_correlated_expr(exec_params, table->table_values_.at(j), contains))) { LOG_WARN("failed to check values table expr correlated", K(ret)); } } @@ -11415,7 +11475,7 @@ int ObTransformUtils::is_table_item_correlated( } // check joined table on conditions and semi info semi condition correlated -int ObTransformUtils::is_join_conditions_correlated(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::is_join_conditions_correlated(const ObIArray &exec_params, const ObSelectStmt *subquery, bool &is_correlated) { @@ -11428,14 +11488,14 @@ int ObTransformUtils::is_join_conditions_correlated(const ObQueryRefRawExpr &que const ObIArray &joined_tables = subquery->get_joined_tables(); const ObIArray &semi_infos = subquery->get_semi_infos(); for (int64_t i = 0; OB_SUCC(ret) && !is_correlated && i < joined_tables.count(); ++i) { - if (OB_FAIL(check_joined_conditions_correlated(query_ref.get_exec_params(), + if (OB_FAIL(check_joined_conditions_correlated(exec_params, joined_tables.at(i), is_correlated))) { LOG_WARN("failed to check joined conditions correlated", K(ret)); } else {/*do nothing*/} } for (int64_t i = 0; OB_SUCC(ret) && !is_correlated && i < semi_infos.count(); ++i) { - if (OB_FAIL(check_semi_conditions_correlated(query_ref.get_exec_params(), + if (OB_FAIL(check_semi_conditions_correlated(exec_params, semi_infos.at(i), is_correlated))) { LOG_WARN("failed to check semi conditions correlated", K(ret)); @@ -11505,7 +11565,7 @@ int ObTransformUtils::check_joined_conditions_correlated(const ObIArray &exec_params, const ObSelectStmt &subquery, bool has_special_expr, bool &can_pullup) @@ -11537,7 +11597,7 @@ int ObTransformUtils::check_correlated_having_expr_can_pullup( ObSEArray column_exprs; ObRawExpr *expr = having_exprs.at(i); bool is_correlated = false; - if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), + if (OB_FAIL(is_correlated_expr(exec_params, expr, is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); @@ -11561,7 +11621,7 @@ int ObTransformUtils::check_correlated_having_expr_can_pullup( * Can't pull up where predicate */ int ObTransformUtils::check_correlated_where_expr_can_pullup( - const ObQueryRefRawExpr &query_ref, + const ObIArray &exec_params, const ObSelectStmt &subquery, bool has_special_expr, bool &can_pullup) @@ -11585,7 +11645,7 @@ int ObTransformUtils::check_correlated_where_expr_can_pullup( if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("condition expr is null", K(ret)); - } else if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), + } else if (OB_FAIL(is_correlated_expr(exec_params, expr, is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); @@ -11671,7 +11731,7 @@ int ObTransformUtils::check_result_type_same(ObRawExpr* left_expr, * You need to call check_correlated_exprs_can_pullup before calling the interface * Ensure that all related expressions can be pulled up */ -int ObTransformUtils::create_spj_and_pullup_correlated_exprs(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::create_spj_and_pullup_correlated_exprs(const ObIArray &exec_params, ObSelectStmt *&subquery, ObTransformerCtx *ctx) { @@ -11689,7 +11749,7 @@ int ObTransformUtils::create_spj_and_pullup_correlated_exprs(const ObQueryRefRaw ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(stmt_factory), K(view_stmt)); } else if (view_stmt->is_set_stmt()) { - if (OB_FAIL(create_spj_and_pullup_correlated_exprs_for_set(query_ref, view_stmt, ctx))) { + if (OB_FAIL(create_spj_and_pullup_correlated_exprs_for_set(exec_params, view_stmt, ctx))) { LOG_WARN("failed to create spj without correlated exprs for set", K(ret)); } else { subquery = view_stmt; @@ -11709,17 +11769,17 @@ int ObTransformUtils::create_spj_and_pullup_correlated_exprs(const ObQueryRefRaw LOG_WARN("table item is null", K(ret)); } else if (OB_FALSE_IT(subquery->get_select_items().reuse())) { } else if (OB_FALSE_IT(subquery->get_column_items().reuse())) { - } else if (OB_FAIL(pullup_correlated_select_expr(query_ref, + } else if (OB_FAIL(pullup_correlated_select_expr(exec_params, *subquery, *view_stmt, new_select_list))) { LOG_WARN("failed to pullup correlated select expr", K(ret)); - } else if (OB_FAIL(pullup_correlated_conditions(query_ref, + } else if (OB_FAIL(pullup_correlated_conditions(exec_params, view_stmt->get_having_exprs(), subquery->get_condition_exprs(), new_select_list))) { LOG_WARN("failed to pullup correlated exprs", K(ret)); - } else if (OB_FAIL(pullup_correlated_conditions(query_ref, + } else if (OB_FAIL(pullup_correlated_conditions(exec_params, view_stmt->get_condition_exprs(), subquery->get_condition_exprs(), new_select_list))) { @@ -11740,7 +11800,7 @@ int ObTransformUtils::create_spj_and_pullup_correlated_exprs(const ObQueryRefRaw for (int64_t i = 0; i < select_items.count(); ++i) { SelectItem &item = select_items.at(i); if (OB_FAIL(replace_none_correlated_expr(item.expr_, - query_ref, + exec_params, pos, new_column_list))) { LOG_WARN("failed to replace expr", K(ret)); @@ -11749,7 +11809,7 @@ int ObTransformUtils::create_spj_and_pullup_correlated_exprs(const ObQueryRefRaw if (OB_FAIL(ret)) { } else if (subquery->get_condition_size() > 0 && OB_FAIL(replace_none_correlated_exprs(subquery->get_condition_exprs(), - query_ref, + exec_params, pos, new_column_list))) { LOG_WARN("failed to replace exprs", K(ret)); @@ -11765,7 +11825,7 @@ int ObTransformUtils::create_spj_and_pullup_correlated_exprs(const ObQueryRefRaw return ret; } -int ObTransformUtils::create_spj_and_pullup_correlated_exprs_for_set(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::create_spj_and_pullup_correlated_exprs_for_set(const ObIArray &exec_params, ObSelectStmt *&stmt, ObTransformerCtx *ctx) { @@ -11796,8 +11856,8 @@ int ObTransformUtils::create_spj_and_pullup_correlated_exprs_for_set(const ObQue first_query = right_query; } else if (OB_FAIL(check_correlated_condition_isomorphic(first_query, right_query, - query_ref, - query_ref, + exec_params, + exec_params, can_pullup, left_new_select_exprs.at(i), right_new_select_exprs.at(i)))) { @@ -11812,7 +11872,7 @@ int ObTransformUtils::create_spj_and_pullup_correlated_exprs_for_set(const ObQue LOG_WARN("unexpect null stmt", K(ret)); // somehow, the following implemenation is quite tircky, // the function actually modify the origin set stmt - } else if (OB_FAIL(create_spj_and_pullup_correlated_exprs(query_ref, query, ctx))) { + } else if (OB_FAIL(create_spj_and_pullup_correlated_exprs(exec_params, query, ctx))) { LOG_WARN("failed to create spj", K(ret)); } else if (0 < i && OB_FAIL(adjust_select_item_pos(right_new_select_exprs.at(i), @@ -11947,14 +12007,14 @@ int ObTransformUtils::adjust_select_item_pos(ObIArray &right_select_ } int ObTransformUtils::replace_none_correlated_exprs(ObIArray &exprs, - const ObQueryRefRawExpr &query_ref, + const ObIArray &exec_params, int &pos, ObIArray &new_column_list) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_FAIL(replace_none_correlated_expr(exprs.at(i), - query_ref, + exec_params, pos, new_column_list))) { LOG_WARN("failed to pullup correlated expr", K(ret)); @@ -11964,7 +12024,7 @@ int ObTransformUtils::replace_none_correlated_exprs(ObIArray &exprs, } int ObTransformUtils::replace_none_correlated_expr(ObRawExpr *&expr, - const ObQueryRefRawExpr &query_ref, + const ObIArray &exec_params, int &pos, ObIArray &new_column_list) { @@ -11978,7 +12038,7 @@ int ObTransformUtils::replace_none_correlated_expr(ObRawExpr *&expr, //do nothing } else if (OB_FAIL(is_scalar_expr(expr, is_scalar))) { LOG_WARN("failed to check is scalar expr", K(ret)); - } else if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), + } else if (OB_FAIL(is_correlated_expr(exec_params, expr, is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); @@ -11996,7 +12056,7 @@ int ObTransformUtils::replace_none_correlated_expr(ObRawExpr *&expr, int64_t N = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { if (OB_FAIL(SMART_CALL(replace_none_correlated_expr(expr->get_param_expr(i), - query_ref, + exec_params, pos, new_column_list)))) { LOG_WARN("failed to pullup correlated expr", K(ret)); @@ -12006,7 +12066,7 @@ int ObTransformUtils::replace_none_correlated_expr(ObRawExpr *&expr, return ret; } -int ObTransformUtils::pullup_correlated_exprs(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::pullup_correlated_exprs(const ObIArray &exec_params, ObIArray &exprs, ObIArray &new_select_list) { @@ -12014,14 +12074,14 @@ int ObTransformUtils::pullup_correlated_exprs(const ObQueryRefRawExpr &query_ref for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { ObRawExpr *expr = exprs.at(i); bool is_correlated = false; - if (OB_FAIL(pullup_correlated_expr(query_ref, expr, new_select_list, is_correlated))) { + if (OB_FAIL(pullup_correlated_expr(exec_params, expr, new_select_list, is_correlated))) { LOG_WARN("failed to pullup correlated expr", K(ret)); } } return ret; } -int ObTransformUtils::pullup_correlated_expr(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::pullup_correlated_expr(const ObIArray &exec_params, ObRawExpr *expr, ObIArray &new_select_list, bool &is_correlated) @@ -12036,7 +12096,7 @@ int ObTransformUtils::pullup_correlated_expr(const ObQueryRefRawExpr &query_ref, //do nothing } else if (OB_FAIL(is_scalar_expr(expr, is_scalar))) { LOG_WARN("failed to check is scalar expr", K(ret)); - } else if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), + } else if (OB_FAIL(is_correlated_expr(exec_params, expr, is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); @@ -12050,7 +12110,7 @@ int ObTransformUtils::pullup_correlated_expr(const ObQueryRefRawExpr &query_ref, int64_t N = expr->get_param_count(); bool param_correlated = false; for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { - if (OB_FAIL(SMART_CALL(pullup_correlated_expr(query_ref, + if (OB_FAIL(SMART_CALL(pullup_correlated_expr(exec_params, expr->get_param_expr(i), new_select_list, param_correlated)))) { @@ -12061,7 +12121,7 @@ int ObTransformUtils::pullup_correlated_expr(const ObQueryRefRawExpr &query_ref, return ret; } -int ObTransformUtils::pullup_correlated_select_expr(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::pullup_correlated_select_expr(const ObIArray &exec_params, ObSelectStmt &stmt, ObSelectStmt &view, ObIArray &new_select_list) @@ -12074,7 +12134,7 @@ int ObTransformUtils::pullup_correlated_select_expr(const ObQueryRefRawExpr &que if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select epxr is null", K(ret)); - } else if (OB_FAIL(pullup_correlated_expr(query_ref, + } else if (OB_FAIL(pullup_correlated_expr(exec_params, expr, new_select_list, is_correlated))) { @@ -12095,7 +12155,7 @@ int ObTransformUtils::pullup_correlated_select_expr(const ObQueryRefRawExpr &que return ret; } -int ObTransformUtils::pullup_correlated_conditions(const ObQueryRefRawExpr &query_ref, +int ObTransformUtils::pullup_correlated_conditions(const ObIArray &exec_params, ObIArray &exprs, ObIArray &pullup_exprs, ObIArray &new_select_list) @@ -12108,14 +12168,14 @@ int ObTransformUtils::pullup_correlated_conditions(const ObQueryRefRawExpr &quer if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("having condition is null", K(ret)); - } else if (OB_FAIL(is_correlated_expr(query_ref.get_exec_params(), + } else if (OB_FAIL(is_correlated_expr(exec_params, expr, is_correlated))) { LOG_WARN("failed to check is correlated expr", K(ret)); } else if (!is_correlated) { //非相关条件不需要上拉 ret = remain_exprs.push_back(expr); - } else if (OB_FAIL(pullup_correlated_expr(query_ref, + } else if (OB_FAIL(pullup_correlated_expr(exec_params, expr, new_select_list, is_correlated))) { @@ -14458,6 +14518,26 @@ int ObTransformUtils::check_can_replace(ObRawExpr *expr, return ret; } +int ObTransformUtils::is_where_subquery_correlated(const ObIArray &exec_params, + const ObSelectStmt &subquery, + bool &is_correlated) +{ + int ret = OB_SUCCESS; + is_correlated = false; + const ObIArray &conds = subquery.get_condition_exprs(); + for (int64_t i = 0; OB_SUCC(ret) && !is_correlated && i < conds.count(); ++i) { + if (OB_ISNULL(conds.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("NULL pointer error", K(conds.at(i)), K(ret)); + } else if (!conds.at(i)->has_flag(CNT_SUB_QUERY)) { + // do nothing + } else if (OB_FAIL(ObTransformUtils::is_correlated_expr(exec_params, conds.at(i), is_correlated))) { + LOG_WARN("failed to check is correlated expr", K(ret)); + } + } + return ret; +} + // check the expr bypass the string input to output, the expr must satisfy following rules: // 1. the param and result are both string type // 2. the content of input string is copied to result without modifying @@ -14485,6 +14565,23 @@ int ObTransformUtils::check_is_bypass_string_expr(const ObRawExpr *expr, return ret; } +int ObTransformUtils::is_correlated_exprs(const ObIArray &exec_params, + ObIArray &exprs, + bool &bret) +{ + int ret = OB_SUCCESS; + bret = false; + for (int64_t i = 0; OB_SUCC(ret) && !bret && i < exprs.count(); ++i) { + if (OB_ISNULL(exprs.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(is_correlated_expr(exec_params, exprs.at(i), bret))) { + LOG_WARN("failed to check correlated expr", K(ret)); + } + } + return ret; +} + // check if the expr result is affected by the collation of param when the expr convert the input // string to another, the expr must satisfy one of following rules: // 1. the param is string type and result is not string type @@ -14512,6 +14609,26 @@ int ObTransformUtils::check_convert_string_safely(const ObRawExpr *expr, return ret; } +int ObTransformUtils::is_select_item_correlated(const ObIArray &exec_params, + const ObSelectStmt &subquery, + bool &is_correlated) +{ + int ret = OB_SUCCESS; + int64_t item_size = subquery.get_select_item_size(); + const ObRawExpr* expr = NULL; + is_correlated = false; + for (int64_t i = 0; OB_SUCC(ret) && !is_correlated && i < item_size; ++i) { + expr = subquery.get_select_item(i).expr_; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(expr), K(ret)); + } else if (OB_FAIL(is_correlated_expr(exec_params, expr, is_correlated))) { + LOG_WARN("failed to check correlated exprs", K(ret)); + } + } + return ret; +} + // insert into t1 values('a'); insert into t2 values('a '); // Q1: select * from (select * from t1 intersect select * from t2) v where c1 = 'a'; // Q2: select * from (select * from t1 intersect select * from t2) v where concat(c1,'a') = 'aa'; @@ -14534,6 +14651,135 @@ int ObTransformUtils::check_pushdown_into_set_valid(const ObSelectStmt* child_st return ret; } +int ObTransformUtils::check_is_basic_aggr_item(const ObSelectStmt &subquery, + bool &is_valid) +{ + int ret = OB_SUCCESS; + is_valid = true; + for (int64_t i = 0; OB_SUCC(ret) && is_valid && i< subquery.get_aggr_item_size(); i++) { + const ObAggFunRawExpr *agg_expr = subquery.get_aggr_item(i); + if (OB_ISNULL(agg_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("aggr expr is null", K(ret)); + } else { + const ObItemType type = agg_expr->get_expr_type(); + is_valid = (type == T_FUN_SUM || type == T_FUN_COUNT || + type == T_FUN_MIN || type == T_FUN_MAX); + } + } + return ret; +} + +class ReplaceColumnsAndAggrs : public ObIRawExprReplacer +{ +public: + int generate_new_expr(ObRawExprFactory &expr_factory, + ObRawExpr *old_expr, + ObRawExpr *&new_expr) + { + int ret = OB_SUCCESS; + if (OB_ISNULL(old_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr is null", K(ret), K(old_expr)); + } else if (old_expr->get_expr_type() == T_FUN_COUNT) { + ObConstRawExpr *const_zero = NULL; + if (OB_FAIL(ObTransformUtils::build_const_expr_for_count(expr_factory, 0, const_zero))) { + LOG_WARN("failed to replace count with 0", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(&expr_factory, + session_, + *const_zero, + old_expr->get_result_type(), + new_expr))) { + LOG_WARN("failed to add cast expr above", K(ret)); + } + } else if (old_expr->is_column_ref_expr() || old_expr->is_aggr_expr()) { + // replace with NULL + ObRawExpr *null_expr = NULL; + if (OB_FAIL(ObRawExprUtils::build_null_expr(expr_factory, null_expr))) { + LOG_WARN("failed to replace variable with null", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(&expr_factory, + session_, + *null_expr, + old_expr->get_result_type(), + new_expr))) { + LOG_WARN("failed to add cast expr above", K(ret)); + } + } else if (old_expr->is_const_or_param_expr()) { + if (OB_FAIL(expr_factory.create_raw_expr(old_expr->get_expr_class(), + old_expr->get_expr_type(), + new_expr))) { + LOG_WARN("failed to create raw expr", K(ret)); + } else if (OB_FAIL(new_expr->assign(*old_expr))) { + LOG_WARN("failed to assign old expr", K(ret)); + } + } + return ret; + } + + ObSQLSessionInfo *session_; +}; + +int ObTransformUtils::deduce_query_values(ObTransformerCtx &ctx, + ObDMLStmt &stmt, + ObIArray &is_null_prop, + ObRawExpr *not_null_expr, + bool is_outer_join, + ObIArray &view_select, + ObIArray &view_columns, + ObIArray &real_values) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(ctx.session_info_) || + OB_ISNULL(ctx.expr_factory_) || + OB_UNLIKELY(is_null_prop.count() > view_select.count()) || + OB_UNLIKELY(is_null_prop.count() > view_columns.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid session or invalid array size", K(ret)); + } else { + ObRawExprCopier copier(*ctx.expr_factory_); + ReplaceColumnsAndAggrs replacer; + replacer.session_ = ctx.session_info_; + for (int64_t i = 0; OB_SUCC(ret) && i < is_null_prop.count(); ++i) { + // replace_columns_and_aggrs() may change expr result type, e.g.: sum() from ObNumberType + // to ObNullType. This may cause operand implicit cast be added twice, so we erase it first. + ObRawExpr *default_expr = NULL; + ObRawExpr *case_when_expr = NULL; + if (OB_FAIL(real_values.push_back(view_columns.at(i)))) { + LOG_WARN("failed to push back view columns", K(ret)); + } else if (is_null_prop.at(i) || !is_outer_join) { + continue; + } else if (OB_ISNULL(not_null_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("not null expr is null", K(ret)); + } else if (OB_FAIL(copier.copy_on_replace(view_select.at(i), + default_expr, + &replacer))) { + LOG_WARN("failed to generate default expr", K(ret)); + // link.zt, shall we add a cast here + } else if (OB_FAIL(default_expr->formalize(ctx.session_info_))) { + LOG_WARN("failed to formalize default expr", K(ret)); + } else if (OB_FAIL(ObTransformUtils::build_case_when_expr(stmt, + not_null_expr, + view_columns.at(i), + default_expr, + case_when_expr, + &ctx))) { + LOG_WARN("failed to build case when expr", K(ret)); + } else if (OB_ISNULL(case_when_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("case when expr is null", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(ctx.expr_factory_, + ctx.session_info_, + *case_when_expr, + view_columns.at(i)->get_result_type(), + real_values.at(i)))) { + LOG_WARN("failed to add cast expr", K(ret)); + } + } + } + return ret; +} + int ObTransformUtils::recursive_check_pushdown_into_set_valid( const ObSelectStmt* child_stmt, ObRawExpr *expr, @@ -14682,6 +14928,136 @@ int ObTransformUtils::is_winfunc_topn_filter(const ObIArray & return ret; } +int ObTransformUtils::extract_nullable_exprs( + const ObRawExpr *expr, ObIArray &vars) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr is null", K(ret)); + } else if (expr->is_column_ref_expr() || + (expr->is_aggr_expr() && expr->get_expr_type() != T_FUN_COUNT)) { + if (OB_FAIL(vars.push_back(expr))) { + LOG_WARN("failed to push back expr", K(ret)); + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { + if (OB_FAIL(SMART_CALL(extract_nullable_exprs(expr->get_param_expr(i), vars)))) { + LOG_WARN("failed to extract nullable expr", K(ret)); + } + } + } + return ret; +} + +int ObTransformUtils::check_contain_correlated_lateral_table(const TableItem *table_item, bool &is_contain) +{ + int ret = OB_SUCCESS; + is_contain = false; + if (OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item->is_joined_table()) { + const JoinedTable *joined_table = static_cast(table_item); + if (OB_FAIL(SMART_CALL(check_contain_correlated_lateral_table(joined_table->left_table_, is_contain)))) { + LOG_WARN("failed to check contain correlated lateral table"); + } else if (is_contain) { + // do nothing + } else if (OB_FAIL(SMART_CALL(check_contain_correlated_lateral_table(joined_table->right_table_, is_contain)))) { + LOG_WARN("failed to check contain correlated lateral table", K(ret)); + } + } else if (table_item->is_lateral_table() && !table_item->exec_params_.empty()) { + is_contain = true; + } + return ret; +} + +int ObTransformUtils::is_orderby_correlated(const ObIArray &exec_params, + const ObSelectStmt &subquery, + bool &is_correlated) +{ + int ret = OB_SUCCESS; + is_correlated = false; + for (int64_t i = 0; OB_SUCC(ret) && !is_correlated && i < subquery.get_order_item_size(); ++i) { + const ObRawExpr *expr = NULL; + if (OB_ISNULL(expr = subquery.get_order_item(i).expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("select expr is null", K(ret)); + } else if (OB_FAIL(ObTransformUtils::is_correlated_expr(exec_params, + expr, + is_correlated))) { + LOG_WARN("failed to check is correlated", K(ret)); + } + } + return ret; +} + +int ObTransformUtils::check_lateral_ref_outer_table(const ObDMLStmt *stmt, + const TableItem *parent_table_item, + const TableItem *table_item, + bool &is_ref_outer) +{ + int ret = OB_SUCCESS; + ObSqlBitSet<> parent_rel_ids; + is_ref_outer = false; + const JoinedTable *join_table = NULL; + if (OB_ISNULL(stmt) || + OB_ISNULL(parent_table_item) || + OB_ISNULL(table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_UNLIKELY(!table_item->is_lateral_table())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected table item", K(ret)); + } else if (!parent_table_item->is_joined_table()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected table item", K(ret)); + } else if (OB_FALSE_IT(join_table = static_cast(parent_table_item))) { + // do nothing + } else if (OB_ISNULL(join_table->left_table_) || + OB_ISNULL(join_table->right_table_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (join_table->left_table_ == table_item && + OB_FAIL(stmt->get_table_rel_ids(*join_table->right_table_, + parent_rel_ids))) { + LOG_WARN("failed to get table rel ids", K(ret)); + } else if (join_table->right_table_ == table_item && + OB_FAIL(stmt->get_table_rel_ids(*join_table->left_table_, + parent_rel_ids))) { + LOG_WARN("failed to get table rel ids", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && !is_ref_outer && i < table_item->exec_params_.count(); ++i) { + ObExecParamRawExpr *exec_param = table_item->exec_params_.at(i); + ObRawExpr *ref_expr = NULL; + if (OB_ISNULL(exec_param) || + OB_ISNULL(ref_expr = exec_param->get_ref_expr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec param is invalid", K(ret)); + } else if (!ref_expr->get_relation_ids().is_subset2(parent_rel_ids)) { + is_ref_outer = true; + } + } + } + return ret; +} + +int ObTransformUtils::check_contain_correlated_lateral_table(ObDMLStmt *stmt, bool &is_contain) +{ + int ret = OB_SUCCESS; + is_contain = false; + for (int i = 0; OB_SUCC(ret) && !is_contain && i < stmt->get_table_items().count(); ++i) { + TableItem *table = stmt->get_table_item(i); + if (OB_ISNULL(table)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null table item", K(ret)); + } else if (OB_FAIL(check_contain_correlated_lateral_table(table, is_contain))) { + LOG_WARN("failed to check contain correlated lateral table", K(ret)); + } + } + return ret; +} + bool ObTransformUtils::is_const_null(ObRawExpr &expr) { int bret = false; diff --git a/src/sql/rewrite/ob_transform_utils.h b/src/sql/rewrite/ob_transform_utils.h index f1b52e4499..c195acbde8 100644 --- a/src/sql/rewrite/ob_transform_utils.h +++ b/src/sql/rewrite/ob_transform_utils.h @@ -272,6 +272,12 @@ public: ObDMLStmt &stmt, TableItem *&ret_table); + static int merge_from_items_as_inner_join(ObTransformerCtx *ctx, + ObDMLStmt &stmt, + ObIArray &from_item_list, + ObIArray &joined_table_list, + TableItem *&ret_table); + static int create_new_column_expr(ObTransformerCtx *ctx, const TableItem &table_item, const int64_t column_id, @@ -987,7 +993,7 @@ public: * 3. 一侧有且仅有本层的列 * @return */ - static int is_equal_correlation(ObQueryRefRawExpr &query_ref, + static int is_equal_correlation(const ObIArray &exec_params, ObRawExpr *cond, bool &is_valid, ObRawExpr **outer_param = NULL, @@ -1513,18 +1519,18 @@ public: const int64_t idx, bool &need_remove); - static int check_correlated_exprs_can_pullup(const ObQueryRefRawExpr &query_ref, + static int check_correlated_exprs_can_pullup(const ObIArray &exec_params, const ObSelectStmt &subquery, bool &can_pullup); - static int check_correlated_exprs_can_pullup_for_set(const ObQueryRefRawExpr &query_ref, + static int check_correlated_exprs_can_pullup_for_set(const ObIArray &exec_params, const ObSelectStmt &subquery, bool &can_pullup); static int check_correlated_condition_isomorphic(ObSelectStmt *left_query, ObSelectStmt *right_query, - const ObQueryRefRawExpr &left_query_ref, - const ObQueryRefRawExpr &right_query_ref, + const ObIArray &left_exec_params, + const ObIArray &right_exec_params, bool &is_valid, ObIArray &left_new_select_exprs, ObIArray &right_new_select_exprs); @@ -1550,17 +1556,17 @@ public: ObRawExpr* right_expr, bool &is_isomorphic); - static int check_fixed_expr_correlated(const ObQueryRefRawExpr &query_ref, + static int check_fixed_expr_correlated(const ObIArray &exec_params, const ObSelectStmt &subquery, bool &is_valid); static int check_can_pullup_conds(const ObSelectStmt &subquery, bool &has_special_expr); - static int is_table_item_correlated(const ObQueryRefRawExpr &query_ref, + static int is_table_item_correlated(const ObIArray &exec_params, const ObSelectStmt &subquery, bool &contains); - static int is_join_conditions_correlated(const ObQueryRefRawExpr &query_ref, + static int is_join_conditions_correlated(const ObIArray &exec_params, const ObSelectStmt *subquery, bool &is_correlated); @@ -1572,12 +1578,12 @@ public: const JoinedTable *joined_table, bool &is_correlated); - static int check_correlated_having_expr_can_pullup(const ObQueryRefRawExpr &query_ref, + static int check_correlated_having_expr_can_pullup(const ObIArray &exec_params, const ObSelectStmt &subquery, bool has_special_expr, bool &can_pullup); - static int check_correlated_where_expr_can_pullup(const ObQueryRefRawExpr &query_ref, + static int check_correlated_where_expr_can_pullup(const ObIArray &exec_params, const ObSelectStmt &subquery, bool has_special_expr, bool &can_pullup); @@ -1585,11 +1591,11 @@ public: static int is_select_item_contain_subquery(const ObSelectStmt *subquery, bool &contain); - static int create_spj_and_pullup_correlated_exprs(const ObQueryRefRawExpr &query_ref, + static int create_spj_and_pullup_correlated_exprs(const ObIArray &exec_params, ObSelectStmt *&subquery, ObTransformerCtx *ctx); - static int create_spj_and_pullup_correlated_exprs_for_set(const ObQueryRefRawExpr &query_ref, + static int create_spj_and_pullup_correlated_exprs_for_set(const ObIArray &exec_params, ObSelectStmt *&stmt, ObTransformerCtx *ctx); @@ -1597,30 +1603,30 @@ public: ObSelectStmt *right_query); static int replace_none_correlated_exprs(ObIArray &exprs, - const ObQueryRefRawExpr &query_ref, + const ObIArray &exec_params, int &pos, ObIArray &new_column_list); static int replace_none_correlated_expr(ObRawExpr *&expr, - const ObQueryRefRawExpr &query_ref, + const ObIArray &exec_params, int &pos, ObIArray &new_column_list); - static int pullup_correlated_exprs(const ObQueryRefRawExpr &query_ref, + static int pullup_correlated_exprs(const ObIArray &exec_params, ObIArray &exprs, ObIArray &new_select_list); - static int pullup_correlated_expr(const ObQueryRefRawExpr &query_ref, + static int pullup_correlated_expr(const ObIArray &exec_params, ObRawExpr *expr, ObIArray &new_select_list, bool &is_correlated); - static int pullup_correlated_select_expr(const ObQueryRefRawExpr &query_ref, + static int pullup_correlated_select_expr(const ObIArray &exec_params, ObSelectStmt &stmt, ObSelectStmt &view, ObIArray &new_select_list); - static int pullup_correlated_conditions(const ObQueryRefRawExpr &query_ref, + static int pullup_correlated_conditions(const ObIArray &exec_params, ObIArray &exprs, ObIArray &pullup_exprs, ObIArray &new_select_list); @@ -1875,6 +1881,44 @@ public: static bool is_const_null(ObRawExpr &expr); static bool is_full_group_by(ObSelectStmt& stmt, ObSQLMode mode); + static int is_where_subquery_correlated(const ObIArray &exec_params, + const ObSelectStmt &subquery, + bool &is_correlated); + + static int is_select_item_correlated(const ObIArray &exec_params, + const ObSelectStmt &subquery, + bool &is_correlated); + + static int is_correlated_exprs(const ObIArray &exec_params, + ObIArray &exprs, + bool &bret); + + static int is_orderby_correlated(const ObIArray &exec_params, + const ObSelectStmt &subquery, + bool &is_correlated); + static int check_is_basic_aggr_item(const ObSelectStmt &subquery, + bool &is_valid); + + static int deduce_query_values(ObTransformerCtx &ctx, + ObDMLStmt &stmt, + ObIArray &is_null_prop, + ObRawExpr *not_null_expr, + bool is_outer_join, + ObIArray &select_exprs, + ObIArray &view_columns, + ObIArray &real_values); + + static int extract_nullable_exprs(const ObRawExpr *expr, ObIArray &vars); + + static int check_contain_correlated_lateral_table(const TableItem *table_item, bool &is_contain); + + static int check_lateral_ref_outer_table(const ObDMLStmt *stmt, + const TableItem *parent_table_item, + const TableItem *table_item, + bool &is_ref); + + static int check_contain_correlated_lateral_table(ObDMLStmt *stmt, bool &is_contain); + private: static int inner_get_lazy_left_join(ObDMLStmt *stmt, TableItem *table, diff --git a/src/sql/rewrite/ob_transform_view_merge.cpp b/src/sql/rewrite/ob_transform_view_merge.cpp index 903bdda82e..2a7a8bf5b1 100644 --- a/src/sql/rewrite/ob_transform_view_merge.cpp +++ b/src/sql/rewrite/ob_transform_view_merge.cpp @@ -117,7 +117,8 @@ int ObTransformViewMerge::need_transform(const common::ObIArray if (OB_ISNULL(table = stmt.get_table_item(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); - } else if (!table->is_generated_table()) { + } else if (!table->is_generated_table() && + !table->is_lateral_table()) { /*do nothing*/ } else if (OB_ISNULL(table->ref_query_)) { ret = OB_ERR_UNEXPECTED; @@ -211,7 +212,8 @@ int ObTransformViewMerge::transform_in_from_item(ObDMLStmt *stmt, LOG_TRACE("succeed to do view merge for joined table", K(is_happened), K(table_item->table_id_)); } - } else if (table_item->is_generated_table()) { + } else if (table_item->is_generated_table() || + table_item->is_lateral_table()) { if (OB_FAIL(transform_generated_table(stmt, table_item, merged_stmts, is_happened))) { LOG_WARN("failed to transform basic table", K(ret)); } else { @@ -395,10 +397,12 @@ int ObTransformViewMerge::transform_generated_table(ObDMLStmt *parent_stmt, ViewMergeHelper helper; trans_happened = false; OPT_TRACE("try to merge view:", table_item); + helper.trans_table = table_item; if (OB_ISNULL(parent_stmt) || OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ptr", K(ret), K(parent_stmt), K(table_item)); - } else if (!table_item->is_generated_table()) { + } else if (!table_item->is_generated_table() && + !table_item->is_lateral_table()) { /*do nothing*/ } else if (OB_ISNULL(child_stmt = table_item->ref_query_)) { ret = OB_ERR_UNEXPECTED; @@ -446,7 +450,8 @@ int ObTransformViewMerge::transform_generated_table(ObDMLStmt *parent_stmt, if (OB_ISNULL(parent_stmt) || OB_ISNULL(parent_table) || OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ptr", K(ret), K(parent_stmt), K(parent_table), K(table_item)); - } else if (!table_item->is_generated_table()) { + } else if (!table_item->is_generated_table() && + !table_item->is_lateral_table()) { /*do nothing*/ } else if (OB_ISNULL(child_stmt = table_item->ref_query_)) { ret = OB_ERR_UNEXPECTED; @@ -467,7 +472,9 @@ int ObTransformViewMerge::transform_generated_table(ObDMLStmt *parent_stmt, is_left_join_right_table = true; } } else {/*do nothing*/} - if (OB_FAIL(ret) || !table_item->is_generated_table()) { + if (OB_FAIL(ret) || + (!table_item->is_generated_table() && + !table_item->is_lateral_table())) { /*do nothing*/ } else if (need_check_where_condi && child_stmt->get_condition_size() > 0) { /*do nothing*/ @@ -647,6 +654,32 @@ int ObTransformViewMerge::check_can_be_merged(ObDMLStmt *parent_stmt, OPT_TRACE("view has random expr, can not merge"); } } + if (OB_SUCC(ret) && can_be) { + bool contain = false; + bool is_ref_outer = false; + if (OB_ISNULL(helper.trans_table)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null table item", K(ret)); + } else if (!helper.trans_table->is_lateral_table()) { + // do nothing + } else if (OB_FAIL(ObTransformUtils::is_table_item_correlated(helper.trans_table->exec_params_, + *child_stmt, + contain))) { + LOG_WARN("failed to check is table item correlated", K(ret)); + } else if (contain) { + can_be = false; + OPT_TRACE("lateral inline view has correlated table item, can not merge"); + } else if (helper.parent_table != NULL && + OB_FAIL(ObTransformUtils::check_lateral_ref_outer_table(parent_stmt, + helper.parent_table, + helper.trans_table, + is_ref_outer))) { + LOG_WARN("failed to check lateral ref outer table", K(ret)); + } else if (is_ref_outer) { + can_be = false; + OPT_TRACE("lateral inline view ref outer table, can not merge"); + } + } } //检查where condition是否存在子查询 if (OB_FAIL(ret) || !can_be) { @@ -966,11 +999,15 @@ int ObTransformViewMerge::transform_joined_table(ObDMLStmt *stmt, //处理joined table single table ids if (OB_SUCC(ret)) { joined_table->single_table_ids_.reset(); - if (OB_FAIL(ObTransformUtils::add_joined_table_single_table_ids(*joined_table, - *left_table))) { + if (OB_ISNULL(joined_table->left_table_) || + OB_ISNULL(joined_table->right_table_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(ObTransformUtils::add_joined_table_single_table_ids(*joined_table, + *joined_table->left_table_))) { LOG_WARN("failed to add joined table single table ids",K(ret)); } else if (OB_FAIL(ObTransformUtils::add_joined_table_single_table_ids(*joined_table, - *right_table))) { + *joined_table->right_table_))) { LOG_WARN("failed to add joined table single table ids",K(ret)); } else {/*do nothing*/} } @@ -1113,6 +1150,9 @@ int ObTransformViewMerge::do_view_merge(ObDMLStmt *parent_stmt, LOG_WARN("failed to remove from item", K(ret)); } else if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(*parent_stmt))) { LOG_WARN("failed to adjust pseudo column like exprs", K(ret)); + } else if (table_item->is_lateral_table() && + OB_FAIL(ObTransformUtils::decorrelate(parent_stmt, table_item->exec_params_))) { + LOG_WARN("failed to decorrelate exec params", K(ret)); } else if (OB_FAIL(parent_stmt->rebuild_tables_hash())) { LOG_WARN("failed to rebuild table hash", K(ret)); } else if (OB_FAIL(parent_stmt->update_column_item_rel_id())) { @@ -1128,7 +1168,7 @@ int ObTransformViewMerge::adjust_updatable_view(ObDMLStmt *parent_stmt, TableIte if (OB_ISNULL(parent_stmt) || OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(parent_stmt), K(table_item), K(ret)); - } else if (OB_UNLIKELY(!table_item->is_generated_table())) { + } else if (OB_UNLIKELY(!table_item->is_generated_table() && !table_item->is_lateral_table())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected table type", K(table_item->type_), K(ret)); } else if (parent_stmt->is_update_stmt() && diff --git a/src/sql/rewrite/ob_transform_where_subquery_pullup.cpp b/src/sql/rewrite/ob_transform_where_subquery_pullup.cpp index 4001fb4bce..fb219fda9d 100644 --- a/src/sql/rewrite/ob_transform_where_subquery_pullup.cpp +++ b/src/sql/rewrite/ob_transform_where_subquery_pullup.cpp @@ -310,7 +310,7 @@ int ObWhereSubQueryPullup::check_transform_validity(ObDMLStmt *stmt, } else if (can_unnest) { /*do nothing*/ } else if (OB_FAIL(ObTransformUtils::check_correlated_exprs_can_pullup( - *trans_param.subquery_expr_, + trans_param.subquery_expr_->get_exec_params(), *trans_param.subquery_, trans_param.can_be_transform_))) { LOG_WARN("failed to check can unnest with spj", K(ret)); @@ -414,7 +414,7 @@ int ObWhereSubQueryPullup::check_subquery_validity(ObQueryRefRawExpr *query_ref, OPT_TRACE("subquery`s select expr contain subquery"); } else if (!is_correlated) { // do nothing - } else if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(*query_ref, + } else if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(query_ref->get_exec_params(), subquery, check_status))) { LOG_WARN("failed to is joined table conditions correlated", K(ret)); @@ -427,7 +427,7 @@ int ObWhereSubQueryPullup::check_subquery_validity(ObQueryRefRawExpr *query_ref, is_valid = false; OPT_TRACE("subquery`s where condition contain correlated subquery"); } else if (OB_FAIL(ObTransformUtils::is_table_item_correlated( - *query_ref, *subquery, check_status))) { + query_ref->get_exec_params(), *subquery, check_status))) { LOG_WARN("failed to check if subquery contain correlated subquery", K(ret)); } else if (check_status) { is_valid = false; @@ -486,7 +486,7 @@ int ObWhereSubQueryPullup::do_transform_pullup_subquery(ObDMLStmt *stmt, ctx_))) { LOG_WARN("failed to add const param constraints", K(ret)); } else if (trans_param.need_create_spj_) { - if (OB_FAIL(ObTransformUtils::create_spj_and_pullup_correlated_exprs(*query_ref, + if (OB_FAIL(ObTransformUtils::create_spj_and_pullup_correlated_exprs(query_ref->get_exec_params(), subquery, ctx_))) { LOG_WARN("failed to create spj and pullup correlated exprs", K(ret)); @@ -1257,12 +1257,14 @@ int ObWhereSubQueryPullup::check_subquery_validity(ObDMLStmt &stmt, //2.check from item correlated if (OB_SUCC(ret) && is_valid) { bool is_correlated = false; - if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(*query_ref, subquery, is_correlated))) { + if (OB_FAIL(ObTransformUtils::is_join_conditions_correlated(query_ref->get_exec_params(), + subquery, + is_correlated))) { LOG_WARN("failed to is joined table conditions correlated", K(ret)); } else if (is_correlated) { is_valid = false; OPT_TRACE("subquery contain correlated on condition"); - } else if (OB_FAIL(ObTransformUtils::is_table_item_correlated(*query_ref, + } else if (OB_FAIL(ObTransformUtils::is_table_item_correlated(query_ref->get_exec_params(), *subquery, is_correlated))) { LOG_WARN("failed to check if subquery contain correlated subquery", K(ret)); diff --git a/src/sql/rewrite/ob_transformer_impl.cpp b/src/sql/rewrite/ob_transformer_impl.cpp index 4fd75a2203..81bf01e3e0 100644 --- a/src/sql/rewrite/ob_transformer_impl.cpp +++ b/src/sql/rewrite/ob_transformer_impl.cpp @@ -47,6 +47,7 @@ #include "sql/rewrite/ob_transform_count_to_exists.h" #include "sql/rewrite/ob_transform_expr_pullup.h" #include "sql/rewrite/ob_transform_dblink.h" +#include "sql/rewrite/ob_transform_decorrelate.h" #include "common/ob_smart_call.h" #include "sql/engine/ob_exec_context.h" @@ -353,6 +354,7 @@ int ObTransformerImpl::transform_rule_set_in_one_iteration(ObDMLStmt *&stmt, APPLY_RULE_IF_NEEDED(SEMI_TO_INNER, ObTransformSemiToInner); APPLY_RULE_IF_NEEDED(QUERY_PUSH_DOWN, ObTransformQueryPushDown); APPLY_RULE_IF_NEEDED(SELECT_EXPR_PULLUP, ObTransformExprPullup); + APPLY_RULE_IF_NEEDED(DECORRELATE, ObTransformDecorrelate); APPLY_RULE_IF_NEEDED(ELIMINATE_OJ, ObTransformEliminateOuterJoin); APPLY_RULE_IF_NEEDED(JOIN_ELIMINATION, ObTransformJoinElimination); APPLY_RULE_IF_NEEDED(JOIN_LIMIT_PUSHDOWN, ObTransformJoinLimitPushDown); @@ -593,23 +595,22 @@ int ObTransformerImpl::finalize_exec_params(ObDMLStmt *stmt) } } } + for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_table_items().count(); ++i) { + TableItem *table_item = NULL; + if (OB_ISNULL(table_item = stmt->get_table_items().at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(finalize_exec_params(stmt, table_item->exec_params_))) { + LOG_WARN("failed to finalize exec params", K(ret)); + } + } for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_subquery_expr_size(); ++i) { ObQueryRefRawExpr *query_ref = NULL; if (OB_ISNULL(query_ref = stmt->get_subquery_exprs().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("query ref expr is null", K(ret)); - } - for (int64_t j = 0; OB_SUCC(ret) && j < query_ref->get_param_count(); ++j) { - ObExecParamRawExpr *exec_param = NULL; - if (OB_ISNULL(exec_param = query_ref->get_exec_param(j))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("exec param is null", K(ret)); - } else if (exec_param->get_param_index() >= 0) { - // do nothing - } else { - exec_param->set_param_index(stmt->get_question_marks_count()); - stmt->increase_question_marks_count(); - } + } else if (OB_FAIL(finalize_exec_params(stmt, query_ref->get_exec_params()))) { + LOG_WARN("failed to finalize exec params", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) { @@ -620,6 +621,24 @@ int ObTransformerImpl::finalize_exec_params(ObDMLStmt *stmt) return ret; } +int ObTransformerImpl::finalize_exec_params(ObDMLStmt *stmt, ObIArray & exec_params) +{ + int ret = OB_SUCCESS; + for (int64_t j = 0; OB_SUCC(ret) && j < exec_params.count(); ++j) { + ObExecParamRawExpr *exec_param = NULL; + if (OB_ISNULL(exec_param = exec_params.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec param is null", K(ret)); + } else if (exec_param->get_param_index() >= 0) { + // do nothing + } else { + exec_param->set_param_index(stmt->get_question_marks_count()); + stmt->increase_question_marks_count(); + } + } + return ret; +} + // TODO @yibo perhaps we can't remove dependency table. // for example, t1 left join t2 on t1.c1 = t2.c1 eliminate t2 relay on t2.c1 is unique, // if schema version of t2 change, t2.c1 may not uniuqe. diff --git a/src/sql/rewrite/ob_transformer_impl.h b/src/sql/rewrite/ob_transformer_impl.h index c0f3db0381..4df18f6ca3 100644 --- a/src/sql/rewrite/ob_transformer_impl.h +++ b/src/sql/rewrite/ob_transformer_impl.h @@ -153,6 +153,8 @@ private: void print_trans_stat(); int finalize_exec_params(ObDMLStmt *stmt); + + int finalize_exec_params(ObDMLStmt *stmt, ObIArray & exec_params); /** * @brief adjust_global_dependency_tables * 为pl收集依赖表的schema version信息