diff --git a/src/sql/optimizer/ob_log_update.cpp b/src/sql/optimizer/ob_log_update.cpp index 578672844f211d6a48827696dbebc1dc4ffa614b..50b2ec9b2127df3c41dfec07440d56a80ab63096 100644 --- a/src/sql/optimizer/ob_log_update.cpp +++ b/src/sql/optimizer/ob_log_update.cpp @@ -333,3 +333,22 @@ int ObLogUpdate::est_cost() } return ret; } + +int ObLogUpdate::inner_replace_generated_agg_expr( + const common::ObIArray > &to_replace_exprs) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(all_table_columns_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null all_table_columns", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < all_table_columns_->count(); i++) { + IndexDMLInfo &index_dml_info = + const_cast *>(all_table_columns_)->at(i).index_dml_infos_.at(0); + if (OB_FAIL(replace_exprs_action(to_replace_exprs, index_dml_info.column_convert_exprs_))) { + LOG_WARN("failed to replace aggr exprs", K(ret)); + } + } + } + return ret; +} diff --git a/src/sql/optimizer/ob_log_update.h b/src/sql/optimizer/ob_log_update.h index 19fc867b054ec648ff3213a4c37d2d16bdfce0a2..2f1c745b02089ae038edd44722af2b1816e52f08 100644 --- a/src/sql/optimizer/ob_log_update.h +++ b/src/sql/optimizer/ob_log_update.h @@ -51,7 +51,10 @@ public: return update_set_; } - virtual int inner_append_not_produced_exprs(ObRawExprUniqueSet& raw_exprs) const override; + virtual int inner_replace_generated_agg_expr( + const common::ObIArray > &to_replace_exprs) override; + + virtual int inner_append_not_produced_exprs(ObRawExprUniqueSet &raw_exprs) const override; private: virtual int print_my_plan_annotation(char* buf, int64_t& buf_len, int64_t& pos, ExplainType type) override; diff --git a/src/sql/rewrite/ob_transform_aggr_subquery.cpp b/src/sql/rewrite/ob_transform_aggr_subquery.cpp index 14dbf2eaddbcac30f82cf5a4033ccc0164b98c4b..02422ed116220a0a3edb1cc703b766a19f14a800 100644 --- a/src/sql/rewrite/ob_transform_aggr_subquery.cpp +++ b/src/sql/rewrite/ob_transform_aggr_subquery.cpp @@ -689,6 +689,17 @@ int ObTransformAggrSubquery::transform_with_join_first(ObDMLStmt*& stmt, bool& t if (OB_FAIL(get_trans_param(*target_stmt, param, root_expr, post_group_by))) { LOG_WARN("failed to find trans params", K(ret)); } else if (NULL == root_expr) { + // should remove alias_ref from target_stmt if it has alias_ref + ObSelectStmt *sel_stmt = NULL; + if (OB_ISNULL(target_stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null stmt", K(ret)); + } else if (target_stmt->is_select_stmt()) { + if (OB_FALSE_IT(sel_stmt = static_cast(target_stmt))) { + } else if (OB_FAIL(revert_vec_assign_exprs(sel_stmt, stmt))) { + LOG_WARN("failed to replace alias exprs", K(ret)); + } + } break; } else if (OB_FAIL(fill_query_refs(target_stmt, root_expr, param))) { LOG_WARN("failed to fill query refs", K(ret)); @@ -704,6 +715,11 @@ int ObTransformAggrSubquery::transform_with_join_first(ObDMLStmt*& stmt, bool& t trans_happened = true; } } + if (OB_SUCC(ret) && trans_happened && stmt->is_update_stmt()) { + if (OB_FAIL(static_cast(stmt)->check_assign())) { + LOG_WARN("failed to check assign", K(ret)); + } + } return ret; } @@ -1125,7 +1141,55 @@ int ObTransformAggrSubquery::do_join_first_transform( return ret; } -int ObTransformAggrSubquery::get_unique_keys(ObDMLStmt& stmt, ObIArray& pkeys, const bool is_first_trans) +int ObTransformAggrSubquery::revert_vec_assign_exprs(ObSelectStmt *&child_stmt, ObDMLStmt *&upper_stmt) +{ + int ret = OB_SUCCESS; + ObSEArray alias_exprs; + ObSEArray col_exprs; + TableItem *tab_item = NULL; + if (OB_ISNULL(child_stmt) || OB_ISNULL(upper_stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->session_info_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (upper_stmt->get_table_size() == 0) { + } else if (OB_ISNULL(tab_item = upper_stmt->get_table_item(0))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null table item", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < child_stmt->get_select_items().count(); ++i) { + ObRawExpr *sel_expr = NULL; + ObRawExpr *expr = NULL; + if (OB_ISNULL(sel_expr = child_stmt->get_select_item(i).expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null select expr", K(ret)); + } else if (!sel_expr->is_alias_ref_expr()) { + } else if (OB_FAIL(alias_exprs.push_back(sel_expr))) { + LOG_WARN("failed to push back alias exprs", K(ret)); + } else if (OB_ISNULL(expr = upper_stmt->get_column_expr_by_id(tab_item->table_id_, i + OB_APP_MIN_COLUMN_ID))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null column expr", K(ret)); + } else if (OB_FAIL(col_exprs.push_back(expr))) { + LOG_WARN("failed to push back alias ref", K(ret)); + } + } + // we can not call remove_select_items if col_exprs or alias_exprs is empty + // since it unavoidablely adjusts column ids + if (OB_FAIL(ret) || col_exprs.empty() || alias_exprs.empty()) { + } else if (OB_FAIL(upper_stmt->replace_inner_stmt_expr(col_exprs, alias_exprs))) { + LOG_WARN("failed to replace inner stmt expr", K(ret)); + } else if (OB_FAIL(ObTransformUtils::remove_select_items( + ctx_, tab_item->table_id_, *child_stmt, *upper_stmt, alias_exprs))) { + LOG_WARN("failed to remove select items", K(ret)); + } else if (OB_FAIL(upper_stmt->formalize_stmt(ctx_->session_info_))) { + LOG_WARN("failed to formalize stmt", K(ret)); + } + } + return ret; +} + +/** + * 获取from list中所有基表的primary key + */ +int ObTransformAggrSubquery::get_unique_keys(ObDMLStmt &stmt, ObIArray &pkeys, const bool is_first_trans) { int ret = OB_SUCCESS; ObSqlBitSet<> empty_ignore_tables; @@ -1482,17 +1546,32 @@ int ObTransformAggrSubquery::fill_query_refs(ObDMLStmt* stmt, ObRawExpr* expr, T ret = OB_ERR_UNEXPECTED; LOG_WARN("params are invalid", K(ret), K(stmt), K(expr)); } else if (expr->has_flag(CNT_ALIAS)) { - if (OB_UNLIKELY(!stmt->is_update_stmt())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("stmt is expected to be update", K(ret)); - } else if (OB_FAIL(static_cast(stmt)->get_vector_assign_values( - param.ja_query_ref_, param.query_refs_))) { - LOG_WARN("failed to get vector assign values", K(ret)); - } - } else { - if (OB_FAIL(param.query_refs_.push_back(param.ja_query_ref_))) { - LOG_WARN("failed to push back query refs", K(ret)); + if (stmt->is_update_stmt()) { + if (OB_FAIL(static_cast(stmt)->get_vector_assign_values(param.ja_query_ref_, + param.query_refs_))) { + LOG_WARN("failed to get vector assign values", K(ret)); + } + } else if (stmt->is_select_stmt()) { + // select stmt can also contain alias ref exprs + ObSEArray sel_exprs; + if (OB_FAIL(static_cast(stmt)->get_select_exprs(sel_exprs))) { + LOG_WARN("failed to get select exprs", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < sel_exprs.count(); ++i) { + ObRawExpr *sel_expr = NULL; + if (OB_ISNULL(sel_expr = sel_exprs.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null expr", K(ret)); + } else if (sel_expr->has_flag(CNT_ALIAS)) { + if (OB_FAIL(param.query_refs_.push_back(sel_expr))) { + LOG_WARN("failed to push back alias ref expr", K(ret)); + } + } + } + } } + } else if (OB_FAIL(param.query_refs_.push_back(param.ja_query_ref_))) { + LOG_WARN("failed to push back query refs", K(ret)); } return ret; } diff --git a/src/sql/rewrite/ob_transform_aggr_subquery.h b/src/sql/rewrite/ob_transform_aggr_subquery.h index 034d7b6189f41ec3ba645b8136f7c10b13ac003e..441bb35b65192044c58c1292c4720295c4da1b25 100644 --- a/src/sql/rewrite/ob_transform_aggr_subquery.h +++ b/src/sql/rewrite/ob_transform_aggr_subquery.h @@ -147,6 +147,21 @@ private: int replace_columns_and_aggrs(ObRawExpr*& expr, ObTransformerCtx* ctx); + /** + * @brief + * revert subquery alias, only used for update vector assignments + * update t1 set (id, name) = (select id, name from t1 where rownum <= 1) where grade < (select max(grade) from t2 + * where id < t1.id); after one iteration transformed, the stmt looks like this: update (select id, name, + * alias_ref(id) as o1, alias_ref(name) as o2 from t1 where xxx) v set v.id = v.o1, v.name = v.o2; the alias_ref + * should not be occurred in the v since v can not be transformed, so we should revert it, the result looks like this: + * update (select id, name from t1 where xxx) v set v.id = alias_ref(id), v.name = alias_ref(name); + * + * @param child_stmt + * @param upper_stmt + * @return int + */ + int revert_vec_assign_exprs(ObSelectStmt *&child_stmt, ObDMLStmt *&upper_stmt); + inline bool is_exists_op(const ObItemType type) { return type == T_OP_EXISTS || type == T_OP_NOT_EXISTS; diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index a7eeaf82c684ad2da1238a8d365cbbfbdeb46432..1bc2730aed18cdb923d571c15ea4c5031ef4f729 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -5351,8 +5351,7 @@ int ObTransformUtils::create_simple_view( } // 4. let the view_stmt process some subqueries if (OB_SUCC(ret) && push_subquery) { - // TODO, subqueries in order by, assignment can also be processed by view - if (OB_FAIL(ObTransformUtils::get_post_join_exprs(stmt, post_join_exprs))) { + if (OB_FAIL(ObTransformUtils::get_post_join_exprs(stmt, post_join_exprs, true))) { LOG_WARN("failed to get additional push down exprs", K(ret)); } }