/** * 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_pre_process.h" #include "sql/rewrite/ob_transformer_impl.h" #include "lib/allocator/ob_allocator.h" #include "lib/oblog/ob_log_module.h" #include "common/ob_common_utility.h" #include "common/ob_smart_call.h" #include "share/ob_unit_getter.h" #include "share/schema/ob_column_schema.h" #include "sql/ob_sql_context.h" #include "sql/resolver/expr/ob_raw_expr.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/optimizer/ob_optimizer_util.h" #include "sql/code_generator/ob_expr_generator_impl.h" #include "sql/engine/ob_physical_plan.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/ob_physical_plan.h" #include "sql/engine/expr/ob_expr_arg_case.h" #include "sql/session/ob_sql_session_info.h" #include "share/config/ob_server_config.h" #include "sql/rewrite/ob_transform_utils.h" #include "sql/resolver/dml/ob_select_stmt.h" #include "sql/resolver/dml/ob_select_resolver.h" #include "sql/resolver/dml/ob_merge_stmt.h" #include "sql/resolver/dml/ob_merge_resolver.h" #include "sql/rewrite/ob_expand_aggregate_utils.h" using namespace oceanbase::common; using namespace oceanbase::share; using namespace oceanbase::share::schema; namespace oceanbase { using namespace common; namespace sql { int ObTransformPreProcess::transform_one_stmt(common::ObIArray &parent_stmts, ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; bool is_happened = false; if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt is NULL", K(ret)); } else if (OB_FAIL(ObTransformUtils::right_join_to_left(stmt))) { LOG_WARN("failed to transform right join as left", K(ret)); } else { if (OB_SUCC(ret)) { if (OB_FAIL(add_all_rowkey_columns_to_stmt(stmt, is_happened))) { LOG_WARN("faield to add all rowkey columns", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to add all rowkey columns", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(eliminate_having(stmt, is_happened))) { LOG_WARN("faield to elinimate having", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to eliminating having statement", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transformer_rowid_expr(stmt, is_happened))) { LOG_WARN("failed to transform rowid expr", K(ret)); } else if (OB_FAIL(add_rowid_constraint(*stmt))) { LOG_WARN("add rowid constraint failed", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform rowid expr", K(is_happened), K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(replace_func_is_serving_tenant(stmt, is_happened))) { LOG_WARN("failed to replace function is_serving_tenant", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to replace function", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_for_temporary_table(stmt, is_happened))) { LOG_WARN("failed to transform for temporary table", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform for temporary table", K(is_happened), K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_for_merge_into(stmt, is_happened))) { LOG_WARN("failed to transform for merge into", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform for merge into", K(is_happened), K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_for_batch_stmt(stmt, is_happened))) { LOG_WARN("failed to transform for batch update", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform for batch stmt", K(is_happened), K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_exprs(stmt, is_happened))) { LOG_WARN("transform exprs failed", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("success to transform exprs", K(is_happened)); } } /*transform_for_nested_aggregate、transformer_aggr_expr两个函数强依赖,必须保证两者改写顺序*/ if (OB_SUCC(ret)) { if (OB_FAIL(transform_for_nested_aggregate(stmt, is_happened))) { LOG_WARN("failed to transform for nested aggregate.", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform for nested aggregate", K(is_happened), K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(transformer_aggr_expr(stmt, is_happened))) { LOG_WARN("failed to transform aggr expr", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform aggr expr", K(is_happened), K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_full_outer_join(stmt, is_happened))) { LOG_WARN("failed to transform full outer join", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform full outer join", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_for_hierarchical_query(stmt, is_happened))) { LOG_WARN("failed to transform for hierarchical query", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform hierarchical query", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_rownum_as_limit_offset(parent_stmts, stmt, is_happened))) { LOG_WARN("failed to transform rownum as limit", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform rownum as limit", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_for_grouping_sets_and_multi_rollup(stmt, is_happened))) { LOG_WARN("failed to transform for transform for grouping sets and multi rollup.", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform for grouping sets and multi rollup",K(is_happened), K(ret)); } } if (OB_SUCC(ret)) { LOG_DEBUG("transform pre process succ", K(*stmt)); if (OB_FAIL(stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize stmt", K(ret)); //} else if (OB_FAIL(stmt->formalize_stmt_expr_reference())) { // LOG_WARN("failed to formalize stmt reference", K(ret)); } } } return ret; } int ObTransformPreProcess::need_transform(const common::ObIArray &parent_stmts, const int64_t current_level, const ObDMLStmt &stmt, bool &need_trans) { UNUSED(parent_stmts); UNUSED(current_level); UNUSED(stmt); need_trans = true; return OB_SUCCESS; } int ObTransformPreProcess::add_all_rowkey_columns_to_stmt(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->schema_checker_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null", K(ret), K(stmt), K(ctx_)); } else { ObIArray &tables = stmt->get_table_items(); TableItem *table_item = NULL; const ObTableSchema *table_schema = NULL; ObSEArray column_items; for (int64_t i = 0; OB_SUCC(ret) && i < tables.count(); ++i) { if (OB_ISNULL(table_item = tables.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null", K(ret), K(table_item)); } else if (!table_item->is_basic_table()) { /* do nothing */ } else if (OB_FAIL(ctx_->schema_checker_->get_table_schema(ctx_->session_info_->get_effective_tenant_id(), table_item->ref_id_, table_schema, table_item->is_link_table()))) { LOG_WARN("table schema not found", K(table_schema)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get invalid table schema", K(table_schema)); } else if (OB_FAIL(add_all_rowkey_columns_to_stmt(*table_schema, *table_item, *ctx_->expr_factory_, *stmt, column_items))) { LOG_WARN("add all rowkey exprs failed", K(ret)); } } if (OB_SUCC(ret) && !column_items.empty()) { ObIArray &orign_column_items = stmt->get_column_items(); for (int i = 0; OB_SUCC(ret) && i < orign_column_items.count(); ++i) { if (OB_ISNULL(orign_column_items.at(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(orign_column_items.at(i).expr_)); } else if (!orign_column_items.at(i).expr_->is_rowkey_column() && OB_FAIL(column_items.push_back(orign_column_items.at(i)))) { LOG_WARN("failed to push back column item", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(stmt->get_column_items().assign(column_items))) { LOG_WARN("failed to assign column items", K(ret)); } else { trans_happened = true; } } } } return ret; } int ObTransformPreProcess::add_all_rowkey_columns_to_stmt(const ObTableSchema &table_schema, const TableItem &table_item, ObRawExprFactory &expr_factory, ObDMLStmt &stmt, ObIArray &column_items) { int ret = OB_SUCCESS; const ObRowkeyInfo &rowkey_info = table_schema.get_rowkey_info(); const ObColumnSchemaV2 *column_schema = NULL; uint64_t column_id = OB_INVALID_ID; ColumnItem *exists_col_item = NULL; ObColumnRefRawExpr *rowkey = NULL; for (int col_idx = 0; OB_SUCC(ret) && col_idx < rowkey_info.get_size(); ++col_idx) { if (OB_FAIL(rowkey_info.get_column_id(col_idx, column_id))) { LOG_WARN("Failed to get column id", K(ret)); } else if (NULL != (exists_col_item = stmt.get_column_item_by_id(table_item.table_id_, column_id))) { if (OB_FAIL(column_items.push_back(*exists_col_item))) { LOG_WARN("failed to push back column item", K(ret)); } } else if (OB_MOCK_LINK_TABLE_PK_COLUMN_ID == column_id && table_item.is_link_table()) { continue; } else if (OB_ISNULL(column_schema = (table_schema.get_column_schema(column_id)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get column schema", K(column_id), K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_column_expr(expr_factory, *column_schema, rowkey))) { LOG_WARN("build column expr failed", K(ret)); } else if (OB_ISNULL(rowkey)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to create raw expr for dummy output", K(ret)); } else { ColumnItem column_item; rowkey->set_ref_id(table_item.table_id_, column_schema->get_column_id()); rowkey->set_column_attr(table_item.get_table_name(), column_schema->get_column_name_str()); rowkey->set_database_name(table_item.database_name_); if (!table_item.alias_name_.empty()) { rowkey->set_table_alias_name(); } column_item.table_id_ = rowkey->get_table_id(); column_item.column_id_ = rowkey->get_column_id(); column_item.base_tid_ = table_item.ref_id_; column_item.base_cid_ = rowkey->get_column_id(); column_item.column_name_ = rowkey->get_column_name(); column_item.set_default_value(column_schema->get_cur_default_value()); column_item.expr_ = rowkey; if (OB_FAIL(stmt.add_column_item(column_item))) { LOG_WARN("add column item to stmt failed", K(ret)); } else if (OB_FAIL(column_items.push_back(column_item))) { LOG_WARN("failed to push back column item", K(ret)); } else if (FALSE_IT(rowkey->clear_explicited_referece())) { } else if (OB_FAIL(rowkey->formalize(NULL))) { LOG_WARN("formalize rowkey failed", K(ret)); } else if (OB_FAIL(rowkey->pull_relation_id_and_levels(stmt.get_current_level()))) { LOG_WARN("failed to pullup relation ids", K(ret)); } } } return ret; } /*@brief,ObTransformPreProcess::transform_for_grouping_sets_and_multi_rollup, tranform stmt with * grouping sets or multi rollup to equal set stmt. * for grouping sets stmt: * 1.select c1,c2 from t1 group by grouping sets(c1,c2); * <==> * select c1, NULL from t1 group by c1 *union all * select NULL, c2 from t1 group by c1; * * 2.select c1,c2,c3,c4 from t1 group by grouping sets(c1,c2), grouping sets(c3,c4); *<==> * select c1,NULL,c3,NULL from t1 group by c1,c3 * union all * select c1,NULL,NULL,c4 from t1 group by c1,c4 * union all * select NULL,c2,c3,NULL from t1 group by c2,c3 * union all * select NULL,c2,NULL,c4 from t1 group by c2,c4; * * as above, {c1,c2} * {c3,c4} ==> Cartesian product * * for multi rollup stmt: * 1.select c1,c2,c3,sum(c3) from t1 group by rollup((c1,c2),c3); * <==> * select c1,c2,c3,sum(c3) from t1 group by c1,c2,c3 * union all * select c1,c2,NULL,sum(c3) from t1 group by c1,c2 * union all * select NULL,NULL,NULL,sum(c3) from t1; * * 2.select c1,c2,c3,sum(c3) from t1 group by rollup (c1,c2),rollup(c3); * <==> * select c1,c2,c3,sum(c3) from t1 group by c1,c2,c3 * union all * select c1,c2,NULL,sum(c3) from t1 group by c1,c2 * union all * select c1,NULL,c3,sum(c3) from t1 group by c1,c3 * union all * select c1,NULL,NULL,sum(c3) from t1 group by c1 * union all * select NULL,NULL,c3,sum(c3) from t1 group by c3 * union all * select NULL,NULL,NULL,sum(c3) from t1; * * as above, {(c1,c2),(c1),(NULL)} * {(c3),(NULL)} ==> Cartesian product */ int ObTransformPreProcess::transform_for_grouping_sets_and_multi_rollup(ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt or ctx is null.", K(ret)); } else if (!stmt->is_select_stmt()) { /* do nothing.*/ } else { ObSelectStmt *select_stmt = static_cast(stmt); ObIArray &grouping_sets_items = select_stmt->get_grouping_sets_items(); ObIArray &multi_rollup_items = select_stmt->get_multi_rollup_items(); if (!select_stmt->has_grouping_sets() && multi_rollup_items.count() == 0) { /* do nothing.*/ } else if (OB_UNLIKELY(grouping_sets_items.count() == 0 && multi_rollup_items.count() == 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(select_stmt->has_grouping_sets()), K(multi_rollup_items.count()), K(grouping_sets_items.count())); } else if (grouping_sets_items.count() == 1 && grouping_sets_items.at(0).grouping_sets_exprs_.count() == 1 && grouping_sets_items.at(0).multi_rollup_items_.count() == 0 && multi_rollup_items.count() == 0) { //if grouping sets expr has only one,we can remove grouping sets directly. if (OB_FAIL(append(select_stmt->get_group_exprs(), grouping_sets_items.at(0).grouping_sets_exprs_.at(0).groupby_exprs_))) { LOG_WARN("failed to append group exprs", K(ret)); } else { grouping_sets_items.reset(); bool is_happened = false; if (!select_stmt->has_group_by() && OB_FAIL(ObTransformUtils::set_limit_expr(select_stmt, ctx_))) { LOG_WARN("add limit expr failed", K(ret)); } else if (!select_stmt->has_group_by() && OB_FAIL(eliminate_having(select_stmt, is_happened))) { LOG_WARN("failed to eliminate having", K(ret)); } else { trans_happened = true; LOG_TRACE("eliminate having", K(is_happened)); } } } else { //as following steps to transform grouping sets stmt to set stmt: // 1. Creating spj stmt from origin stmt; // 2. According to the spj stmt separated in the previous step, creating temp table and add it // to origin stmt // 3. According to grouping sets items or multi rollup items and stmt created in the previous // step,creating set stmt // 4. Merging set stmt created in the previous step and origin stmt into transform stmt. ObSelectStmt *view_stmt = NULL; ObSelectStmt *transform_stmt = NULL; ObSelectStmt *set_view_stmt = NULL; bool is_correlated = false; int32_t stmt_level = select_stmt->get_current_level(); //step 1, creating spj stmt if (OB_FAIL(ObTransformUtils::create_simple_view(ctx_, select_stmt, view_stmt))) { LOG_WARN("failed to create spj view.", K(ret)); //step 2, creating temp table } else if (OB_ISNULL(view_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("view stmt is null", K(ret), K(view_stmt)); } else if (stmt_level > 0 && OB_FAIL(ObTransformUtils::is_correlated_subquery(*view_stmt, is_correlated))) { LOG_WARN("failed to check is correlated subquery", K(ret)); } else if (is_correlated) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "correlated temp table now"); LOG_WARN("correlated temp table is not support now!", K(ret)); } else if (OB_FAIL(add_generated_table_as_temp_table(ctx_, select_stmt))) { LOG_WARN("failed to add generated table as temp table", K(ret)); //setp 3, creating set stmt } else if (OB_FAIL(create_set_view_stmt(select_stmt, set_view_stmt))) { LOG_WARN("failed to create grouping sets view.", K(ret)); //step 4, merge stmt } else if (OB_FAIL(replace_with_set_stmt_view(select_stmt, set_view_stmt, transform_stmt))) { LOG_WARN("failed to create union view for grouping sets.", K(ret)); } else { stmt = transform_stmt; trans_happened = true; LOG_TRACE("succeed to transform transform for grouping sets and multi rollup", K(*stmt)); } } } return ret; } int ObTransformPreProcess::add_generated_table_as_temp_table(ObTransformerCtx *ctx, ObDMLStmt *stmt) { int ret = OB_SUCCESS; TableItem *table_item = NULL; if (OB_ISNULL(ctx) || OB_ISNULL(ctx->allocator_) || OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ctx), K(stmt), K(ret)); } else if (OB_UNLIKELY(1 != stmt->get_table_items().count()) || OB_ISNULL(table_item = stmt->get_table_item(0)) || OB_UNLIKELY(!table_item->is_generated_table()) || OB_ISNULL(table_item->ref_query_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(stmt->get_table_items().count()), K(table_item), K(ret)); } else if (OB_FALSE_IT(table_item->alias_name_ = table_item->table_name_)) { } else if (OB_FAIL(stmt->generate_view_name(*ctx->allocator_, table_item->table_name_, true))) { LOG_WARN("failed to generate view name", K(ret)); } else { table_item->type_ = TableItem::TEMP_TABLE; for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_column_items().count(); i++) { if (OB_ISNULL(stmt->get_column_item(i)) || OB_ISNULL(stmt->get_column_item(i)->expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else { stmt->get_column_item(i)->expr_->set_table_name(table_item->alias_name_); } } } return ret; } /*@brief, ObTransformPreProcess::create_select_list_from_grouping_sets, according to oracle action: * if the expr not in group by expr except in aggr, the expr will replaced with NULL; eg: * select c1, c2, max(c1), max(c2) from t1 group by grouping sets(c1,c2) having c1 > 1 or c2 > 1 or sum(c1) > 2 or sum(c2) > 2; * <==> * select c1, NULL, max(c1), max(c1) from t1 group by c1 having c1 > 1 or NULL > 1 or sum(c1) > 2 or sum(c2) > 2 * union all * select NULL, c2, max(c1), max(c1) from t1 group by c2 having NULL > 1 or c2 > 1 or sum(c1) > 2 or sum(c2) > 2; * * select nvl(c1,1),c3 from t1 group by grouping sets(nvl(c1,1),c3); * <==> * select nvl(c1,1), NULL from t1 group by nvl(c1,1) * union all * select NULL, c3 from t1 group by c3; * * select nvl(c1,1) + c3 from t1 group by grouping sets(nvl(c1,1),c3); */ int ObTransformPreProcess::create_select_list_from_grouping_sets( ObSelectStmt *stmt, ObIArray &groupby_exprs_list, int64_t cur_index, ObIArray &old_exprs, ObIArray &new_exprs, int64_t origin_groupby_num /* = -1 */) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null.", K(ret), K(stmt), K(ctx_)); } else { common::ObSEArray select_items; ObRelIds rel_ids; for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_select_item_size(); i++) { if (OB_FAIL(extract_select_expr_and_replace_expr(stmt->get_select_item(i).expr_, stmt->get_group_exprs(), stmt->get_rollup_exprs(), stmt->get_aggr_items(), groupby_exprs_list, cur_index, select_items, old_exprs, new_exprs, rel_ids, origin_groupby_num))) { LOG_WARN("failed to extract select expr and replace expr", K(ret)); } else {/*do nothing*/} } for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_column_size(); ++i) { ObRawExpr *expr = stmt->get_column_items().at(i).expr_; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (ObOptimizerUtil::find_item(stmt->get_group_exprs(), expr) || ObOptimizerUtil::find_item(stmt->get_rollup_exprs(), expr) || expr->get_relation_ids().is_subset2(rel_ids)) { /*do nothing*/ } else { ObRawExpr *null_expr = NULL; ObSysFunRawExpr *cast_expr = NULL; if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx_->expr_factory_, null_expr))) { LOG_WARN("failed build null exprs.", K(ret)); } else if (OB_FAIL(ObRawExprUtils::create_cast_expr(*ctx_->expr_factory_, null_expr, expr->get_result_type(), cast_expr, ctx_->session_info_))) { LOG_WARN("create cast expr failed", K(ret)); } else if (OB_FAIL(cast_expr->add_flag(IS_INNER_ADDED_EXPR))) { LOG_WARN("failed to add flag", K(ret)); } else if (OB_FAIL(old_exprs.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(new_exprs.push_back(cast_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else {/*do nothing*/} } } if (OB_SUCC(ret)) { if (select_items.empty()) { stmt->get_select_items().reset(); if (OB_FAIL(ObTransformUtils::create_dummy_select_item(*stmt, ctx_))) { LOG_WARN("failed to create dummy select item", K(ret)); } else {/*do nothing*/} } else if (OB_FAIL(stmt->get_select_items().assign(select_items))) { LOG_WARN("failed to assign to select items.", K(ret)); } } } return ret; } int ObTransformPreProcess::replace_aggr_exprs_in_select_and_having( ObRawExpr *&expr, ObIArray &groupby_exprs, ObIArray &rollup_exprs, ObIArray &aggr_items, ObIArray &groupby_exprs_list, int64_t cur_index, ObIArray &old_exprs, ObIArray &new_exprs, ObRelIds &rel_ids, int64_t origin_groupby_num /*default -1*/, bool using_rel_ids/*default true*/) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(expr)); } else if (expr->get_expr_type() == T_FUN_GROUPING && OB_FAIL(calc_grouping_in_grouping_sets(expr, groupby_exprs, rollup_exprs, aggr_items, old_exprs, new_exprs, rel_ids, using_rel_ids))) { LOG_WARN("fail to calculate grouping"); } else if (expr->get_expr_type() == T_FUN_GROUPING_ID && OB_FAIL(calc_grouping_id_in_grouping_sets(expr, groupby_exprs, rollup_exprs, aggr_items, old_exprs, new_exprs, rel_ids, using_rel_ids))) { LOG_WARN("fail to calculate grouping_id"); } else if (expr->get_expr_type() == T_FUN_GROUP_ID && OB_FAIL(calc_group_id_in_grouping_sets(expr, groupby_exprs, rollup_exprs, aggr_items, groupby_exprs_list, cur_index, old_exprs, new_exprs, rel_ids, origin_groupby_num, using_rel_ids))) { LOG_WARN("fail to calculate group_id"); } else { //do nothing. } return ret; } int ObTransformPreProcess::calc_grouping_in_grouping_sets( ObRawExpr *&expr, ObIArray &groupby_exprs, ObIArray &rollup_exprs, ObIArray &aggr_items, ObIArray &old_exprs, ObIArray &new_exprs, ObRelIds &rel_ids, bool using_rel_ids/*default true*/) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || expr->get_expr_type() != T_FUN_GROUPING) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null expr"); } else if (OB_UNLIKELY(expr->get_param_count() != 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(*expr), K(ret)); } else if (ObOptimizerUtil::find_item(groupby_exprs, expr->get_param_expr(0)) || ObOptimizerUtil::find_item(rollup_exprs, expr->get_param_expr(0))) { /*do nothing*/ } else { ObConstRawExpr *one_expr = NULL; ObSysFunRawExpr *cast_expr = NULL; if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, ObIntType, 1, one_expr))) { LOG_WARN("failed to build const int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::create_cast_expr(*ctx_->expr_factory_, one_expr, expr->get_result_type(), cast_expr, ctx_->session_info_))) { LOG_WARN("create cast expr failed", K(ret)); } else if (OB_FAIL(cast_expr->add_flag(IS_INNER_ADDED_EXPR))) { LOG_WARN("failed to add flag", K(ret)); } else if (OB_FAIL(old_exprs.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (using_rel_ids && OB_FAIL(rel_ids.add_members2(expr->get_relation_ids()))) { LOG_WARN("failed to get relation ids", K(ret)); } else if (OB_FAIL(new_exprs.push_back(cast_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::remove_item(aggr_items, static_cast(expr)))) { LOG_WARN("failed to remove item", K(ret)); } else { if (!using_rel_ids) { expr = cast_expr; } } } return ret; } /*grouping sets is tranformed into union all, so the grouping_id function must finish in transformer. *grouping_id function in stmt without rollup is done here. *select grouping_id(c1) from t1 group by grouping sets(c1,c2) will be transformed to *select {new_value1} from t1 group by c1 UNION ALL select {new_value2} from t1 group by c2. * new value is a const value we have calculated in the following function. * here new_value1 is 0, and new_value2 is 1. So the stmt is: * select 0 from t1 group by c1 UNION ALL select 1 from t1 group by c2; */ int ObTransformPreProcess::calc_grouping_id_in_grouping_sets( ObRawExpr *&expr, ObIArray &groupby_exprs, ObIArray &rollup_exprs, ObIArray &aggr_items, ObIArray &old_exprs, ObIArray &new_exprs, ObRelIds &rel_ids, bool using_rel_ids/*default true*/) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || expr->get_expr_type() != T_FUN_GROUPING_ID) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null expr"); } else if (OB_UNLIKELY(expr->get_param_count() == 0)) { ret = OB_INVALID_ARGUMENT_NUM; LOG_WARN("invalid number of argument", K(ret)); } else if (rollup_exprs.count() != 0) { // do nothing. for stmt that has rollup, the grouping_id is done in executor. } else { uint64_t new_value = 0; for (int64_t expr_idx = 0; expr_idx < expr->get_param_count(); expr_idx++) { if (ObOptimizerUtil::find_item(groupby_exprs, expr->get_param_expr(expr_idx))) { new_value = new_value << 1; } else { new_value = new_value << 1; new_value++; } } ObConstRawExpr *int_expr = NULL; ObSysFunRawExpr *cast_expr = NULL; if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, ObIntType, new_value, int_expr))) { LOG_WARN("failed to build const int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::create_cast_expr(*ctx_->expr_factory_, int_expr, expr->get_result_type(), cast_expr, ctx_->session_info_))) { LOG_WARN("create cast expr failed", K(ret)); } else if (OB_FAIL(cast_expr->add_flag(IS_INNER_ADDED_EXPR))) { LOG_WARN("failed to add flag", K(ret)); } else if (OB_FAIL(old_exprs.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (using_rel_ids && OB_FAIL(rel_ids.add_members2(expr->get_relation_ids()))) { LOG_WARN("failed to get relation ids", K(ret)); } else if (OB_FAIL(new_exprs.push_back(cast_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::remove_item(aggr_items, static_cast(expr)))) { LOG_WARN("failed to remove item", K(ret)); } else { if (!using_rel_ids) { expr = cast_expr; } } } return ret; } /* since OB's grouping sets will be expanded to UNION ALL. We have to calculate the group_id() here * rather than the executor. * select group_id() from t1 group by grouping sets (c1,c2); will first be transformed to * select group_id() from t1 group by c1 UNION ALL select group_id() from t1 group by c2; * and than be transformed to * select {duplicated_groupby_num1} from t1 group by c1 UNION ALL select {duplicated_groupby_num2} from t1 group by c2; * duplicated_groupby_num is a const value that we have calculated in the following function * * @brief * @param groupby_exprs_list: store all previous sub stmt's groupby exprs. * @param origin_groupby_num: groupby_exprs'number in origin stmt. * * we traversal the groupby_exprs_list from 0 to cur_index to find out how many sub stmts have same groupby_exprs will * current sub stmt. */ int ObTransformPreProcess::calc_group_id_in_grouping_sets( ObRawExpr *&expr, ObIArray &groupby_exprs, ObIArray &rollup_exprs, ObIArray &aggr_items, ObIArray &groupby_exprs_list, int64_t cur_index, ObIArray &old_exprs, ObIArray &new_exprs, ObRelIds &rel_ids, int64_t origin_groupby_num /*default -1*/, bool using_rel_ids/*default true*/) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || expr->get_expr_type() != T_FUN_GROUP_ID) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null expr"); } else if (OB_UNLIKELY(expr->get_param_count() != 0)) { ret = OB_INVALID_ARGUMENT_NUM; LOG_WARN("invalid number of argument", K(ret)); } else if (rollup_exprs.count() == 0) { int64_t duplicated_groupby_num = 0; for (int64_t i = 0; i < cur_index; i++) { bool match = true; for(int64_t j = origin_groupby_num; match && j < groupby_exprs.count(); j++) { if (ObOptimizerUtil::find_item(groupby_exprs_list.at(i).groupby_exprs_, groupby_exprs.at(j))) { } else { match = false; } } for (int64_t j = 0; match && j< groupby_exprs_list.at(i).groupby_exprs_.count(); j++) { if (ObOptimizerUtil::find_item(groupby_exprs, groupby_exprs_list.at(i).groupby_exprs_.at(j))) { } else { match = false; } } if (match) { //if match inc the duplciated count. duplicated_groupby_num++; } } // the group id is duplicated_groupby_num; ObConstRawExpr *int_expr = NULL; ObSysFunRawExpr *cast_expr = NULL; if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, ObIntType, duplicated_groupby_num, int_expr))) { LOG_WARN("failed to build const int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::create_cast_expr(*ctx_->expr_factory_, int_expr, expr->get_result_type(), cast_expr, ctx_->session_info_))) { LOG_WARN("create cast expr failed", K(ret)); } else if (OB_FAIL(cast_expr->add_flag(IS_INNER_ADDED_EXPR))) { LOG_WARN("failed to add flag", K(ret)); } else if (OB_FAIL(old_exprs.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (using_rel_ids && OB_FAIL(rel_ids.add_members2(expr->get_relation_ids()))) { LOG_WARN("failed to get relation ids", K(ret)); } else if (OB_FAIL(new_exprs.push_back(cast_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::remove_item(aggr_items, static_cast(expr)))) { LOG_WARN("failed to remove item", K(ret)); } else { if (!using_rel_ids) { expr = cast_expr; } } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("group_id doesn't support coexisting grouping sets and rollup", K(ret)); } return ret; } int ObTransformPreProcess::extract_select_expr_and_replace_expr( ObRawExpr *expr, ObIArray &groupby_exprs, ObIArray &rollup_exprs, ObIArray &aggr_items, ObIArray &groupby_exprs_list, int64_t cur_index, ObIArray &select_items, ObIArray &old_exprs, ObIArray &new_exprs, ObRelIds &rel_ids, int64_t origin_groupby_num /* = -1 */) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(ctx_)); } else if (expr->is_aggr_expr() || ObOptimizerUtil::find_item(groupby_exprs, expr) || ObOptimizerUtil::find_item(rollup_exprs, expr)) { if (!is_expr_in_select_item(select_items, expr)) { SelectItem select_item; select_item.expr_ = expr; select_item.expr_name_ = expr->get_expr_name(); select_item.alias_name_ = expr->get_expr_name(); if (OB_FAIL(select_items.push_back(select_item))) { LOG_WARN("failed to push back into select items.", K(ret)); } else if (OB_FAIL(replace_aggr_exprs_in_select_and_having(expr, groupby_exprs, rollup_exprs, aggr_items, groupby_exprs_list, cur_index, old_exprs, new_exprs, rel_ids, origin_groupby_num))) { LOG_WARN("failed to place aggr expr", K(ret)); } else { //do nothing } } } else if (is_select_expr_in_other_groupby_exprs(expr, groupby_exprs_list, cur_index)) { if (!ObOptimizerUtil::find_item(old_exprs, expr)) { ObRawExpr *null_expr = NULL; ObSysFunRawExpr *cast_expr = NULL; SelectItem select_item; select_item.expr_ = expr; select_item.expr_name_ = expr->get_expr_name(); select_item.alias_name_ = expr->get_expr_name(); if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx_->expr_factory_, null_expr))) { LOG_WARN("failed build null exprs.", K(ret)); } else if (OB_FAIL(ObRawExprUtils::create_cast_expr(*ctx_->expr_factory_, null_expr, expr->get_result_type(), cast_expr, ctx_->session_info_))) { LOG_WARN("create cast expr failed", K(ret)); } else if (OB_FAIL(cast_expr->add_flag(IS_INNER_ADDED_EXPR))) { LOG_WARN("failed to add flag", K(ret)); } else if (OB_FAIL(old_exprs.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(rel_ids.add_members2(expr->get_relation_ids()))) { LOG_WARN("failed to get relation ids", K(ret)); } else if (OB_FAIL(new_exprs.push_back(cast_expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(select_items.push_back(select_item))) { LOG_WARN("failed to push back into select items.", K(ret)); } else {/*do nothing*/} } } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(extract_select_expr_and_replace_expr(expr->get_param_expr(i), groupby_exprs, rollup_exprs, aggr_items, groupby_exprs_list, cur_index, select_items, old_exprs, new_exprs, rel_ids, origin_groupby_num)))) { LOG_WARN("failed to extract select expr and replace expr", K(ret)); } } } return ret; } int ObTransformPreProcess::replace_select_and_having_exprs(ObSelectStmt *select_stmt, ObIArray &old_exprs, ObIArray &new_exprs, ObIArray &groupby_exprs_list, int64_t cur_index/*default -1*/, int64_t origin_groupby_num/*default -1*/) { int ret = OB_SUCCESS; if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(select_stmt)); } else { //replace select expr for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_select_item_size(); ++i) { SelectItem &select_item = select_stmt->get_select_item(i); if (OB_ISNULL(select_item.expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(select_item.expr_)); } else if (OB_FAIL(replace_stmt_special_exprs(select_stmt, select_item.expr_, old_exprs, new_exprs, groupby_exprs_list, false, cur_index, origin_groupby_num))) { LOG_WARN("failed to replace exception aggr exprs", K(ret)); } } //replace having expr into null if (OB_SUCC(ret)) { ObIArray &having_exprs = select_stmt->get_having_exprs(); for (int64_t i = 0; OB_SUCC(ret) && i < having_exprs.count(); ++i) { if (OB_ISNULL(having_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(having_exprs.at(i))); } else if (OB_FAIL(replace_stmt_special_exprs(select_stmt, having_exprs.at(i), old_exprs, new_exprs, groupby_exprs_list, true, cur_index, origin_groupby_num))) { LOG_WARN("failed to replace exception aggr exprs", K(ret)); } } } } return ret; } bool ObTransformPreProcess::is_select_expr_in_other_groupby_exprs( ObRawExpr *expr, ObIArray &groupby_exprs_list, int64_t cur_index) { bool is_true = false; for (int64_t i = 0; !is_true && i < groupby_exprs_list.count(); ++i) { if (i == cur_index) { /*do nothing */ } else { is_true = ObOptimizerUtil::find_equal_expr(groupby_exprs_list.at(i).groupby_exprs_, expr); } } return is_true; } bool ObTransformPreProcess::is_expr_in_select_item(ObIArray &select_items, ObRawExpr *expr) { bool is_true = false; for (int64_t i = 0; !is_true && i < select_items.count(); ++i) { is_true = (select_items.at(i).expr_ == expr); } return is_true; } int ObTransformPreProcess::replace_stmt_special_exprs(ObSelectStmt *select_stmt, ObRawExpr *&expr, ObIArray &old_exprs, ObIArray &new_exprs, ObIArray &groupby_exprs_list, bool ignore_const/*default false*/, int64_t cur_index/*default -1*/, int64_t origin_groupby_num/*default -1*/) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(expr)); } else if (ignore_const && expr->is_const_expr()) { /*do nothing*/ } else if (ObOptimizerUtil::find_item(select_stmt->get_group_exprs(), expr) || ObOptimizerUtil::find_item(select_stmt->get_rollup_exprs(), expr)) { /*do nothing*/ } else { int64_t idx = -1; ObRelIds rel_ids; if (!ObOptimizerUtil::find_item(old_exprs, expr, &idx)) { if (expr->is_aggr_expr()) { if (OB_FAIL(replace_aggr_exprs_in_select_and_having(expr, select_stmt->get_group_exprs(), select_stmt->get_rollup_exprs(), select_stmt->get_aggr_items(), groupby_exprs_list, cur_index, old_exprs, new_exprs, rel_ids, origin_groupby_num, false))) { LOG_WARN("failed to replace aggr expr"); } } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(replace_stmt_special_exprs(select_stmt, expr->get_param_expr(i), old_exprs, new_exprs, groupby_exprs_list, ignore_const, cur_index, origin_groupby_num)))) { LOG_WARN("failed to replace exception aggr exprs", K(ret)); } else {/*do nothing */} } } } else if (OB_UNLIKELY(idx < 0 || idx >= new_exprs.count()) || OB_ISNULL(new_exprs.at(idx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid index", K(ret), K(idx), K(new_exprs.count()), K(new_exprs)); } else { expr = new_exprs.at(idx); } } return ret; } int ObTransformPreProcess::replace_with_set_stmt_view(ObSelectStmt *origin_stmt, ObSelectStmt *set_view_stmt, ObSelectStmt *&union_stmt) { int ret = OB_SUCCESS; ObSqlBitSet<> rel_ids; TableItem *view_table_item = NULL; ObSEArray old_exprs; ObSEArray new_exprs; ObSEArray temp_column_items; if (OB_ISNULL(origin_stmt) || OB_ISNULL(set_view_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("origin stmt is null", K(ret)); } else if (OB_FAIL(origin_stmt->get_from_tables(rel_ids))) { LOG_WARN("failed to get from tables.", K(ret)); } else if (FALSE_IT(origin_stmt->get_table_items().reset())) { } else if (FALSE_IT(origin_stmt->get_from_items().reset())) { } else if (OB_FAIL(ObTransformUtils::add_new_table_item(ctx_, origin_stmt, set_view_stmt, view_table_item))) { LOG_WARN("failed to add new table item.", K(ret)); } else if (OB_FAIL(origin_stmt->add_from_item(view_table_item->table_id_))) { LOG_WARN("failed to add from item", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *view_table_item, origin_stmt, new_exprs))) { LOG_WARN("failed to get select exprs from grouping sets view.", K(ret)); } else { /* do nothing. */ } for (int64_t i = 0; OB_SUCC(ret) && i < origin_stmt->get_column_size(); i++) { if (!origin_stmt->get_column_item(i)->expr_->get_relation_ids().overlap(rel_ids)) { if (OB_FAIL(temp_column_items.push_back(*origin_stmt->get_column_item(i)))) { LOG_WARN("faield to push back into column items.", K(ret)); } else { /* do nothing. */ } } else { /* do nothing. */ } } if (OB_FAIL(ret)) { } else if (OB_FAIL(origin_stmt->get_column_items().assign(temp_column_items))) { LOG_WARN("failed to assign column items.", K(ret)); } else if (OB_FAIL(extract_stmt_replace_expr(origin_stmt, old_exprs))) { LOG_WARN("failed to extract stmt replace expr", K(ret)); } else if (OB_UNLIKELY(old_exprs.count() != 0 && old_exprs.count() != new_exprs.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret), K(old_exprs), K(new_exprs)); } else { origin_stmt->get_grouping_sets_items().reset(); origin_stmt->get_multi_rollup_items().reset(); origin_stmt->get_aggr_items().reset(); origin_stmt->get_group_exprs().reset(); origin_stmt->get_rollup_exprs().reset(); origin_stmt->get_having_exprs().reset(); origin_stmt->get_table_items().reset(); if (old_exprs.count() != 0 && OB_FAIL(origin_stmt->replace_inner_stmt_expr(old_exprs, new_exprs))) { LOG_WARN("failed to replace inner stmt exprs.", K(ret)); } else if (OB_FAIL(origin_stmt->get_table_items().push_back(view_table_item))) { LOG_WARN("add table item failed", K(ret)); } else if (OB_FAIL(origin_stmt->rebuild_tables_hash())) { LOG_WARN("failed to rebuild tables hash.", K(ret)); } else if (OB_FAIL(origin_stmt->update_column_item_rel_id())) { LOG_WARN("failed to update column items rel id.", K(ret)); } else if (OB_FAIL(origin_stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalized stmt.", K(ret)); } else { union_stmt = origin_stmt; } } return ret; } int ObTransformPreProcess::extract_stmt_replace_expr(ObSelectStmt *select_stmt, ObIArray &old_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(select_stmt)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_select_item_size(); i++) { if (OB_FAIL(extract_replace_expr_from_select_expr(select_stmt->get_select_item(i).expr_, select_stmt, old_exprs))) { LOG_WARN("failed to extract replace expr from select expr", K(ret)); } } } return ret; } int ObTransformPreProcess::extract_replace_expr_from_select_expr(ObRawExpr *expr, ObSelectStmt *select_stmt, ObIArray &old_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(expr)); } else if (expr->is_aggr_expr() || ObOptimizerUtil::find_item(select_stmt->get_group_exprs(), expr) || ObOptimizerUtil::find_item(select_stmt->get_rollup_exprs(), expr) || select_stmt->is_expr_in_groupings_sets_item(expr) || select_stmt->is_expr_in_multi_rollup_items(expr)) { //here use find_equal_expr function, because same exprs in groupings set item have different ptr if (!ObOptimizerUtil::find_equal_expr(old_exprs, expr)) { if (OB_FAIL(old_exprs.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else {/*do nothing*/} } } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(extract_replace_expr_from_select_expr(expr->get_param_expr(i), select_stmt, old_exprs)))) { LOG_WARN("failed to extract replace expr from select expr", K(ret)); } else {/*do nothing*/} } } return ret; } int ObTransformPreProcess::create_set_view_stmt(ObSelectStmt *origin_stmt, ObSelectStmt *&set_view_stmt) { int ret = OB_SUCCESS; ObSelectStmt *groupby_stmt = NULL; ObSelectStmt *part_union_stmt = NULL; ObSelectStmt *temp_stmt = NULL; if (OB_ISNULL(origin_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("origin stmt is null", K(ret)); } else if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->stmt_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ctx or ctx stmt factory is null", K(ret)); } else { /* as following to create set stmt: * 1. get total group by stmt count(grouping sets + multi rollup) * 2. deep copy origin stmt; * 3. generate group by exprs and add stmt; * 4. deal with stmt other attribute: select list、aggr、column and so on; * 5. create set stmt. */ int64_t count = get_total_count_of_groupby_stmt(origin_stmt->get_grouping_sets_items(), origin_stmt->get_multi_rollup_items()); int64_t origin_groupby_num = origin_stmt->get_group_expr_size(); if (OB_UNLIKELY(count < 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret), K(count)); } else { // for grouping sets, we do the following transform. /* T_OP_ADD T_OP_ADD / \ -> / \ xxx -1 xxx T_OP_NEG \ 1 so that 1 in "select c1-1 from t1 group by grouping sets(c1,1);" share same expr. */ if (OB_FAIL(ObTransformUtils::replace_stmt_expr_with_groupby_exprs(origin_stmt, ctx_))) { LOG_WARN("failed to replace stmt expr with groupby columns", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < count; i++) { ObSEArray groupby_exprs_list; bool is_happened = false; if (OB_FAIL(ctx_->stmt_factory_->create_stmt(groupby_stmt))) { LOG_WARN("failed to create stmt from ctx.", K(ret)); } else if (OB_ISNULL(groupby_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("groupby stmt is null", K(ret)); } else if (FALSE_IT(groupby_stmt->set_query_ctx(origin_stmt->get_query_ctx()))) { } else if (OB_FAIL(groupby_stmt->deep_copy(*ctx_->stmt_factory_, *ctx_->expr_factory_, *origin_stmt))) { LOG_WARN("failed to deep copy from stmt.", K(ret)); } else if (OB_FAIL(get_groupby_exprs_list(groupby_stmt->get_grouping_sets_items(), groupby_stmt->get_multi_rollup_items(), groupby_exprs_list))) { LOG_WARN("failed to get groupby exprs list", K(ret)); } else if (OB_UNLIKELY(i >= groupby_exprs_list.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(i), K(groupby_exprs_list.count()), K(ret)); } else if (OB_FAIL(append_array_no_dup(groupby_stmt->get_group_exprs(), groupby_exprs_list.at(i).groupby_exprs_))) { LOG_WARN("failed to assign the group exprs.", K(ret)); } else { //stmt only reserve group by、having and aggr info groupby_stmt->get_order_items().reset(); groupby_stmt->set_limit_offset(NULL, NULL); groupby_stmt->set_limit_percent_expr(NULL); groupby_stmt->set_fetch_with_ties(false); groupby_stmt->set_has_fetch(false); groupby_stmt->clear_sequence(); groupby_stmt->set_select_into(NULL); groupby_stmt->get_grouping_sets_items().reset(); groupby_stmt->get_multi_rollup_items().reset(); groupby_stmt->get_window_func_exprs().reset(); ObSEArray old_exprs; ObSEArray new_exprs; if (OB_FAIL(ObTransformUtils::replace_stmt_expr_with_groupby_exprs(groupby_stmt))) { LOG_WARN("failed to replace stmt expr with groupby columns", K(ret)); } else if (OB_FAIL(create_select_list_from_grouping_sets(groupby_stmt, groupby_exprs_list, i, old_exprs, new_exprs, origin_groupby_num))) { LOG_WARN("failed to create select list from grouping sets.", K(ret)); //why not use replace_inner_stmt_expr?, see this example: //select nvl(c1,1), c1, max(c1) from t1 grouping sets(nvl(c1,1), c1); } else if (OB_FAIL(replace_select_and_having_exprs(groupby_stmt, old_exprs, new_exprs, groupby_exprs_list, i, origin_groupby_num))) { LOG_WARN("failed to replace select and having expr", K(ret)); //select c1 from t1 group by grouping sets(c1, ()); //<==> //select c1 from t1 group by c1 union all select NULL from t1 limit 1; } else if (!groupby_stmt->has_group_by() && OB_FAIL(ObTransformUtils::set_limit_expr(groupby_stmt, ctx_))) { LOG_WARN("add limit expr failed", K(ret)); } else if (!groupby_stmt->has_group_by() && OB_FAIL(eliminate_having(groupby_stmt, is_happened))) { LOG_WARN("failed to eliminate having", K(ret)); } else if (OB_FAIL(groupby_stmt->recursive_adjust_statement_id(ctx_->allocator_, ctx_->src_hash_val_, i + 1))) { LOG_WARN("failed to recursive adjust statement id", K(ret)); } else if (OB_FAIL(groupby_stmt->update_stmt_table_id(*origin_stmt))) { LOG_WARN("failed to update stmt table id.", K(ret)); } else if (OB_FAIL(groupby_stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalized stmt.", K(ret)); } else if (i >= 1) { if (OB_FAIL(ObTransformUtils::create_set_stmt(ctx_, ObSelectStmt::UNION, false, part_union_stmt, groupby_stmt, temp_stmt))) { LOG_WARN("failed to create union stmt.", K(ret)); } else if (OB_ISNULL(temp_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(temp_stmt)); } else if (FALSE_IT(temp_stmt->set_query_ctx(origin_stmt->get_query_ctx()))) { } else if (OB_FAIL(temp_stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize stmt.", K(ret)); } else { part_union_stmt = temp_stmt; } } else if (i == 0) { part_union_stmt = groupby_stmt; } else { /*do nothing.*/ } } } set_view_stmt = part_union_stmt; } } if (OB_SUCC(ret)) { ObSEArray select_exprs; /* 这里为了将union的select item命名,因为改写union之后的stmt的select item不会带名字 * create select item中会将SEL_*的命名赋值给select item。 */ if (OB_FAIL(set_view_stmt->get_select_exprs(select_exprs))) { LOG_WARN("failed to get select exprs.", K(ret)); } else if (FALSE_IT(set_view_stmt->get_select_items().reset())){ } else if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, select_exprs, set_view_stmt))) { LOG_WARN("failed to create select items.", K(ret)); } else { /*do nothing.*/} } return ret; } int64_t ObTransformPreProcess::get_total_count_of_groupby_stmt( ObIArray &grouping_sets_items, ObIArray &multi_rollup_items) { int64_t cnt_grouping_sets = 1; int64_t cnt_multi_rollup = 1; for (int64_t i = 0; i < grouping_sets_items.count(); ++i) { int64_t tmp_count = 1; ObIArray &rollup_items = grouping_sets_items.at(i).multi_rollup_items_; for (int64_t j = 0; j < rollup_items.count(); ++j) { tmp_count = tmp_count * (rollup_items.at(j).rollup_list_exprs_.count() + 1); } cnt_grouping_sets = cnt_grouping_sets * (grouping_sets_items.at(i).grouping_sets_exprs_.count() + (tmp_count > 1 ? tmp_count : 0)); } for (int64_t i = 0; i < multi_rollup_items.count(); ++i) { cnt_multi_rollup = cnt_multi_rollup * (multi_rollup_items.at(i).rollup_list_exprs_.count() + 1); } return cnt_grouping_sets * cnt_multi_rollup; } int ObTransformPreProcess::get_groupby_exprs_list(ObIArray &grouping_sets_items, ObIArray &multi_rollup_items, ObIArray &groupby_exprs_list) { int ret = OB_SUCCESS; ObSEArray grouping_sets_exprs_list; ObSEArray multi_rollup_exprs_list; if (OB_FAIL(expand_grouping_sets_items(grouping_sets_items, grouping_sets_exprs_list))) { LOG_WARN("failed to expand grouping sets items", K(ret)); } else if (OB_FAIL(expand_multi_rollup_items(multi_rollup_items, multi_rollup_exprs_list))) { LOG_WARN("failed to expand grouping sets items", K(ret)); } else if (OB_FAIL(combination_two_rollup_list(grouping_sets_exprs_list, multi_rollup_exprs_list, groupby_exprs_list))) { LOG_WARN("failed to expand grouping sets items", K(ret)); } else { LOG_TRACE("succeed to get groupby exprs list", K(grouping_sets_exprs_list), K(multi_rollup_exprs_list), K(groupby_exprs_list)); } return ret; } /*@brief,ObTransformPreProcess::expand_grouping_sets_items,Creating a complete group exprs. such as: * select c1,c2,c3,c4 from t1 group by grouping sets(c1,c2), grouping sets(c3,c4); * <==> * select c1,NULL,c3,NULL from t1 group by c1,c3 * union all * select c1,NULL,NULL,c4 from t1 group by c1,c4 * union all * select NULL,c2,c3,NULL from t1 group by c2,c3 * union all * select NULL,c2,NULL,c4 from t1 group by c2,c4; * as above example, multi grouping sets is actually grouping sets cartesian product. */ int ObTransformPreProcess::expand_grouping_sets_items( ObIArray &grouping_sets_items, ObIArray &grouping_sets_exprs) { int ret = OB_SUCCESS; int64_t total_cnt = 1; typedef ObSEArray GroupingSetsArray; SMART_VAR(GroupingSetsArray, tmp_grouping_sets_items) { for (int64_t i = 0; i < grouping_sets_items.count(); ++i) { total_cnt = total_cnt * (grouping_sets_items.at(i).grouping_sets_exprs_.count() + grouping_sets_items.at(i).multi_rollup_items_.count()); } if (OB_UNLIKELY(total_cnt < 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret), K(total_cnt), K(grouping_sets_items)); } else if (OB_FAIL(tmp_grouping_sets_items.prepare_allocate(total_cnt))) { LOG_WARN("failed to prepare allocate", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < total_cnt; ++i) { int64_t bit_count = i; int64_t index = 0; for (int64_t j = 0; OB_SUCC(ret) && j < grouping_sets_items.count(); ++j) { ObGroupingSetsItem &item = grouping_sets_items.at(j); int64_t item_count = item.grouping_sets_exprs_.count() + item.multi_rollup_items_.count(); index = bit_count % (item_count); bit_count = bit_count / (item_count); if (index < item.grouping_sets_exprs_.count()) { if (OB_FAIL(tmp_grouping_sets_items.at(i).grouping_sets_exprs_.push_back( item.grouping_sets_exprs_.at(index)))) { LOG_WARN("failed to push back item", K(ret)); } } else if (OB_UNLIKELY(index - item.grouping_sets_exprs_.count() >= item.multi_rollup_items_.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret)); } else if (OB_FAIL(tmp_grouping_sets_items.at(i).multi_rollup_items_.push_back( item.multi_rollup_items_.at(index - item.grouping_sets_exprs_.count())))) { LOG_WARN("failed to push back item", K(ret)); } else {/*do nothing*/} } } if (OB_SUCC(ret)) { for (int64_t i = 0; OB_SUCC(ret) && i < total_cnt; ++i) { ObGroupbyExpr groupby_item; for (int64_t j = 0; OB_SUCC(ret) && j < tmp_grouping_sets_items.at(i).grouping_sets_exprs_.count(); ++j) { if (OB_FAIL(append(groupby_item.groupby_exprs_, tmp_grouping_sets_items.at(i).grouping_sets_exprs_.at(j).groupby_exprs_))) { LOG_WARN("failed to append exprs", K(ret)); } else {/*do nothing*/} } if (tmp_grouping_sets_items.at(i).multi_rollup_items_.count() > 0) { ObSEArray groupby_exprs_list; if (OB_FAIL(expand_multi_rollup_items(tmp_grouping_sets_items.at(i).multi_rollup_items_, groupby_exprs_list))) { LOG_WARN("failed to expand multi rollup items", K(ret)); } else { for (int64_t k = 0; OB_SUCC(ret) && k < groupby_exprs_list.count(); ++k) { if (OB_FAIL(append(groupby_exprs_list.at(k).groupby_exprs_, groupby_item.groupby_exprs_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(grouping_sets_exprs.push_back(groupby_exprs_list.at(k)))) { LOG_WARN("failed to push back groupby exprs", K(ret)); } else {/*do nothing*/} } } } else if (OB_FAIL(grouping_sets_exprs.push_back(groupby_item))) { LOG_WARN("failed to push back item", K(ret)); } else {/*do nothing*/} } } } } return ret; } int ObTransformPreProcess::expand_multi_rollup_items( ObIArray &multi_rollup_items, ObIArray &rollup_list_exprs) { int ret = OB_SUCCESS; ObSEArray result_rollup_list_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < multi_rollup_items.count(); ++i) { ObMultiRollupItem &multi_rollup_item = multi_rollup_items.at(i); ObSEArray tmp_rollup_list_exprs; ObGroupbyExpr empty_item; if (OB_FAIL(tmp_rollup_list_exprs.push_back(empty_item))) { LOG_WARN("failed to push back item", K(ret)); } else { for (int64_t j = 0; OB_SUCC(ret) && j < multi_rollup_item.rollup_list_exprs_.count(); ++j) { ObGroupbyExpr item; if (OB_FAIL(append(item.groupby_exprs_, tmp_rollup_list_exprs.at(j).groupby_exprs_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(append(item.groupby_exprs_, multi_rollup_item.rollup_list_exprs_.at(j).groupby_exprs_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(tmp_rollup_list_exprs.push_back(item))) { LOG_WARN("failed to push back item", K(ret)); } else {/*do nothing*/} } if (OB_SUCC(ret)) { if (OB_FAIL(combination_two_rollup_list(result_rollup_list_exprs, tmp_rollup_list_exprs, rollup_list_exprs))) { LOG_WARN("failed to combination two rollup list", K(ret)); } else if (OB_FAIL(result_rollup_list_exprs.assign(rollup_list_exprs))) { LOG_WARN("failed to assign exprs", K(ret)); } else {/*do nothing*/} } } } return ret; } int ObTransformPreProcess::combination_two_rollup_list(ObIArray &rollup_list_exprs1, ObIArray &rollup_list_exprs2, ObIArray &rollup_list_exprs) { int ret = OB_SUCCESS; rollup_list_exprs.reset(); if (rollup_list_exprs1.count() == 0 && rollup_list_exprs2.count() > 0) { if (OB_FAIL(append(rollup_list_exprs, rollup_list_exprs2))) { LOG_WARN("failed to append exprs", K(ret)); } else {/*do nothing*/} } else if (rollup_list_exprs1.count() > 0 && rollup_list_exprs2.count() == 0) { if (OB_FAIL(append(rollup_list_exprs, rollup_list_exprs1))) { LOG_WARN("failed to append exprs", K(ret)); } else {/*do nothing*/} } else { for (int64_t i = 0; OB_SUCC(ret) && i < rollup_list_exprs1.count(); ++i) { for (int64_t j = 0; OB_SUCC(ret) && j < rollup_list_exprs2.count(); ++j) { ObGroupbyExpr item; if (OB_FAIL(append(item.groupby_exprs_, rollup_list_exprs1.at(i).groupby_exprs_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(append(item.groupby_exprs_, rollup_list_exprs2.at(j).groupby_exprs_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(rollup_list_exprs.push_back(item))) { LOG_WARN("failed to push back item", K(ret)); } else {/*do nothing*/} } } } return ret; } int ObTransformPreProcess::transform_for_hierarchical_query(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param is null", K(ret)); } else if (stmt->is_hierarchical_query()) { ObSelectStmt *select_stmt = static_cast(stmt); TableItem *table = NULL; //connect by视图分离 if (OB_FAIL(stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize stmt", K(ret)); } else if (OB_FAIL(create_connect_by_view(*select_stmt))) { LOG_WARN("failed to create connect by view", K(ret)); } else if (OB_UNLIKELY(select_stmt->get_table_size() != 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect table size after create connect by view", K(select_stmt->get_table_size()), K(ret)); } else if (OB_ISNULL(table = select_stmt->get_table_item(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_UNLIKELY(!table->is_generated_table())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expect generated table after create connect by view", K(ret)); } else if (OB_ISNULL(table->ref_query_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null ref query", K(ret)); } else if (OB_FAIL(create_and_mock_join_view(*table->ref_query_))) { LOG_WARN("failed to transform from item", K(ret)); } else { trans_happened = true; } } return ret; } class ReplaceRownumRowidExpr : public ObIRawExprReplacer { public: ReplaceRownumRowidExpr(ObSelectStmt *stmt) : view_stmt_(stmt) {} virtual 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("old expr is null", K(ret)); } else if (old_expr->has_flag(IS_ROWNUM)) { if (OB_FAIL(ObRawExprUtils::build_rownum_expr(expr_factory, new_expr))) { LOG_WARN("failed to build rownum expr", K(ret)); } else if (OB_ISNULL(new_expr) || OB_ISNULL(view_stmt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to build new expr", K(ret), K(new_expr), K(view_stmt_)); } else if (OB_FAIL(view_stmt_->get_pseudo_column_like_exprs().push_back(new_expr))) { LOG_WARN("failed to add rownum expr into view stmt", K(ret)); } } else if (old_expr->get_expr_type() == T_FUN_SYS_CALC_UROWID) { if (OB_FAIL(ObRawExprCopier::copy_expr_node(expr_factory, old_expr, new_expr))) { LOG_WARN("failed to copy calc urowid expr", K(ret)); } else if (OB_ISNULL(new_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to build new calc rowid expr", K(ret)); } } return ret; } ObSelectStmt *view_stmt_; }; int ObTransformPreProcess::create_connect_by_view(ObSelectStmt &stmt) { int ret = OB_SUCCESS; //把层次查询相关的运算全都封装在view内部 ObSelectStmt* view_stmt = NULL; ObStmtFactory *stmt_factory = NULL; ObRawExprFactory *expr_factory = NULL; ObSQLSessionInfo *session_info = NULL; //connect by view需要投影出来的表达式 ObSEArray select_list; //LEVEL、CONNECT_BY_ISLEAF、CONNECT_BY_ISCYCLE //CONNECT_BY_ROOT、PRIOR、CONNECT_BY_PATH表达式 ObSEArray connect_by_related_exprs; if (OB_ISNULL(ctx_) || OB_ISNULL(session_info = ctx_->session_info_) || OB_ISNULL(stmt_factory = ctx_->stmt_factory_) || OB_ISNULL(expr_factory = ctx_->expr_factory_) || OB_ISNULL(ctx_->allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(stmt_factory), K(expr_factory), K(stmt), K(ret)); } else if (OB_FAIL(stmt_factory->create_stmt(view_stmt))) { LOG_WARN("failed to create stmt", K(ret)); } else if (OB_FAIL(view_stmt->ObDMLStmt::assign(stmt))) { LOG_WARN("failed to assign stmt", K(ret)); } else if (OB_FAIL(view_stmt->adjust_statement_id(ctx_->allocator_, ctx_->src_qb_name_, ctx_->src_hash_val_))) { LOG_WARN("failed to adjust statement id", K(ret)); } else { view_stmt->set_stmt_type(stmt::T_SELECT); /*in: https://code.aone.alibaba-inc.com/oceanbase/oceanbase/codereview/7518289 ObDMLStmt::assign won't assign has_prior/order_siblings/is_hierarchical_query. So we need to set it manually. */ view_stmt->set_has_prior(stmt.has_prior()); view_stmt->set_order_siblings(stmt.is_order_siblings()); view_stmt->set_hierarchical_query(stmt.is_hierarchical_query()); // 1. handle table, columns, from // dml_stmt: from table, semi table, joined table stmt.get_semi_infos().reuse(); stmt.get_column_items().reuse(); stmt.get_part_exprs().reset(); stmt.get_check_constraint_items().reset(); stmt.set_hierarchical_query(false); //prior相关表达式放在视图内计算 stmt.set_has_prior(false); if (stmt.is_order_siblings()) { //order by siblings需要放到视图内计算 stmt.get_order_items().reset(); stmt.set_order_siblings(false); } else { //普通order by需要在层次查询完再计算 } } // 2. handle where conditions if (OB_SUCC(ret)) { ObSEArray join_conds; ObSEArray other_conds; if (OB_FAIL(classify_join_conds(stmt, join_conds, other_conds))) { LOG_WARN("failed to classify join conditions", K(ret)); } else if (OB_FAIL(stmt.get_condition_exprs().assign(other_conds))) { LOG_WARN("failed to assign rownum conditions", K(ret)); } else if (OB_FAIL(view_stmt->get_condition_exprs().assign(join_conds))) { LOG_WARN("failed to assign normal conditions", K(ret)); } else { stmt.reset_table_items(); stmt.get_joined_tables().reuse(); stmt.clear_from_items(); if (OB_FAIL(stmt.rebuild_tables_hash())) { LOG_WARN("failed to rebuild tables hash", K(ret)); } } } // 3. handle clauses processed by the upper_stmt if (OB_SUCC(ret)) { // consider following parts: // select: group-by, rollup, select subquery, window function, distinct, sequence, // order by, limit, select into, connect by if (!view_stmt->is_order_siblings()) { //普通的order by需要在上层stmt计算 view_stmt->get_order_items().reset(); } else { //sibling order在层次查询内部计算 } view_stmt->set_limit_offset(NULL, NULL); view_stmt->set_limit_percent_expr(NULL); view_stmt->set_fetch_with_ties(false); view_stmt->set_has_fetch(false); view_stmt->clear_sequence(); view_stmt->set_select_into(NULL); view_stmt->get_pseudo_column_like_exprs().reset(); //填充层次查询信息 view_stmt->set_hierarchical_query(true); view_stmt->set_nocycle(stmt.is_nocycle()); ObRawExprCopier copier(*expr_factory); ReplaceRownumRowidExpr replacer(view_stmt); if (OB_FAIL(copier.copy_on_replace(stmt.get_start_with_exprs(), view_stmt->get_start_with_exprs(), &replacer))) { LOG_WARN("failed to generate start with expr", K(ret)); } else if (OB_FAIL(copier.copy_on_replace(stmt.get_connect_by_exprs(), view_stmt->get_connect_by_exprs(), &replacer))) { LOG_WARN("failed to copy and replace connect by expr", K(ret)); } else { stmt.get_start_with_exprs().reset(); stmt.get_connect_by_exprs().reset(); } } // 4. 处理 connect by related expr if (OB_SUCC(ret)) { //提取所有层次查询相关表达式,在层次查询内计算,然后投影出来 if (OB_FAIL(extract_connect_by_related_exprs(stmt, connect_by_related_exprs))) { LOG_WARN("failed to extract connect by related exprs", K(ret)); } } // 5. finish creating the child stmts if (OB_SUCC(ret)) { // create select list ObSEArray columns; ObSqlBitSet<> from_tables; ObSEArray shared_exprs; if (OB_FAIL(view_stmt->get_from_tables(from_tables))) { LOG_WARN("failed to get from tables", K(ret)); } else if (OB_FAIL(view_stmt->get_column_exprs(columns))) { LOG_WARN("failed to get column exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::extract_table_exprs(*view_stmt, columns, from_tables, select_list))) { LOG_WARN("failed to extract table exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::extract_shared_expr(&stmt, view_stmt, shared_exprs))) { LOG_WARN("failed to extract shared expr", K(ret)); } else if (OB_FAIL(append(select_list, shared_exprs))) { LOG_WARN("failed to append shared exprs", K(ret)); } else if (OB_FAIL(append(select_list, connect_by_related_exprs))) { LOG_WARN("failed to append connect by related exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, select_list, view_stmt))) { LOG_WARN("failed to create select items", K(ret)); } else if (OB_FAIL(view_stmt->adjust_subquery_list())) { LOG_WARN("failed to adjust subquery list", K(ret)); } else if (OB_FAIL(view_stmt->adjust_subquery_stmt_parent(&stmt, view_stmt))) { LOG_WARN("failed to adjust sbuquery stmt parent", K(ret)); } else if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(*view_stmt))) { LOG_WARN("failed to adjust pseudo column like exprs", K(ret)); } } // 6. link upper stmt and view stmt TableItem *table_item = NULL; ObSEArray columns; if (OB_SUCC(ret)) { if (OB_FAIL(ObOptimizerUtil::remove_item(stmt.get_subquery_exprs(), view_stmt->get_subquery_exprs()))) { LOG_WARN("failed to remove subqueries", K(ret)); } else if (OB_FAIL(ObTransformUtils::add_new_table_item(ctx_, &stmt, view_stmt, table_item))) { LOG_WARN("failed to add new table item", K(ret)); } else if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_FAIL(stmt.add_from_item(table_item->table_id_))) { LOG_WARN("failed to add from item", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *table_item, &stmt, columns))) { LOG_WARN("failed to create columns for view", K(ret)); } } // 7. formalize if (OB_SUCC(ret)) { stmt.get_table_items().pop_back(); //view的expr不递归替换 if (OB_FAIL(stmt.replace_inner_stmt_expr(select_list, columns))) { LOG_WARN("failed to replace inner stmt expr", K(ret)); } else if (OB_FAIL(stmt.get_table_items().push_back(table_item))) { LOG_WARN("failed to push back view table item", K(ret)); } else if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(stmt))) { LOG_WARN("failed to adjust pseudo column like exprs", K(ret)); } else if (OB_FAIL(stmt.formalize_stmt(session_info))) { LOG_WARN("failed to formalize stmt", K(ret)); } } return ret; } /** * @brief create_and_mock_join_view * 层次查询会把所有的连接运算封装到视图内部计算, * 处理时会生成两个相同的视图,第一个做个root节点 * 生成子计划,第二个作为子节点的生成子计划,在这里 * start with会预处理放入第一个视图内,其他表达式 * 引用第二个视图 */ int ObTransformPreProcess::create_and_mock_join_view(ObSelectStmt &stmt) { int ret = OB_SUCCESS; bool has_for_update = false; ObSelectStmt* left_view_stmt = NULL; ObSelectStmt* right_view_stmt = NULL; ObStmtFactory *stmt_factory = NULL; ObRawExprFactory *expr_factory = NULL; ObSQLSessionInfo *session_info = NULL; ObSEArray select_list; if (OB_ISNULL(ctx_) || OB_ISNULL(session_info = ctx_->session_info_) || OB_ISNULL(stmt_factory = ctx_->stmt_factory_) || OB_ISNULL(expr_factory = ctx_->expr_factory_) || OB_ISNULL(ctx_->allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(stmt_factory), K(expr_factory), K(stmt), K(ret)); } else if (OB_FAIL(stmt_factory->create_stmt(left_view_stmt))) { LOG_WARN("failed to create stmt", K(ret)); } else if (OB_FAIL(stmt_factory->create_stmt(right_view_stmt))) { LOG_WARN("failed to create stmt", K(ret)); } else if (OB_FAIL(left_view_stmt->ObDMLStmt::assign(stmt))) { LOG_WARN("failed to assign stmt", K(ret)); } else if (OB_FAIL(left_view_stmt->adjust_statement_id(ctx_->allocator_, ctx_->src_qb_name_, ctx_->src_hash_val_))) { LOG_WARN("failed to adjust statement id", K(ret)); } else { has_for_update = stmt.has_for_update(); left_view_stmt->set_stmt_type(stmt::T_SELECT); left_view_stmt->set_has_prior(stmt.has_prior()); left_view_stmt->set_order_siblings(stmt.is_order_siblings()); left_view_stmt->set_hierarchical_query(stmt.is_hierarchical_query()); // 1. handle table, columns, from // dml_stmt: from table, semi table, joined table stmt.reset_table_items(); stmt.get_joined_tables().reuse(); stmt.get_semi_infos().reuse(); stmt.get_column_items().reuse(); stmt.clear_from_items(); stmt.get_part_exprs().reset(); stmt.get_check_constraint_items().reset(); if (OB_FAIL(stmt.rebuild_tables_hash())) { LOG_WARN("failed to rebuild tables hash", K(ret)); } } // 2. handle where conditions if (OB_SUCC(ret)) { if (OB_FAIL(left_view_stmt->get_condition_exprs().assign(stmt.get_condition_exprs()))) { LOG_WARN("failed to assign conditions", K(ret)); } else { stmt.get_condition_exprs().reset(); } } // 3. handle clauses processed by the upper_stmt if (OB_SUCC(ret)) { // consider following parts: // select: group-by, rollup, select subquery, window function, distinct, sequence, // order by, limit, select into, start with, connect by left_view_stmt->get_order_items().reset(); left_view_stmt->set_limit_offset(NULL, NULL); left_view_stmt->set_limit_percent_expr(NULL); left_view_stmt->set_fetch_with_ties(false); left_view_stmt->set_has_fetch(false); left_view_stmt->clear_sequence(); left_view_stmt->set_select_into(NULL); left_view_stmt->get_pseudo_column_like_exprs().reset(); left_view_stmt->get_start_with_exprs().reset(); left_view_stmt->get_connect_by_exprs().reset(); left_view_stmt->set_hierarchical_query(false); left_view_stmt->set_has_prior(false); left_view_stmt->set_order_siblings(false); } // 4. finish creating the left child stmts if (OB_SUCC(ret)) { // create select list ObSEArray columns; ObSEArray query_refs; ObSqlBitSet<> from_tables; ObSEArray shared_exprs; if (OB_FAIL(left_view_stmt->get_from_tables(from_tables))) { LOG_WARN("failed to get from tables", K(ret)); } else if (OB_FAIL(left_view_stmt->get_column_exprs(columns))) { LOG_WARN("failed to get column exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::extract_table_exprs(*left_view_stmt, columns, from_tables, select_list))) { LOG_WARN("failed to extract table exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::extract_shared_expr(&stmt, left_view_stmt, shared_exprs))) { LOG_WARN("failed to extract shared expr", K(ret)); } else if (OB_FAIL(append(select_list, shared_exprs))) { LOG_WARN("failed to append shared exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, select_list, left_view_stmt))) { LOG_WARN("failed to create select items", K(ret)); } else if (OB_FAIL(left_view_stmt->adjust_subquery_list())) { LOG_WARN("failed to adjust subquery list", K(ret)); } } // 5. copy left stmt to right stmt if (OB_SUCC(ret)) { int64_t sub_num = 1; if (OB_FAIL(right_view_stmt->deep_copy(*stmt_factory, *expr_factory, *left_view_stmt))) { LOG_WARN("failed to copy stmt", K(ret)); } else if (OB_FAIL(right_view_stmt->recursive_adjust_statement_id(ctx_->allocator_, ctx_->src_hash_val_, sub_num))) { LOG_WARN("failed to adjust statement id", K(ret)); } else if (OB_FAIL(right_view_stmt->update_stmt_table_id(*left_view_stmt))) { LOG_WARN("failed to update stmt table id", K(ret)); } } // 6. link upper stmt and view stmt TableItem *left_table_item = NULL; ObSEArray left_columns; TableItem *right_table_item = NULL; ObSEArray right_columns; if (OB_SUCC(ret)) { //为左右视图创建from item、table item if (OB_FAIL(ObTransformUtils::add_new_table_item(ctx_, &stmt, left_view_stmt, left_table_item))) { LOG_WARN("failed to add new table item", K(ret)); } else if (OB_ISNULL(left_table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_FAIL(stmt.add_from_item(left_table_item->table_id_))) { LOG_WARN("failed to add from item", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *left_table_item, &stmt, left_columns))) { LOG_WARN("failed to create columns for view", K(ret)); } else if (OB_FAIL(ObTransformUtils::add_new_table_item(ctx_, &stmt, right_view_stmt, right_table_item))) { LOG_WARN("failed to add new table item", K(ret)); } else if (OB_ISNULL(right_table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_FAIL(stmt.add_from_item(right_table_item->table_id_))) { LOG_WARN("failed to add from item", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *right_table_item, &stmt, right_columns))) { LOG_WARN("failed to create columns for copy stmt", K(ret)); } } // 7. 预处理start with exprs,放置到第一个视图的where condition //调整subquery exprs if (OB_SUCC(ret)) { ObRawExprCopier copier(*expr_factory); ReplaceRownumRowidExpr replacer(left_view_stmt); if (OB_FAIL(copier.copy_on_replace(stmt.get_start_with_exprs(), stmt.get_start_with_exprs(), &replacer))) { LOG_WARN("failed to copy on replace start with exprs", K(ret)); } else if (OB_FAIL(left_view_stmt->add_condition_exprs(stmt.get_start_with_exprs()))) { LOG_WARN("failed to push start with exprs to view", K(ret)); } else if (OB_FAIL(left_view_stmt->adjust_subquery_list())) { LOG_WARN("failed to adjust subquery list", K(ret)); } else if (OB_FAIL(left_view_stmt->adjust_subquery_stmt_parent(&stmt, left_view_stmt))) { LOG_WARN("failed to adjust sbuquery stmt parent", K(ret)); } else if (OB_FAIL(right_view_stmt->adjust_subquery_list())) { LOG_WARN("failed to adjust subquery list", K(ret)); } else if (OB_FAIL(right_view_stmt->adjust_subquery_stmt_parent(&stmt, right_view_stmt))) { LOG_WARN("failed to adjust sbuquery stmt parent", K(ret)); } else if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(*right_view_stmt))) { LOG_WARN("failed to adjust pseudo column like exprs", K(ret)); } else { stmt.get_start_with_exprs().reset(); } } // 8. 如果stmt有for update标记,需要把标记打在connect by的右侧表上, // 同时清除左侧表上的for update标记 if (OB_SUCC(ret) && has_for_update) { for (int64_t i = 0; OB_SUCC(ret) && i < left_view_stmt->get_table_size(); ++i) { TableItem *table = left_view_stmt->get_table_item(i); if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else { table->for_update_ = false; } } } // 9. do replace and formalize if (OB_SUCC(ret)) { stmt.get_table_items().pop_back(); stmt.get_table_items().pop_back(); if (OB_FAIL(ObOptimizerUtil::remove_item(stmt.get_subquery_exprs(), left_view_stmt->get_subquery_exprs()))) { LOG_WARN("failed to remove subqueries", K(ret)); } else if (OB_FAIL(stmt.replace_inner_stmt_expr(select_list, right_columns))) { LOG_WARN("failed to replace inner stmt expr", K(ret)); } else if (OB_FAIL(stmt.get_table_items().push_back(left_table_item))) { LOG_WARN("failed to push back view table item", K(ret)); } else if (OB_FAIL(stmt.get_table_items().push_back(right_table_item))) { LOG_WARN("failed to push back view table item", K(ret)); } else if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(stmt))) { LOG_WARN("failed to adjust pseudo column like exprs", K(ret)); } else if (OB_FAIL(stmt.formalize_stmt(session_info))) { LOG_WARN("failed to formalize stmt", K(ret)); } } // 10. ignore for temp table optimization if (OB_SUCC(ret)) { if (OB_FAIL(ctx_->temp_table_ignore_stmts_.push_back(left_view_stmt))) { LOG_WARN("failed to push back stmt", K(ret)); } else if (OB_FAIL(ctx_->temp_table_ignore_stmts_.push_back(right_view_stmt))) { LOG_WARN("failed to push back stmt", K(ret)); } } return ret; } int ObTransformPreProcess::classify_join_conds(ObSelectStmt &stmt, ObIArray &normal_join_conds, ObIArray &other_conds) { int ret = OB_SUCCESS; //将where condition分成普通连接条件和其他条件 //CONNECT_BY_PATH不会出现在where condition中 for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_condition_size(); ++i) { ObRawExpr *cond_expr = NULL; bool in_from_item = false; if (OB_ISNULL(cond_expr = stmt.get_condition_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("condition expr is null", K(ret)); } else if (cond_expr->has_flag(CNT_LEVEL) || cond_expr->has_flag(CNT_CONNECT_BY_ISLEAF) || cond_expr->has_flag(CNT_CONNECT_BY_ISCYCLE) || cond_expr->has_flag(CNT_CONNECT_BY_ROOT) || cond_expr->has_flag(CNT_PRIOR) || cond_expr->has_flag(CNT_SUB_QUERY)) { if (OB_FAIL(other_conds.push_back(cond_expr))) { LOG_WARN("failed to add condition expr into upper stmt", K(ret)); } } else if (OB_FAIL(is_cond_in_one_from_item(stmt, cond_expr, in_from_item))) { LOG_WARN("failed to check cond is in from item", K(ret)); } else if (!in_from_item) { //如果下推的join condition与select expr共享了sub_query expr //需要将subquery下推到view,然后构造select expr吐出 if (OB_FAIL(normal_join_conds.push_back(cond_expr))) { LOG_WARN("failed to add condition expr into join view stmt", K(ret)); } } else { //from item filter if (OB_FAIL(other_conds.push_back(cond_expr))) { LOG_WARN("failed to add condition expr into upper stmt", K(ret)); } } } return ret; } /** * 例如select * from t1 lef join t2 on xxx , t3 * where t1.c1 = t2.c1 and t2.c2 = t3.c2 * t1.c1 = t2.c1来自一个from item,t2.c2 = t3.c2来自两个from item * 所以t1.c1 = t2.c1应该在层次查询之后做,t2.c2 = t3.c2在层次查询之前做。 */ int ObTransformPreProcess::is_cond_in_one_from_item(ObSelectStmt &stmt, ObRawExpr *expr, bool &in_from_item) { int ret = OB_SUCCESS; TableItem *table = NULL; ObSqlBitSet<> table_ids; in_from_item = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (expr->get_relation_ids().is_empty()) { in_from_item = true; } int64_t N = stmt.get_from_item_size(); for (int64_t i = 0; OB_SUCC(ret) && !in_from_item && i < N; ++i) { table_ids.reuse(); FromItem &item = stmt.get_from_items().at(i); if (item.is_joined_) { table = stmt.get_joined_table(item.table_id_); } else { table = stmt.get_table_item_by_id(item.table_id_); } if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null table item", K(ret)); } else if (OB_FAIL(stmt.get_table_rel_ids(table->is_joined_table() ? *(static_cast(table)) : *table, table_ids))) { LOG_WARN("failed to get table rel ids", K(ret)); } else if (expr->get_relation_ids().is_subset(table_ids)) { in_from_item = true; } } return ret; } int ObTransformPreProcess::extract_connect_by_related_exprs(ObSelectStmt &stmt, ObIArray &special_exprs) { int ret = OB_SUCCESS; ObSEArray relation_exprs; if (OB_FAIL(stmt.get_relation_exprs(relation_exprs))) { LOG_WARN("failed to relation exprs", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < relation_exprs.count(); i++) { ObRawExpr *expr = relation_exprs.at(i); if (OB_FAIL(extract_connect_by_related_exprs(expr, special_exprs))) { LOG_WARN("failed to extract connect by related exprs", K(ret)); } } } return ret; } int ObTransformPreProcess::extract_connect_by_related_exprs(ObRawExpr *expr, ObIArray &special_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (T_LEVEL == expr->get_expr_type() || T_CONNECT_BY_ISLEAF == expr->get_expr_type() || T_CONNECT_BY_ISCYCLE == expr->get_expr_type() || T_OP_CONNECT_BY_ROOT == expr->get_expr_type() || T_OP_PRIOR == expr->get_expr_type() || T_FUN_SYS_CONNECT_BY_PATH == expr->get_expr_type()) { if (ObOptimizerUtil::find_item(special_exprs, expr)) { //do nothing } else if (OB_FAIL(special_exprs.push_back(expr))) { LOG_WARN("failed to push back connect by expr", K(ret)); } } else if (expr->has_flag(CNT_LEVEL) || expr->has_flag(CNT_CONNECT_BY_ISLEAF) || expr->has_flag(CNT_CONNECT_BY_ISCYCLE) || expr->has_flag(CNT_CONNECT_BY_ROOT) || expr->has_flag(CNT_PRIOR) || expr->has_flag(CNT_SYS_CONNECT_BY_PATH)) { int64_t N = expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { if (OB_FAIL(extract_connect_by_related_exprs(expr->get_param_expr(i), special_exprs))) { LOG_WARN("failed to extract connect by eprs", K(ret)); } } } else { //do nothing } return ret; } uint64_t ObTransformPreProcess::get_real_tid(uint64_t tid, ObSelectStmt &stmt) { uint64_t real_tid = OB_INVALID_ID; for (int64_t i = 0; i < stmt.get_table_size(); i ++) { TableItem *table_item = stmt.get_table_item(i); if (tid == table_item->table_id_) { real_tid = table_item->ref_id_; break; } } return real_tid; } int ObTransformPreProcess::eliminate_having(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL pointer", K(stmt), K(ret)); } else if (!stmt->is_select_stmt()) { // do nothing } else { ObSelectStmt *select_stmt = static_cast(stmt); if (!select_stmt->has_group_by() && !select_stmt->get_having_exprs().empty()) { if (OB_FAIL(append(select_stmt->get_condition_exprs(), select_stmt->get_having_exprs()))) { LOG_WARN("failed to append condition exprs", K(ret)); } else { select_stmt->get_having_exprs().reset(); trans_happened = true; } } } return ret; } int ObTransformPreProcess::replace_func_is_serving_tenant(ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid parameter or data member", K(ret), K(stmt), K(ctx_)); } else if (OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session info is NULL", K(ret)); } else { common::ObIArray &cond_exprs = stmt->get_condition_exprs(); for (int64_t i = 0; OB_SUCC(ret) && i < cond_exprs.count(); ++i) { if (OB_ISNULL(cond_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cond expr is NULL", K(ret), K(i), K(cond_exprs)); } else if (OB_FAIL(recursive_replace_func_is_serving_tenant(*stmt, cond_exprs.at(i), trans_happened))) { // 此处必须直接传cond_exprs.at(i),因为可能需要修改它的值 LOG_WARN("fail to recursive replace functino is_serving_tenant", K(ret), K(i), K(*cond_exprs.at(i))); } else if (OB_ISNULL(cond_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null pointer", K(ret)); } else if (OB_FAIL(cond_exprs.at(i)->formalize(ctx_->session_info_))) { LOG_WARN("failed to formalize expr", K(ret), K(i), K(*cond_exprs.at(i))); } else {/*do nothing*/} } if (OB_SUCC(ret)) { if (OB_FAIL(stmt->pull_all_expr_relation_id_and_levels())) { LOG_WARN("pull stmt all expr relation ids failed", K(ret)); } } } return ret; } int ObTransformPreProcess::recursive_replace_func_is_serving_tenant(ObDMLStmt &stmt, ObRawExpr *&cond_expr, bool &trans_happened) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(cond_expr) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("cond_expr is NULL", K(cond_expr), K_(ctx)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("failed to check stack overflow", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < cond_expr->get_param_count(); ++i) { // 此处必须直接传cond_expr->get_param_expr(i),因为可能需要修改它的值 if (OB_FAIL(SMART_CALL(recursive_replace_func_is_serving_tenant(stmt, cond_expr->get_param_expr(i), trans_happened)))) { LOG_WARN("fail to recursive replace_func_is_serving_tenant", K(ret)); } } // 如果是函数is_serving_tenant并且tenant_id为常量表达式,则改写为(svr_ip, svr_port) in ((ip1, // port1), (ip2, port2), ...)的形式 // 如果当前租户是系统租户,直接返回true if (OB_SUCC(ret) && T_FUN_IS_SERVING_TENANT == cond_expr->get_expr_type()) { int64_t tenant_id_int64 = -1; if (OB_UNLIKELY(3 != cond_expr->get_param_count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("T_FUN_IS_SERVING_TENANT must has 3 params", K(ret), K(cond_expr->get_param_count()), K(*cond_expr)); } else if (OB_ISNULL(cond_expr->get_param_expr(0)) || OB_ISNULL(cond_expr->get_param_expr(1)) || OB_ISNULL(cond_expr->get_param_expr(2))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("T_FUN_IS_SERVING_TENANT has a null param", K(ret), K(cond_expr->get_param_expr(0)), K(cond_expr->get_param_expr(1)), K(cond_expr->get_param_expr(2)), K(*cond_expr)); } else if (!cond_expr->get_param_expr(2)->is_static_scalar_const_expr()) { } else if (OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ctx_ is NULL", K(ret)); } else if (OB_ISNULL(ctx_->exec_ctx_) || OB_ISNULL(ctx_->session_info_) || OB_ISNULL(ctx_->allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid argument", K(ret), K(ctx_->exec_ctx_), K(ctx_->session_info_), K(ctx_->allocator_)); } else if (OB_FAIL(calc_const_raw_expr_and_get_int(stmt, cond_expr->get_param_expr(2), *ctx_->exec_ctx_, ctx_->session_info_, *ctx_->allocator_, tenant_id_int64))) { LOG_WARN("fail to calc tenant id", K(ret), K(*cond_expr->get_param_expr(2))); } else if (OB_UNLIKELY(tenant_id_int64 <= 0)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("tenant id is <= 0", K(ret), K(tenant_id_int64)); } else { uint64_t tenant_id = static_cast(tenant_id_int64); // if current tenant is sys, return true directly if (OB_SYS_TENANT_ID == tenant_id) { ObConstRawExpr *true_expr = NULL; if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_VARCHAR, true_expr))) { LOG_WARN("create const expr failed", K(ret)); } else if (OB_ISNULL(true_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("true expr is NULL", K(ret)); } else { ObObj true_obj; true_obj.set_bool(true); true_expr->set_value(true_obj); cond_expr = true_expr; trans_happened = true; } } else { ObUnitInfoGetter ui_getter; ObArray servers; if (OB_ISNULL(ctx_->exec_ctx_->get_sql_proxy())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sql proxy from exec_ctx_ is NULL", K(ret)); } else if (OB_FAIL(ui_getter.init(*ctx_->exec_ctx_->get_sql_proxy(), &GCONF))) { LOG_WARN("fail to init ObUnitInfoGetter", K(ret)); } else if (OB_FAIL(ui_getter.get_tenant_servers(tenant_id, servers))) { LOG_WARN("fail to get servers of a tenant", K(ret)); } else if (0 == servers.count()) { // 没找到该tenant_id对应的observer,可能该tenant_id是非法的,为了能通过query // range,将这里改成where false的形式,这样虽然优化器会返回所有partition,但是 // ObPhyOperator中会处理好false的条件,不会进行多余的查询 ObConstRawExpr *false_expr = NULL; if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_VARCHAR, false_expr))) { LOG_WARN("create varchar expr failed", K(ret)); } else if (OB_ISNULL(false_expr)){ ret = OB_ERR_UNEXPECTED; LOG_WARN("false expr is NULL", K(ret)); } else { ObObj false_obj; false_obj.set_bool(false); false_expr->set_value(false_obj); cond_expr = false_expr; trans_happened = true; } } else { ObOpRawExpr *in_op = NULL; ObOpRawExpr *left_row_op = NULL; ObOpRawExpr *right_row_op = NULL; if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_OP_IN, in_op))) { LOG_WARN("create in operator expr", K(ret)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_OP_ROW, left_row_op))) { LOG_WARN("create left row operator failed", K(ret)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_OP_ROW, right_row_op))) { LOG_WARN("create right row op failed", K(ret)); } else if (OB_ISNULL(in_op) || OB_ISNULL(left_row_op) || OB_ISNULL(right_row_op)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("operator is null", K(in_op), K(left_row_op), K(right_row_op)); } else {/*do nothing*/} for (int64_t i = 0; OB_SUCC(ret) && i < servers.count(); ++i) { ObAddr server = servers.at(i); ObOpRawExpr *row_op = NULL; ObConstRawExpr *ip_expr = NULL; ObConstRawExpr *port_expr = NULL; char *ip_buf = NULL; ObObj ip_obj; ObObj port_obj; if (OB_UNLIKELY(NULL == (ip_buf = static_cast(ctx_->allocator_->alloc(OB_MAX_SERVER_ADDR_SIZE))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("fail to alloc ip str buffer", K(ret), LITERAL_K(OB_MAX_SERVER_ADDR_SIZE)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_OP_ROW, row_op))) { LOG_WARN("create row operator expr failed", K(ret)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_VARCHAR, ip_expr))) { LOG_WARN("create ip operator expr failed", K(ret)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_INT, port_expr))) { LOG_WARN("create port expr failed", K(ret)); } else if (OB_UNLIKELY(!server.ip_to_string(ip_buf, OB_MAX_SERVER_ADDR_SIZE))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("convert server addr to ip failed", K(ret), K(i), K(server)); } else if (OB_ISNULL(row_op) || OB_ISNULL(ip_expr) || OB_ISNULL(port_expr)) { LOG_WARN("expr is null", K(row_op), K(ip_expr), K(port_expr)); } else { ip_obj.set_varchar(ObString(ip_buf)); ip_obj.set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); ip_obj.set_collation_level(CS_LEVEL_SYSCONST); port_obj.set_int(server.get_port()); ip_expr->set_value(ip_obj); port_expr->set_value(port_obj); if (OB_FAIL(row_op->set_param_exprs(ip_expr, port_expr))) { LOG_WARN("fail to set param expr", K(ret)); } else if (OB_FAIL(right_row_op->add_param_expr(row_op))) { LOG_WARN("fail to add param expr", K(ret)); } else {/*do nothing*/} } } if (OB_SUCC(ret)) { if (OB_FAIL(left_row_op->set_param_exprs(cond_expr->get_param_expr(0), cond_expr->get_param_expr(1)))) { LOG_WARN("fail to set param expr", K(ret)); } else if (OB_FAIL(in_op->set_param_exprs(left_row_op, right_row_op))) { LOG_WARN("fail to set param expr", K(ret)); } else { cond_expr = in_op; trans_happened = true; } } } } } } } return ret; } int ObTransformPreProcess::calc_const_raw_expr_and_get_int(const ObStmt &stmt, ObRawExpr *const_expr, ObExecContext &exec_ctx, ObSQLSessionInfo *session, ObIAllocator &allocator, int64_t &result) { int ret = OB_SUCCESS; ObMySQLProxy *sql_proxy = NULL; ObPhysicalPlanCtx *plan_ctx = NULL; ObObj result_int_obj; bool got_result = false; if (OB_ISNULL(const_expr) || OB_ISNULL(session)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr or session is NULL", KP(session), KP(const_expr), K(ret)); } else if (OB_UNLIKELY(!const_expr->is_static_scalar_const_expr())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr is not const expr", K(ret), K(*const_expr)); } else if (OB_ISNULL(sql_proxy = exec_ctx.get_sql_proxy())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sql proxy is NULL", K(ret)); } else if (OB_ISNULL(plan_ctx = exec_ctx.get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("physical plan ctx is NULL", K(ret)); } else if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(ctx_->exec_ctx_, const_expr, result_int_obj, got_result, exec_ctx.get_allocator(), false))) { LOG_WARN("failed to calc const or calculable expr", K(ret)); } else if (OB_UNLIKELY(false == ob_is_integer_type(result_int_obj.get_type()))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("tenant id result must integer", K(ret), K(result_int_obj)); } else { result = result_int_obj.get_int(); } return ret; } /** * 1) select * from temp_t1 x, t2 y, temp_t3 z where ... ==> * select * from temp_t1 x, t2 y, temp_t3 z where ... AND x.__session_id = xxx and z.__session_id = xxx; * 2) update temp_t set c1 = 1 where ... ==> * update temp_t set c1 = 1 where ... AND __session_id = xxx; * 3) delete from temp_t where ... ==> * delete from temp_t where ... AND __session_id = xxx; */ int ObTransformPreProcess::transform_for_temporary_table(ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null stmt or ctx", K(ret), K(stmt), K(ctx_)); } else if (OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session info is NULL", K(ret)); } else if (/*false == ctx_->session_info_->is_inner() //内部session不附加条件, 给定的sql已经考虑过了*/ ObSQLSessionInfo::USER_SESSION == ctx_->session_info_->get_session_type()) { common::ObArray table_item_list; int64_t num_from_items = stmt->get_from_item_size(); //1, collect all table item for(int64_t i = 0; OB_SUCC(ret) && i < num_from_items; ++i) { const FromItem &from_item = stmt->get_from_item(i); if (from_item.is_joined_) { JoinedTable *joined_table_item = stmt->get_joined_table(from_item.table_id_); if (OB_FAIL(collect_all_tableitem(stmt, joined_table_item, table_item_list))) { LOG_WARN("failed to collect table item", K(ret)); } } else { TableItem *table_item = NULL; table_item = stmt->get_table_item_by_id(from_item.table_id_); if (OB_FAIL(collect_all_tableitem(stmt, table_item, table_item_list))) { LOG_WARN("failed to collect table item", K(ret)); } } } //2, for each temporary table item, add session_id = xxx filter for (int64 i = 0; OB_SUCC(ret) && i < table_item_list.count(); ++i) { TableItem *table_item = table_item_list.at(i); if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (table_item->is_basic_table()) { uint64_t table_ref_id = table_item->ref_id_; const ObTableSchema *table_schema = NULL; if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->schema_checker_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ctx_ or schema_cheker_ is NULL", K(ret), K(ctx_), K(ctx_->schema_checker_)); } else if (OB_FAIL(ctx_->schema_checker_->get_table_schema(ctx_->session_info_->get_effective_tenant_id(), table_ref_id, table_schema, table_item->is_link_table()))) { LOG_WARN("failed to get table schema", K(table_ref_id), K(ret)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table should not be null", K(table_ref_id)); } else if (table_schema->is_oracle_tmp_table()) { // 单表查询时直接添加 filter; 多表时创建 view 并在内部添加 filter TableItem *view_table = NULL; ObSelectStmt *ref_query = NULL; TableItem *child_table = NULL; if (stmt->is_single_table_stmt()) { if (OB_FAIL(add_filter_for_temporary_table(*stmt, *table_item))) { LOG_WARN("add filter for temporary table failed", K(ret)); } else { trans_happened = true; } } else if(OB_FAIL(ObTransformUtils::create_view_with_table(stmt, ctx_, table_item, view_table))) { LOG_WARN("failed to create view with table", K(ret)); } else if (!view_table->is_generated_table() || OB_ISNULL(ref_query = view_table->ref_query_) || !ref_query->is_single_table_stmt() || OB_ISNULL(child_table = ref_query->get_table_item(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected view table", K(ret), K(*view_table)); } else if (OB_FAIL(add_filter_for_temporary_table(*ref_query, *child_table))) { LOG_WARN("add filter for temporary table failed", K(ret)); } else { trans_happened = true; } } } } ObInsertStmt *ins_stmt = dynamic_cast(stmt); if (OB_SUCC(ret) && NULL != ins_stmt) { // value exprs for insert stmt is not included in relation expr array. ObIArray &value_vectors = ins_stmt->get_values_vector(); for (int64_t i = 0; OB_SUCC(ret) && i < value_vectors.count(); ++i) { ObRawExpr *expr = value_vectors.at(i); bool is_happened = false; if (OB_FAIL(transform_expr(*ctx_->expr_factory_, *ctx_->session_info_, expr, is_happened))) { LOG_WARN("transform expr failed", K(ret)); } else if(OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret)); } else { value_vectors.at(i) = expr; trans_happened |= is_happened; } } } } return ret; } //为stmt->where添加session_id = xxx int ObTransformPreProcess::add_filter_for_temporary_table(ObDMLStmt &stmt, const TableItem &table_item) { int ret = OB_SUCCESS; ObRawExpr *equal_expr = NULL; ObConstRawExpr *expr_const = NULL; ObColumnRefRawExpr *expr_col = NULL; if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->session_info_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("some parameter is NULL", K(ret), K(ctx_)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_UINT64, expr_const))) { LOG_WARN("create const raw expr failed", K(ret)); } else if (OB_ISNULL(expr_const)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(expr_col), K(expr_const), K(ret)); } else { ObObj sid_obj; ColumnItem *exist_col_item = NULL; sid_obj.set_int(ctx_->session_info_->get_sessid_for_table()); expr_const->set_value(sid_obj); if (NULL != (exist_col_item = stmt.get_column_item(table_item.table_id_, OB_HIDDEN_SESSION_ID_COLUMN_NAME))) { expr_col = exist_col_item->expr_; } else { ColumnItem column_item; ObExprResType result_type; result_type.set_int(); if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_REF_COLUMN, expr_col))) { LOG_WARN("fail to create raw expr", K(ret)); } else if (OB_ISNULL(expr_col)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr_col is null", K(expr_col), K(ret)); } else { expr_col->set_table_name(table_item.get_table_name()); expr_col->set_column_name(OB_HIDDEN_SESSION_ID_COLUMN_NAME); expr_col->set_ref_id(table_item.table_id_, OB_HIDDEN_SESSION_ID_COLUMN_ID); expr_col->set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); expr_col->set_collation_level(CS_LEVEL_SYSCONST); expr_col->set_result_type(result_type); expr_col->set_expr_level(stmt.get_current_level()); column_item.expr_ = expr_col; column_item.table_id_ = expr_col->get_table_id(); column_item.column_id_ = expr_col->get_column_id(); column_item.column_name_ = expr_col->get_column_name(); if (OB_FAIL(expr_col->add_relation_id(stmt.get_table_bit_index(table_item.table_id_)))) { LOG_WARN("failed to add relation id", K(ret)); } else if (OB_FAIL(stmt.add_column_item(column_item))) { LOG_WARN("add column item to stmt failed", K(ret)); } } } if (OB_FAIL(ret)) { //do nothing } else if (OB_FAIL(ObRawExprUtils::create_equal_expr(*(ctx_->expr_factory_), ctx_->session_info_, expr_const, expr_col, equal_expr))) { LOG_WARN("Creation of equal expr for outer stmt fails", K(ret)); } if (OB_FAIL(stmt.get_condition_exprs().push_back(equal_expr))) { LOG_WARN("failed to push back new filter", K(ret)); } else { LOG_TRACE("add new filter succeed", K(stmt.get_condition_exprs()), K(*equal_expr)); } } return ret; } //递归收集from_item中所有TableItem, 用于后续的查询改写 int ObTransformPreProcess::collect_all_tableitem(ObDMLStmt *stmt, TableItem *table_item, common::ObArray &table_item_list) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("failed to check stack overflow", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); } else { if (table_item->is_joined_table()) { JoinedTable *joined_table_item = static_cast(table_item); if (OB_FAIL(SMART_CALL(collect_all_tableitem(stmt, joined_table_item->left_table_, table_item_list)))) { LOG_WARN("failed to collect temp table item", K(ret)); } else if (OB_FAIL(SMART_CALL(collect_all_tableitem(stmt, joined_table_item->right_table_, table_item_list)))) { LOG_WARN("failed to collect temp table item", K(ret)); } } else if (table_item->is_basic_table() && OB_FAIL(add_var_to_array_no_dup(table_item_list, table_item))) { LOG_WARN("failed to push table item", K(ret)); } } return ret; } int ObTransformPreProcess::get_first_level_output_exprs( ObSelectStmt *sub_stmt, common::ObIArray& inner_aggr_exprs) { int ret = OB_SUCCESS; if (OB_ISNULL(sub_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select stmt is null", K(ret)); } else { common::ObIArray &aggr_exprs = sub_stmt->get_aggr_items(); for (int64_t i = 0; OB_SUCC(ret) && i < aggr_exprs.count(); i++) { if (OB_ISNULL(aggr_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr of aggr expr is null", K(ret)); } else if (aggr_exprs.at(i)->is_nested_aggr()) { /*do nothing.*/ } else { int64_t N = aggr_exprs.at(i)->get_param_count(); for (int64_t j = 0; OB_SUCC(ret) && j < N; ++j) { if (OB_ISNULL(aggr_exprs.at(i)->get_param_expr(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (aggr_exprs.at(i)->get_param_expr(j)->is_const_expr()) { //do nothing } else if (OB_FAIL(add_var_to_array_no_dup(inner_aggr_exprs, aggr_exprs.at(i)->get_param_expr(j)))) { LOG_WARN("failed to to add var to array no dup.", K(ret)); } else { /*do nothing.*/ } } } } } return ret; } int ObTransformPreProcess::generate_child_level_aggr_stmt(ObSelectStmt *select_stmt, ObSelectStmt *&sub_stmt) { int ret = OB_SUCCESS; ObSEArray complex_aggr_exprs; ObSEArray select_item_array; ObSEArray aggr_expr_array; if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->stmt_factory_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select stmt is null", K(ret)); } else if (OB_FAIL(ctx_->stmt_factory_->create_stmt(sub_stmt))) { LOG_WARN("failed to create stmt.", K(ret)); } else if (FALSE_IT(sub_stmt->set_query_ctx(select_stmt->get_query_ctx()))) { } else if (OB_FAIL(sub_stmt->deep_copy(*ctx_->stmt_factory_, *ctx_->expr_factory_, *select_stmt))) { LOG_WARN("failed to deep copy from nested stmt.", K(ret)); } else if (OB_FAIL(sub_stmt->adjust_statement_id(ctx_->allocator_, ctx_->src_qb_name_, ctx_->src_hash_val_))) { LOG_WARN("failed to recursive adjust statement id", K(ret)); } else if (OB_FAIL(get_first_level_output_exprs(sub_stmt, complex_aggr_exprs))) { LOG_WARN("failed to extract levels aggr.", K(ret)); } else { sub_stmt->get_aggr_items().reset(); sub_stmt->get_select_items().reset(); } for (int64_t i = 0; OB_SUCC(ret) && i < sub_stmt->get_having_exprs().count(); ++i) { if (OB_FAIL(ObTransformUtils::extract_aggr_expr(sub_stmt->get_current_level(), sub_stmt->get_having_exprs().at(i), sub_stmt->get_aggr_items()))) { LOG_WARN("failed to extract aggr exprs.", K(ret)); } else { /*do nothing.*/ } } for (int64_t j = 0; OB_SUCC(ret) && j < complex_aggr_exprs.count(); ++j) { if (OB_FAIL(ObTransformUtils::extract_aggr_expr(sub_stmt->get_current_level(), complex_aggr_exprs.at(j), sub_stmt->get_aggr_items()))) { LOG_WARN("failed to extract aggr exprs.", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, complex_aggr_exprs.at(j), sub_stmt))) { LOG_WARN("failed to push back into select item array.", K(ret)); } else { /*do nothing.*/ } } if (OB_SUCC(ret)) { //try transform_for_grouping_sets_and_multi_rollup: // SELECT count(sum(c1)) FROM t1 GROUP BY GROUPING sets(c1, c2); bool is_happened = false; ObDMLStmt *dml_stmt = static_cast(sub_stmt); if (OB_FAIL(transform_for_grouping_sets_and_multi_rollup(dml_stmt, is_happened))) { LOG_WARN("failed to transform for transform for grouping sets and multi rollup.", K(ret)); } else if (is_happened) { sub_stmt = static_cast(dml_stmt); LOG_TRACE("succeed to transform for grouping sets and multi rollup",K(is_happened), K(ret)); } else {/*do nothing*/} } return ret; } int ObTransformPreProcess::remove_nested_aggr_exprs(ObSelectStmt *stmt) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret)); } else { ObSEArray aggr_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_aggr_items().count(); i++) { if (OB_ISNULL(stmt->get_aggr_items().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr of aggr expr is null", K(ret)); } else if (stmt->get_aggr_items().at(i)->is_nested_aggr()) { /*do nothing.*/ } else if (OB_FAIL(aggr_exprs.push_back(stmt->get_aggr_items().at(i)))) { LOG_WARN("failed to assign to inner aggr exprs.", K(ret)); } else { /*do nothing.*/ } } if (OB_SUCC(ret)) { if (OB_FAIL(stmt->get_aggr_items().assign(aggr_exprs))) { LOG_WARN("failed to extract second aggr items.", K(ret)); } } } return ret; } int ObTransformPreProcess::construct_column_items_from_exprs( const ObIArray &column_exprs, ObIArray &column_items) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < column_exprs.count(); ++i) { ColumnItem column_item; ObColumnRefRawExpr* expr = static_cast(column_exprs.at(i)); column_item.expr_ = expr; column_item.table_id_ = expr->get_table_id(); column_item.column_id_ = expr->get_column_id(); column_item.column_name_ = expr->get_expr_name(); if (OB_FAIL(column_items.push_back(column_item))) { LOG_WARN("failed to push back into temp column items.", K(ret)); } else { /*do nothing.*/ } } return ret; } int ObTransformPreProcess::generate_parent_level_aggr_stmt(ObSelectStmt *&select_stmt, ObSelectStmt *sub_stmt) { int ret = OB_SUCCESS; TableItem *view_table_item = NULL; ObSEArray old_exprs; ObSEArray new_exprs; ObSEArray column_items; if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select stmt is null", K(ret)); } else { select_stmt->get_table_items().reset(); select_stmt->get_joined_tables().reset(); select_stmt->get_from_items().reset(); select_stmt->get_having_exprs().reset(); select_stmt->get_order_items().reset(); select_stmt->get_group_exprs().reset(); select_stmt->get_rollup_exprs().reset(); select_stmt->get_column_items().reset(); select_stmt->get_condition_exprs().reset(); select_stmt->get_part_exprs().reset(); select_stmt->get_check_constraint_items().reset(); select_stmt->get_grouping_sets_items().reset(); select_stmt->get_multi_rollup_items().reset(); if (OB_FAIL(get_first_level_output_exprs(select_stmt, old_exprs))) { LOG_WARN("failed to get column exprs from stmt from.", K(ret)); } else if (OB_FAIL(remove_nested_aggr_exprs(select_stmt))) { LOG_WARN("failed to extract second aggr items.", K(ret)); } else if (OB_FAIL(ObTransformUtils::add_new_table_item(ctx_, select_stmt, sub_stmt, view_table_item))) { LOG_WARN("failed to add new table item.", K(ret)); } else if (OB_FAIL(select_stmt->add_from_item(view_table_item->table_id_))) { LOG_WARN("failed to add from item", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *view_table_item, select_stmt, new_exprs))) { LOG_WARN("failed to get select exprs from grouping sets view.", K(ret)); } else if (OB_FAIL(construct_column_items_from_exprs(new_exprs, column_items))) { LOG_WARN("failed to construct column items from exprs.", K(ret)); } else if (OB_FAIL(replace_group_id_in_stmt(select_stmt))) { LOG_WARN("fail to replace group_id in nested aggr"); } else if (OB_FAIL(select_stmt->replace_inner_stmt_expr(old_exprs, new_exprs))) { LOG_WARN("failed to replace inner stmt exprs.", K(ret)); } else if (OB_FAIL(select_stmt->get_column_items().assign(column_items))) { LOG_WARN("failed to assign column items.", K(ret)); } else if (OB_FAIL(select_stmt->rebuild_tables_hash())) { LOG_WARN("failed to rebuild tables hash.", K(ret)); } else if (OB_FAIL(select_stmt->update_column_item_rel_id())) { LOG_WARN("failed to update column items rel id.", K(ret)); } else if (OB_FAIL(select_stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalized stmt.", K(ret)); } else { /*do nothing.*/ } } return ret; } int ObTransformPreProcess::transform_for_nested_aggregate(ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret), K(stmt), K(ctx_)); } else if (!stmt->is_select_stmt()) { /*do nothing.*/ } else { ObSelectStmt *sub_stmt = NULL; ObSelectStmt *select_stmt = static_cast(stmt); /** * 本函数将含有嵌套聚合的stmt改写成两层stmt * select sum(b), max(sum(b)) from t1 group by b; * 以上sql可以改写成 * select sum(v.b), max(v.sum_b) * from ( * select b, sum(b) as sum_b * from t1 * group by b * ) v * 其中generate_child_level_aggr_stmt函数生成视图v * generate_parent_level_aggr_stmt生成外部stmt */ if (!select_stmt->contain_nested_aggr()) { /*do nothing.*/ } else if (OB_FAIL(generate_child_level_aggr_stmt(select_stmt, sub_stmt))) { LOG_WARN("failed to generate first level aggr stmt.", K(ret)); } else if (OB_FAIL(generate_parent_level_aggr_stmt(select_stmt, sub_stmt))) { LOG_WARN("failed to generate nested aggr stmt.", K(ret)); } else if (OB_FAIL(select_stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize stmt.", K(ret)); } else { trans_happened = true; stmt = select_stmt; } } return ret; } int ObTransformPreProcess::replace_group_id_in_stmt(ObSelectStmt *stmt) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret)); } else { // replace group_id in select list; ObIArray &sel_items = stmt->get_select_items(); for (int64_t i = 0; OB_SUCC(ret) && i < sel_items.count(); i++) { if (OB_ISNULL(sel_items.at(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr of select item shouldn't be null", K(ret)); } else if (OB_FAIL(replace_group_id_in_expr_recursive(sel_items.at(i).expr_))) { LOG_WARN("fail to replace expr in selet items", K(ret)); } } // replace group_id in having exprs; for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_having_expr_size(); i++) { if (OB_ISNULL(stmt->get_having_exprs().at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("having expr shouldn't be null", K(ret)); } else if (OB_FAIL(replace_group_id_in_expr_recursive(stmt->get_having_exprs().at(i)))) { LOG_WARN("fail to replace expr in having exprs", K(ret)); } } // replace group_id in order by exprs; for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_order_item_size(); i++) { if (OB_ISNULL(stmt->get_order_item(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("having expr shouldn't be null", K(ret)); } else if (OB_FAIL(replace_group_id_in_expr_recursive(stmt->get_order_item(i).expr_))) { LOG_WARN("fail to replace expr in having exprs", K(ret)); } } } return ret; } int ObTransformPreProcess::replace_group_id_in_expr_recursive(ObRawExpr *&expr) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null pointer", K(ret)); } else { if (expr->is_aggr_expr()) { if (expr->get_expr_type() == T_FUN_GROUP_ID) { // replace group id with 0; ObConstRawExpr *c_expr = NULL; if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, ObIntType, 0, c_expr))) { LOG_WARN("fail to build const expr", K(ret)); } else if (OB_ISNULL(c_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("c_expr is null", K(ret)); } else { expr = c_expr; } } } else { // recursive check hierarchical expr(exclude aggr_expr); ObRawExpr *tmp_expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { if (OB_ISNULL(tmp_expr = expr->get_param_expr(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get param expr is null", K(ret)); } else if (OB_FAIL(replace_group_id_in_expr_recursive(tmp_expr))) { LOG_WARN("fail to replace group id in expr", K(ret)); } } } } return ret; } int ObTransformPreProcess::transform_for_merge_into(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret), K(stmt), K(ctx_)); } else if (stmt->get_stmt_type() != stmt::T_MERGE) { /*do nothing*/ } else if (OB_ISNULL(stmt->get_query_ctx()) || OB_UNLIKELY(stmt->get_table_size() != 2)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid stmt", K(stmt), K(ret)); } else { const int64_t TARGET_TABLE_IDX = 0; const int64_t SOURCE_TABLE_IDX = 1; TableItem *new_table = NULL; ObMergeStmt *merge_stmt = static_cast(stmt); TableItem *target_table = stmt->get_table_item(TARGET_TABLE_IDX); TableItem *source_table = stmt->get_table_item(SOURCE_TABLE_IDX); if (OB_ISNULL(target_table) || OB_ISNULL(source_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid table item", K(target_table), K(source_table), K(ret)); } else if (ObTransformUtils::add_new_joined_table(ctx_, *merge_stmt, LEFT_OUTER_JOIN, source_table, target_table, merge_stmt->get_match_condition_exprs(), new_table, true)) { LOG_WARN("failed to add new joined table", K(ret)); } else if (OB_ISNULL(new_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("new join table is NULL", K(ret)); } else if (OB_FAIL(merge_stmt->add_from_item(new_table->table_id_, new_table->is_joined_table()))) { LOG_WARN("fail to add from item", K(new_table), K(ret)); } else { merge_stmt->get_match_condition_exprs().reset(); trans_happened = true; } } return ret; } int ObTransformPreProcess::transform_exprs(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt or context is null", K(ret)); } else { ObArray relation_exprs; if (OB_FAIL(stmt->get_relation_exprs(relation_exprs))) { LOG_WARN("failed to get all relation exprs", K(ret)); } else { for (int i = 0; OB_SUCC(ret) && i < relation_exprs.count(); i++) { bool is_happened = false; ObRawExpr *expr = NULL; if (OB_FAIL(relation_exprs.at(i).get(expr))) { LOG_WARN("failed to get expr", K(ret)); } else if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret)); } else if (OB_FAIL(transform_expr(*ctx_->expr_factory_, *ctx_->session_info_, expr, is_happened))) { LOG_WARN("transform expr failed", K(ret)); } else if (OB_FAIL(relation_exprs.at(i).set(expr))) { LOG_WARN("failed to set expr", K(ret)); } else { trans_happened |= is_happened; } } } } return ret; } int ObTransformPreProcess::transform_expr(ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, ObRawExpr *&expr, bool &trans_happened) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr is NULL", K(ret)); } if (OB_SUCC(ret)) { // rewrite `c1 in (c2, c3)` to `c1 = c2 or c1 = c3` if (OB_FAIL(replace_in_or_notin_recursively( expr_factory, session, expr, trans_happened))) { LOG_WARN("replace in or not in failed", K(ret), K(expr)); } } if (OB_SUCC(ret)) { // rewrite // `cast c1 when c2 then xxx when c3 then xxx else xxx end` // to: // `cast when c1 = c2 then xxx when c1 = c3 then xxx else xxx end` if (OB_FAIL(transform_arg_case_recursively( expr_factory, session, expr, trans_happened))) { LOG_WARN("transform arg case failed", K(ret)); } } return ret; } int ObTransformPreProcess::transform_in_or_notin_expr_without_row(ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, const bool is_in_expr, ObRawExpr *&in_expr, bool &trans_happened) { int ret = OB_SUCCESS; ObRawExpr *left_expr = in_expr->get_param_expr(0); ObRawExpr *right_expr = in_expr->get_param_expr(1); ObSEArray distinct_types; for (int i = 0; OB_SUCC(ret) && i < right_expr->get_param_count(); i++) { if (OB_ISNULL(right_expr->get_param_expr(i))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null param expr", K(ret), K(right_expr->get_param_expr(i))); } else { ObObjType obj_type = right_expr->get_param_expr(i)->get_result_type().get_type(); ObCollationType coll_type = right_expr->get_param_expr(i) ->get_result_type().get_collation_type(); ObCollationLevel coll_level = right_expr->get_param_expr(i) ->get_result_type().get_collation_level(); if (OB_UNLIKELY(obj_type == ObMaxType)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected obj type", K(ret), K(obj_type), K(*in_expr)); } else if (OB_FAIL(add_var_to_array_no_dup(distinct_types, DistinctObjMeta(obj_type, coll_type, coll_level)))) { LOG_WARN("failed to push back", K(ret)); } else { LOG_DEBUG("add param expr type", K(i), K(obj_type)); } } } // for end if (OB_FAIL(ret)) { // do nothing } else if (1 == distinct_types.count()) { // only one type contained in right row expr, do not need rewrite // set should_deduce_type = true ObOpRawExpr *op_raw_expr = dynamic_cast(in_expr); if (OB_ISNULL(op_raw_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid null op_raw_expr", K(ret)); } else { op_raw_expr->set_deduce_type_adding_implicit_cast(true); } } else { LOG_DEBUG("distinct types", K(distinct_types)); ObSEArray transed_in_exprs; ObSEArray same_type_exprs; for (int i = 0; OB_SUCC(ret) && i < distinct_types.count(); i++) { same_type_exprs.reuse(); DistinctObjMeta obj_meta = distinct_types.at(i); for (int j = 0; OB_SUCC(ret) && j < right_expr->get_param_count(); j++) { ObObjType obj_type = right_expr->get_param_expr(j)->get_result_type().get_type(); ObCollationType coll_type = right_expr->get_param_expr(j) ->get_result_type().get_collation_type(); ObCollationLevel coll_level = right_expr->get_param_expr(j) ->get_result_type().get_collation_level(); DistinctObjMeta tmp_meta(obj_type, coll_type, coll_level); if (obj_meta == tmp_meta && OB_FAIL(same_type_exprs.push_back(right_expr->get_param_expr(j)))) { LOG_WARN("failed to add param expr", K(ret)); } else { /* do nothing */ } } // for end if (OB_SUCC(ret) && OB_FAIL(create_partial_expr(expr_factory, left_expr, same_type_exprs, is_in_expr, transed_in_exprs))) { LOG_WARN("failed to create partial expr", K(ret)); } } // for end if (OB_FAIL(ret)) { } else if (OB_FAIL(get_final_transed_or_and_expr(expr_factory, session, is_in_expr, transed_in_exprs, in_expr))) { LOG_WARN("failed to get final transed or expr", K(ret)); } else { trans_happened = true; } } return ret; } int ObTransformPreProcess::transform_in_or_notin_expr_with_row(ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, const bool is_in_expr, ObRawExpr *&in_expr, bool &trans_happened) { int ret = OB_SUCCESS; ObRawExpr *left_expr = in_expr->get_param_expr(0); ObRawExpr *right_expr = in_expr->get_param_expr(1); int row_dim = T_REF_QUERY != left_expr->get_expr_type() ? left_expr->get_param_count() : static_cast(left_expr)->get_output_column(); ObSEArray, 4> distinct_row_types; ObSEArray, 4> all_row_types; for (int i = 0; OB_SUCC(ret) && i < right_expr->get_param_count(); i++) { if (OB_ISNULL(right_expr->get_param_expr(i))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null param expr", K(ret)); } else if (OB_UNLIKELY(right_expr->get_param_expr(i)->get_param_count() != row_dim)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid param cnt", K(row_dim), K(right_expr->get_param_expr(i)->get_param_count())); } else { ObSEArray tmp_row_type; for (int j = 0; OB_SUCC(ret) && j < right_expr->get_param_expr(i)->get_param_count(); j++) { if (OB_ISNULL(right_expr->get_param_expr(i)->get_param_expr(j))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null param expr", K(ret)); } else { const ObRawExpr *param_expr = right_expr->get_param_expr(i)->get_param_expr(j); const ObObjType obj_type = param_expr->get_result_type().get_type(); const ObCollationType coll_type = param_expr->get_result_type().get_collation_type(); const ObCollationLevel coll_level = param_expr->get_result_type().get_collation_level(); if (OB_UNLIKELY(obj_type == ObMaxType)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected obj type", K(ret), K(obj_type), K(*in_expr)); } else if (OB_FAIL(tmp_row_type.push_back( DistinctObjMeta(obj_type, coll_type, coll_level)))) { LOG_WARN("failed to push back element", K(ret)); } else { /* do nothing */ } } } // for end if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(add_row_type_to_array_no_dup(distinct_row_types, tmp_row_type))) { LOG_WARN("failed to add_row_type_to_array_no_dup", K(ret)); } else if (OB_FAIL(all_row_types.push_back(tmp_row_type))) { LOG_WARN("failed to push back element", K(ret)); } else { /* do nothing */ } } } // for end if (OB_FAIL(ret)) { // do nothing } else if (1 == distinct_row_types.count()) { // all rows are same, do nothing ObOpRawExpr *op_raw_expr = dynamic_cast(in_expr); if (OB_ISNULL(op_raw_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid null op_raw_expr", K(ret)); } else { op_raw_expr->set_deduce_type_adding_implicit_cast(true); } } else { ObSEArray transed_in_exprs; ObSEArray same_type_exprs; for (int i = 0; OB_SUCC(ret) && i < distinct_row_types.count(); i++) { same_type_exprs.reuse(); for (int j = 0; OB_SUCC(ret) && j < all_row_types.count(); j++) { if (is_same_row_type(distinct_row_types.at(i), all_row_types.at(j)) && OB_FAIL(same_type_exprs.push_back(right_expr->get_param_expr(j)))) { LOG_WARN("failed to add param expr", K(ret)); } } // for end if (OB_SUCC(ret) && OB_FAIL(create_partial_expr(expr_factory, left_expr, same_type_exprs, is_in_expr, transed_in_exprs))) { LOG_WARN("failed to create partial expr", K(ret)); } } // for end if (OB_FAIL(ret)) { } else if (OB_FAIL(get_final_transed_or_and_expr( expr_factory, session, is_in_expr, transed_in_exprs, in_expr))) { LOG_WARN("failed to get final transed in expr", K(ret)); } else { trans_happened = true; } } return ret; } int ObTransformPreProcess::create_partial_expr(ObRawExprFactory &expr_factory, ObRawExpr *left_expr, ObIArray &same_type_exprs, const bool is_in_expr, ObIArray &transed_in_exprs) { int ret = OB_SUCCESS; ObOpRawExpr *tmp_expr = NULL; ObOpRawExpr *tmp_row_expr = NULL; ObRawExpr *tmp_left_expr = left_expr; ObRawExpr *tmp_right_expr = NULL; if (OB_UNLIKELY(same_type_exprs.empty()) || OB_ISNULL(left_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected empty same_type_exprs", K(ret), K(same_type_exprs), K(left_expr)); } else if (left_expr->get_expr_type() == T_OP_ROW && OB_FAIL(ObRawExprCopier::copy_expr_node(expr_factory, left_expr, tmp_left_expr))) { // Comment for T_OP_ROW // for T_OP_ROW expr, the cast is not added above the expr // it is added on the expr's param. // when the expr is used by different predicates // we may need add different cast for its param // hence, we need to copy the expr node. // we do not need to copy its param, the param can be shared used. LOG_WARN("failed to copy expr node", K(ret)); } else if (1 == same_type_exprs.count()) { // = / <> if (OB_FAIL(expr_factory.create_raw_expr(is_in_expr ? T_OP_EQ : T_OP_NE, tmp_expr))) { LOG_WARN("failed to create or create raw expr", K(ret)); } else { tmp_right_expr = same_type_exprs.at(0); } } else if (OB_FAIL(expr_factory.create_raw_expr(is_in_expr ? T_OP_IN : T_OP_NOT_IN, tmp_expr)) // in / not in || OB_FAIL(expr_factory.create_raw_expr(T_OP_ROW, tmp_row_expr))) { LOG_WARN("failed to create or create raw expr", K(ret)); } else if (OB_ISNULL(tmp_row_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr", K(ret), K(tmp_row_expr)); } else if (OB_FAIL(append(tmp_row_expr->get_param_exprs(), same_type_exprs))) { LOG_WARN("failed to append exprs", K(ret)); } else { tmp_right_expr = tmp_row_expr; } if (OB_FAIL(ret)) { } else if (OB_ISNULL(tmp_expr) || OB_ISNULL(tmp_left_expr) || OB_ISNULL(tmp_right_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr", K(ret), K(tmp_expr), K(tmp_left_expr), K(tmp_right_expr)); } else if (OB_FAIL(tmp_expr->add_param_expr(tmp_left_expr)) || OB_FAIL(tmp_expr->add_param_expr(tmp_right_expr))) { LOG_WARN("failed to add param exprs", K(ret)); } else if (OB_FAIL(transed_in_exprs.push_back(tmp_expr))) { LOG_WARN("failed to push back element", K(ret)); } else { tmp_expr->set_deduce_type_adding_implicit_cast(true); LOG_DEBUG("partial in expr", K(*tmp_expr), K(*tmp_right_expr), K(*left_expr)); } return ret; } int ObTransformPreProcess::transform_arg_case_recursively( ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, ObRawExpr *&expr, bool &trans_happened) { int ret = OB_SUCCESS; if (T_OP_ARG_CASE == expr->get_expr_type()) { if (OB_FAIL(transform_arg_case_expr(expr_factory, session, expr, trans_happened))) { LOG_WARN("failed to transform_arg_case_expr", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(transform_arg_case_recursively(expr_factory, session, expr->get_param_expr(i), trans_happened))) { LOG_WARN("failed to transform arg case expr", K(ret), K(i)); } } return ret; } // in engine 3.0 transform arg_case_when_expr to simple_case_when_expr // eg: // case arg when when1 then then1 case when arg = when1 then then1 // when when1 then then2 -> when arg = when2 then then2 // else else1 else else1 int ObTransformPreProcess::transform_arg_case_expr(ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, ObRawExpr *&expr, bool &trans_happened) { int ret = OB_SUCCESS; ObCaseOpRawExpr *case_expr = static_cast(expr); ObRawExpr *arg_expr = case_expr->get_arg_param_expr(); ObCaseOpRawExpr *new_case_expr = NULL; if (OB_FAIL(expr_factory.create_raw_expr(T_OP_CASE, new_case_expr))) { LOG_WARN("failed to create case expr", K(ret)); } else if (OB_ISNULL(new_case_expr) || OB_ISNULL(arg_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret), KP(new_case_expr), KP(arg_expr)); } for (int64_t i = 0; OB_SUCC(ret) && i < case_expr->get_when_expr_size(); ++i) { ObRawExpr *when_expr = case_expr->get_when_param_expr(i); ObRawExpr *then_expr = case_expr->get_then_param_expr(i); ObRawExpr *tmp_arg_expr = arg_expr; ObOpRawExpr *equal_expr = NULL; if (OB_ISNULL(when_expr) || OB_ISNULL(then_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("when_expr is NULL", K(ret), KP(when_expr), KP(then_expr)); } else if (T_OP_ROW == arg_expr->get_expr_type() && OB_FAIL(ObRawExprCopier::copy_expr_node(expr_factory, arg_expr, tmp_arg_expr))) { // See the Comment for T_OP_ROW above LOG_WARN("failed to copy expr", K(ret)); } else if (OB_FAIL(create_equal_expr_for_case_expr(expr_factory, session, tmp_arg_expr, when_expr, case_expr->get_result_type(), equal_expr))) { LOG_WARN("failed to create equal expr", K(ret)); } else if (OB_FAIL(new_case_expr->add_when_param_expr(equal_expr)) || OB_FAIL(new_case_expr->add_then_param_expr(then_expr))) { LOG_WARN("failed to add param expr", K(ret)); } } // for end if (OB_SUCC(ret)) { new_case_expr->set_default_param_expr(case_expr->get_default_param_expr()); if (OB_FAIL(new_case_expr->formalize(&session))) { LOG_WARN("failed to formalize", K(ret)); } else { expr = static_cast(new_case_expr); trans_happened = true; } } return ret; } int ObTransformPreProcess::create_equal_expr_for_case_expr(ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, ObRawExpr *arg_expr, ObRawExpr *when_expr, const ObExprResType &case_res_type, ObOpRawExpr *&equal_expr) { int ret = OB_SUCCESS; ObObjType obj_type = ObMaxType; const ObExprResType &arg_type = arg_expr->get_result_type(); const ObExprResType &when_type = when_expr->get_result_type(); ObRawExpr *new_when_expr = NULL; // cast expr may added ObRawExpr *new_arg_expr = NULL; if (OB_ISNULL(arg_expr) || OB_ISNULL(when_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KP(arg_expr), KP(when_expr)); } else if (OB_FAIL(expr_factory.create_raw_expr(T_OP_EQ, equal_expr))) { LOG_WARN("failed to create equal expr", K(ret)); } else { if (OB_FAIL(ObExprArgCase::get_cmp_type(obj_type, arg_type.get_type(), when_type.get_type(), ObMaxType))) { // last argument is unused LOG_WARN("failed to get_cmp_type", K(ret)); } else if (lib::is_mysql_mode() && ob_is_string_type(obj_type)) { // when cmp_type is string, need to use case_res_type.calc_type_.cs_type_ as // collation type. it is aggregated by all when_exprs. // eg: select case col_utf8_general_ci when col_utf8_general_ci then 'a' // when col_utf8_bin then 'b' end from tbl; // use col_utf8_bin to compare(see in ObExprArgCase::calc_result_typeN()) ObExprResType cmp_type; cmp_type.set_type(obj_type); cmp_type.set_collation_type(case_res_type.get_calc_collation_type()); cmp_type.set_collation_level(case_res_type.get_calc_collation_level()); if (ObRawExprUtils::try_add_cast_expr_above(&expr_factory, &session, *arg_expr, cmp_type, new_arg_expr) || ObRawExprUtils::try_add_cast_expr_above(&expr_factory, &session, *when_expr, cmp_type, new_when_expr)) { LOG_WARN("failed to add_cast", K(ret), KP(new_arg_expr), KP(new_when_expr)); } } else { new_arg_expr = arg_expr; new_when_expr = when_expr; } } if (OB_SUCC(ret)) { if (OB_ISNULL(new_when_expr) || OB_ISNULL(new_arg_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret), KP(new_when_expr), KP(new_arg_expr)); } else if (OB_FAIL(equal_expr->add_param_expr(new_arg_expr)) || OB_FAIL(equal_expr->add_param_expr(new_when_expr))) { LOG_WARN("failed to add_param_expr", K(ret)); } } return ret; } bool ObTransformPreProcess::is_same_row_type(const ObIArray &left, const ObIArray &right) { bool ret_bool = true; if (left.count() != right.count()) { ret_bool = false; } for (int i = 0; ret_bool && i < left.count(); i++) { ret_bool = (left.at(i) == right.at(i)); } // for end return ret_bool; } int ObTransformPreProcess::get_final_transed_or_and_expr( ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, const bool is_in_expr, ObIArray &transed_in_exprs, ObRawExpr *&final_or_expr) { int ret = OB_SUCCESS; ObOpRawExpr *transed_or_expr = NULL; ObOpRawExpr *tmp_or_expr = NULL; ObOpRawExpr *last_or_expr = NULL; ObItemType op_type = is_in_expr ? T_OP_OR : T_OP_AND; if (OB_FAIL(expr_factory.create_raw_expr(op_type, transed_or_expr))) { LOG_WARN("failed to create or expr", K(ret)); } else if (OB_ISNULL(transed_or_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null expr", K(ret), K(transed_or_expr)); } else if (OB_FAIL(transed_or_expr->add_param_expr(transed_in_exprs.at(0)))) { LOG_WARN("failed to add param expr", K(ret)); } else { last_or_expr = transed_or_expr; int cur_idx = 1; for (; OB_SUCC(ret) && cur_idx < transed_in_exprs.count() - 1; cur_idx++) { if (OB_FAIL(expr_factory.create_raw_expr(op_type, tmp_or_expr))) { LOG_WARN("failed to create raw expr", K(ret)); } else if (OB_ISNULL(tmp_or_expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null expr", K(ret)); } else if (OB_FAIL(last_or_expr->add_param_expr(tmp_or_expr))) { LOG_WARN("failed to add param expr", K(ret)); } else if (OB_FAIL(tmp_or_expr->add_param_expr(transed_in_exprs.at(cur_idx)))) { LOG_WARN("failed to add param expr", K(ret)); } else { last_or_expr = tmp_or_expr; } } // for end if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(last_or_expr->add_param_expr(transed_in_exprs.at(cur_idx)))) { LOG_WARN("failed to add param expr", K(ret)); } else if (OB_FAIL(transed_or_expr->formalize(&session))) { LOG_WARN("expr formalize failed", K(ret)); } else { final_or_expr = transed_or_expr; } } return ret; } int ObTransformPreProcess::add_row_type_to_array_no_dup( ObIArray> &row_type_array, const ObSEArray &row_type) { int ret = OB_SUCCESS; bool founded = false; for (int i = 0; OB_SUCC(ret) && !founded && i < row_type_array.count(); i++) { if (is_same_row_type(row_type_array.at(i), row_type)) { founded = true; } } if (!founded && OB_FAIL(row_type_array.push_back(row_type))) { LOG_WARN("failed to push back element", K(ret)); } return ret; } int ObTransformPreProcess::check_and_transform_in_or_notin(ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, ObRawExpr *&in_expr, bool &trans_happened) { int ret = OB_SUCCESS; if (OB_UNLIKELY(2 != in_expr->get_param_count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid param cnt", K(ret), K(in_expr->get_param_count())); } else if (OB_ISNULL(in_expr->get_param_expr(0)) || OB_ISNULL(in_expr->get_param_expr(1))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null params", K(ret), K(in_expr->get_param_expr(0)), K(in_expr->get_param_expr(1))); } else if (T_OP_ROW == in_expr->get_param_expr(0)->get_expr_type() || (T_REF_QUERY == in_expr->get_param_expr(0)->get_expr_type() && static_cast(in_expr->get_param_expr(0))->get_output_column() > 1)) { // (x, y) in ((x0, y0), (x1, y1), ...) // (select x, y from ...) in ((x0, y0), (x1, y1), ...)) LOG_DEBUG("Before Transform", K(*in_expr)); ret = transform_in_or_notin_expr_with_row( expr_factory, session, T_OP_IN == in_expr->get_expr_type(), in_expr, trans_happened); } else { // x in (x0, x1, ...) LOG_DEBUG("Before Transform", K(*in_expr)); ret = transform_in_or_notin_expr_without_row( expr_factory, session, T_OP_IN == in_expr->get_expr_type(), in_expr, trans_happened); } if (OB_SUCC(ret)) { ObOpRawExpr *op_raw_expr = dynamic_cast(in_expr); if (OB_ISNULL(op_raw_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid null op_raw_expr", K(ret)); } else if (OB_FAIL(op_raw_expr->formalize(&session))) { LOG_WARN("formalize expr failed", K(ret)); } else { LOG_DEBUG("After Transform", K(*op_raw_expr)); } } return ret; } int ObTransformPreProcess::replace_in_or_notin_recursively(ObRawExprFactory &expr_factory, const ObSQLSessionInfo &session, ObRawExpr *&root_expr, bool &trans_happened) { int ret = OB_SUCCESS; for (int i = 0; OB_SUCC(ret) && i < root_expr->get_param_count(); i++) { if (OB_ISNULL(root_expr->get_param_expr(i))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null param expr", K(ret)); } else if (OB_FAIL(SMART_CALL(replace_in_or_notin_recursively(expr_factory, session, root_expr->get_param_expr(i), trans_happened)))) { LOG_WARN("failed to replace in or notin recursively", K(ret)); } } if (OB_SUCC(ret) && (T_OP_IN == root_expr->get_expr_type() || T_OP_NOT_IN == root_expr->get_expr_type())) { if (OB_FAIL(check_and_transform_in_or_notin( expr_factory, session, root_expr, trans_happened))) { LOG_WARN("failed to check and transform", K(ret)); } } return ret; } /*@brief ObTransformPreProcess::transformer_aggr_expr 用于将一些复杂的聚合函数展开为普通的聚合运算; * eg:var_pop(expr) ==> SUM(expr*expr) - SUM(expr)* SUM(expr)/ COUNT(expr)) / COUNT(expr) * 其中ObExpandAggregateUtils这个类主要涉及到相关的函数用于展开复杂的聚合函数: * 1.ObExpandAggregateUtils::expand_aggr_expr ==> 用于处理普通的aggr函数接口 * 2.ObExpandAggregateUtils::expand_window_aggr_expr ==> 用于处理窗口函数中的aggr的函数接口 * */ int ObTransformPreProcess::transformer_aggr_expr(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; bool is_expand_aggr = false; bool is_expand_window_aggr = false; bool is_happened = false; //之前的逻辑保证了两者嵌套聚合及普通函数的改写顺序,传进来的trans_happened包含了是否发生嵌套聚合函数改写的信息 bool is_trans_nested_aggr_happened = trans_happened; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null allocator", K(ret)); } else if (OB_FAIL(ObExpandAggregateUtils::expand_aggr_expr(stmt, ctx_, is_expand_aggr))) { LOG_WARN("failed to expand aggr expr", K(ret)); } else if (OB_FAIL(ObExpandAggregateUtils::expand_window_aggr_expr(stmt, ctx_, is_expand_window_aggr))) { LOG_WARN("failed to expand window aggr expr", K(ret)); //如果发生了嵌套聚合函数改写: // select max(avg(c1)) from t1 group by c2; // ==> // select max(a) from (select avg(c1) as a from t1 group by c2); // 需要改写view里面的聚合函数,同时需要注释的是嵌套聚合函数只有内外两层,不会生成超过2层的结构 } else if (is_trans_nested_aggr_happened) { TableItem *table_item = NULL; if (OB_UNLIKELY(stmt->get_table_items().count() != 1) || OB_ISNULL(table_item = stmt->get_table_item(0)) || OB_UNLIKELY(!table_item->is_generated_table())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(table_item), K(stmt->get_table_items().count()), K(ret)); } else if (OB_FAIL(transformer_aggr_expr(table_item->ref_query_, is_happened))) { LOG_WARN("failed to transformer aggr expr", K(ret)); } else {/*do nothing*/} } if (OB_SUCC(ret)) { trans_happened = is_expand_aggr | is_expand_window_aggr | is_happened; } return ret; } /** * @brief ObTransformSimplify::transform_rownum_as_limit_offset * 将 rownum 改写为 limit * select * from t where ... and rownum < ?; * => select * from t where ... limit ?; * * select * from (select * from t order by c) where rownum < ?; * => select * from (select * from t order by c limit ?); * * 将 rownum 改写为 limit / offset * select * from (select rownum rn, ... from t) where rn > ? and rn < ?; * => select * from (select rownum rn, ... from t limit ? offset ?); */ int ObTransformPreProcess::transform_rownum_as_limit_offset( const ObIArray &parent_stmts, ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; //bool is_rownum_gen_col_happened = false; bool is_rownum_happened = false; bool is_generated_rownum_happened = false; trans_happened = false; if (OB_FAIL(transform_common_rownum_as_limit(stmt, is_rownum_happened))) { LOG_WARN("failed to transform common rownum as limit", K(ret)); } else if (OB_FAIL(transform_generated_rownum_as_limit(parent_stmts, stmt, is_generated_rownum_happened))) { LOG_WARN("failed to transform rownum gen col as limit", K(ret)); } else { trans_happened = is_rownum_happened || is_generated_rownum_happened; } return ret; } /** * @brief ObTransformPreProcess::transform_common_rownum_as_limit * 将 rownum 改写为 limit * select * from t where ... and rownum < ? order by c1; * => select * from (select * from t where ... limit ?) order by c1; * **/ int ObTransformPreProcess::transform_common_rownum_as_limit(ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; ObRawExpr *limit_expr = NULL; ObSelectStmt *child_stmt = NULL; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)|| OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret), K(ctx_)); } else if (stmt->is_hierarchical_query()) {//层次查询暂时无法支持 /*do nothing*/ } else if (is_oracle_mode() && stmt->is_select_stmt() && static_cast(stmt)->has_for_update()) { // in oracle mode, do not create view when has for update } else if (OB_FAIL(try_transform_common_rownum_as_limit(stmt, limit_expr))) { LOG_WARN("failed to try transform rownum expr as limit", K(ret)); } else if (NULL == limit_expr) { /*do nothing */ //不含有order by的update/delete stmt不用再进行分离spj } else if (!stmt->is_select_stmt() && !stmt->has_order_by()) { stmt->set_limit_offset(limit_expr, NULL); trans_happened = true; } else if (OB_FAIL(ObTransformUtils::create_simple_view(ctx_, stmt, child_stmt, false))) { LOG_WARN("failed to create simple view", K(ret)); } else if (OB_ISNULL(child_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(child_stmt)); } else { child_stmt->set_limit_offset(limit_expr, NULL); trans_happened = true; } return ret; } /** * @brief ObTransformPreProcess::try_transform_common_rownum_as_limit * 满足以下条件时,stmt 中的 rownum 是可以改写 limit * 1. rownum 表达式位于where中,形式为: rownum < ?, rownum <= ?, rownum = ? 且参数为 int/number 型 * 对于等值条件: rownum = 1 转化为 limit 1, 其它转化为 limit 0 * 2. stmt 没有 distinct, groupby, order by, aggr, window function 等 * e.g. select rownum, * from t where rownum < 2; */ int ObTransformPreProcess::try_transform_common_rownum_as_limit(ObDMLStmt *stmt, ObRawExpr *&limit_expr) { int ret = OB_SUCCESS; limit_expr = NULL; ObRawExpr *limit_value = NULL; ObItemType op_type = T_INVALID; bool is_valid = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else { ObIArray &conditions = stmt->get_condition_exprs(); int64_t expr_idx = -1; bool is_eq_cond = false; bool is_const_filter = false; for (int64_t i = 0; OB_SUCC(ret) && !is_eq_cond && i < conditions.count(); ++i) { ObRawExpr *cond_expr = NULL; ObRawExpr *const_expr = NULL; ObItemType expr_type = T_INVALID; if (OB_ISNULL(cond_expr = conditions.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("condition expr is null", K(ret), K(i)); } else if (cond_expr->has_flag(CNT_DYNAMIC_PARAM)) { // do nothing } else if (OB_FAIL(ObOptimizerUtil::get_rownum_filter_info(cond_expr, expr_type, const_expr, is_const_filter))) { LOG_WARN("failed to check is filter rownum", K(ret)); } else if (!is_const_filter) { // do nothing } else if (T_OP_LE == expr_type || T_OP_LT == expr_type) { limit_value = const_expr; op_type = expr_type; expr_idx = i; is_valid = true; } else if (T_OP_EQ == expr_type) { limit_value = const_expr; expr_idx = i; is_valid = true; is_eq_cond = true; } else {/*do nothing*/} } for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < conditions.count(); ++i) { ObRawExpr *cond_expr = NULL; if (i == expr_idx) { //do nothing } else if (OB_ISNULL(cond_expr = conditions.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("condition expr is null", K(ret), K(i)); } else if (cond_expr->has_flag(CNT_ROWNUM)) { is_valid = false; } } if (OB_SUCC(ret) && is_valid) { ObRawExpr *eq_expr = NULL; ObConstRawExpr *zero_expr = NULL; ObConstRawExpr *one_expr = NULL; if (OB_UNLIKELY(expr_idx < 0 || expr_idx >= conditions.count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr index is invalid", K(ret), K(expr_idx), K(conditions.count())); } else if (OB_FAIL(conditions.remove(expr_idx))) { LOG_WARN("failed to remove expr", K(ret)); } else if (!is_eq_cond) { ObRawExpr *int_expr = NULL; if (OB_FAIL(ObOptimizerUtil::convert_rownum_filter_as_limit(*ctx_->expr_factory_, ctx_->session_info_, op_type, limit_value, int_expr))) { LOG_WARN("failed to convert rownum filter as limit", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr_for_limit(*ctx_->expr_factory_, int_expr, limit_expr))) { LOG_WARN("failed to build case when expr for limit", K(ret)); } } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, ObIntType, 0, zero_expr))) { LOG_WARN("failed to build const int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, ObIntType, 1, one_expr))) { LOG_WARN("failed to build const int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(*ctx_->expr_factory_, T_OP_EQ, limit_value, one_expr, eq_expr))) { LOG_WARN("failed to build common binary op expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(*ctx_->expr_factory_, eq_expr, one_expr, zero_expr, limit_expr))) { LOG_WARN("failed to build case when expr", K(ret)); } } if (OB_SUCC(ret) && NULL != limit_expr) { //添加 cast 作用: // 1.对于新引擎, 必须保证输出结果为 int // 2.目前单独的 case when 无法预计算, 分配了 cast 后能够进行预计算 ObExprResType dst_type; dst_type.set_int(); ObSysFunRawExpr *cast_expr = NULL; OZ(ObRawExprUtils::create_cast_expr(*ctx_->expr_factory_, limit_expr, dst_type, cast_expr, ctx_->session_info_)); CK(NULL != cast_expr); if (OB_SUCC(ret)) { limit_expr = cast_expr; } } } return ret; } int ObTransformPreProcess::transform_generated_rownum_as_limit( const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; ObDMLStmt *upper_stmt = NULL; ObSelectStmt *select_stmt = NULL; ObRawExpr *upper_offset = NULL; ObRawExpr *upper_limit = NULL; ObRawExpr *offset_expr = NULL; ObRawExpr *limit_expr = NULL; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else if (parent_stmts.empty()) { /*do nothing*/ } else if (!stmt->is_select_stmt() || OB_ISNULL(select_stmt = static_cast(stmt)) || OB_ISNULL(upper_stmt = parent_stmts.at(parent_stmts.count()-1).stmt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else if (select_stmt->is_hierarchical_query() || //层次查询不进行改写 upper_stmt->is_hierarchical_query()) { /*do nothing*/ } else if (OB_FAIL(try_transform_generated_rownum_as_limit_offset(upper_stmt, select_stmt, upper_limit, upper_offset))) { LOG_WARN("failed to try transform generated rownum as offset offset", K(ret)); } else if (NULL == upper_limit && NULL == upper_offset) { /*do nothing*/ } else if (OB_FAIL(ObTransformUtils::merge_limit_offset(ctx_, stmt->get_limit_expr(), upper_limit, stmt->get_offset_expr(), upper_offset, limit_expr, offset_expr))) { LOG_WARN("failed to merge limit offset", K(ret)); } else { stmt->set_limit_offset(limit_expr, offset_expr); trans_happened = true; } return ret; } // 将 generate rownum 改写为 limit / offset // 1. select * from (select rownum rn, ... from t) where rn > 2 and rn <= 5; // => select * from (select rownum rn, ... from t limit 3 offset 2); // 2. select * from (select rownum rn, ... from t) where rn = 4; // => select * from (select rownum rn, ... from t limit 1 offset 3); // 3. select * from (select rownum rn, ... from t) where rn = 4.2; // => select * from (select rownum rn, ... from t limit 0 offset 0); int ObTransformPreProcess::try_transform_generated_rownum_as_limit_offset(ObDMLStmt *upper_stmt, ObSelectStmt *select_stmt, ObRawExpr *&limit_expr, ObRawExpr *&offset_expr) { int ret = OB_SUCCESS; TableItem *table = NULL; limit_expr = NULL; offset_expr = NULL; if (OB_ISNULL(select_stmt) || OB_ISNULL(upper_stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else if (!upper_stmt->is_sel_del_upd() || !upper_stmt->is_single_table_stmt()) { // 仅对单表视图查询尝试提取 limit/offset } else if (OB_ISNULL(table = upper_stmt->get_table_item(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else if (!is_oracle_mode() || select_stmt->is_fetch_with_ties() || NULL != select_stmt->get_offset_expr() || NULL != select_stmt->get_limit_percent_expr() || select_stmt->has_order_by() || select_stmt->has_rollup() || select_stmt->has_group_by() || select_stmt->has_window_function()) { // oracle 模式下, 以下情况禁止转化: // 1. is fetch with ties / has limit percent expr / has offset expr // 2. order by, 即使输出 rownum 也为乱序: // select * from (select rounum rn, c1 from t order by c1) where rn > 10; // 3. rollup/group by 无法输出非聚合列 rownum // 4. window func 内部可能进行排序, 不进行转化 } else { bool is_eq_cond = false; ObRawExpr *limit_cond = NULL; ObRawExpr *offset_cond = NULL; ObRawExpr *limit_value = NULL; ObRawExpr *offset_value = NULL; ObItemType limit_cmp_type = T_INVALID; ObItemType offset_cmp_type = T_INVALID; ObRawExpr *select_expr = NULL; ColumnItem *column_item = NULL; ObRawExpr *cond_expr = NULL; ObIArray &select_items = select_stmt->get_select_items(); ObIArray &upper_conds = upper_stmt->get_condition_exprs(); for (int64_t i = 0; OB_SUCC(ret) && !is_eq_cond && i < select_items.count(); ++i) { if (OB_ISNULL(select_expr = select_items.at(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (!select_expr->has_flag(IS_ROWNUM)) { /*do nothing*/ } else if (OB_ISNULL(column_item = upper_stmt->get_column_item_by_id(table->table_id_, i + OB_APP_MIN_COLUMN_ID))) { /*do nothing*/ } else { for (int64_t j = 0; OB_SUCC(ret) && !is_eq_cond && j < upper_conds.count(); ++j) { if (OB_ISNULL(cond_expr = upper_conds.at(j))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (cond_expr->is_op_expr() && 2 == cond_expr->get_param_count() && (IS_RANGE_CMP_OP(cond_expr->get_expr_type()) || T_OP_EQ == cond_expr->get_expr_type())) { ObRawExpr *param1 = cond_expr->get_param_expr(0); ObRawExpr *param2 = cond_expr->get_param_expr(1); ObRawExpr *const_expr = NULL; ObItemType expr_type = T_INVALID; if (OB_ISNULL(param1) || OB_ISNULL(param2)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null expr", K(ret), K(param1), K(param2)); } else if (param1 == column_item->expr_ && param2->is_static_scalar_const_expr()) { expr_type = cond_expr->get_expr_type(); const_expr = param2; } else if (param1->is_static_scalar_const_expr() && param2 == column_item->expr_) { const_expr = param1; ret = ObOptimizerUtil::flip_op_type(cond_expr->get_expr_type(), expr_type); } else {/*do nothing*/} // 多个可转换为 limit/offset 的conds, 仅转换第一个 if (OB_FAIL(ret) || NULL == const_expr) { } else if (!const_expr->get_result_type().is_integer_type() && !const_expr->get_result_type().is_number()) { /*do nothing*/ } else if (T_OP_EQ == expr_type) { // 有等值条件优先转化 limit_value = const_expr; limit_cond = cond_expr; is_eq_cond = true; offset_cond = NULL; } else if (NULL == limit_cond && (T_OP_LE == expr_type || T_OP_LT == expr_type)) { limit_value = const_expr; limit_cmp_type = expr_type; limit_cond = cond_expr; } else if (NULL == offset_cond && (T_OP_GE == expr_type || T_OP_GT == expr_type)) { offset_value = const_expr; offset_cmp_type = expr_type; offset_cond = cond_expr; } } } } } ObRawExpr *init_limit_expr = NULL; ObRawExpr *init_offset_expr = NULL; ObRawExpr *minus_expr = NULL; if (OB_FAIL(ret)) { } else if (NULL != limit_cond && OB_FAIL(ObOptimizerUtil::remove_item(upper_conds, limit_cond))) { LOG_WARN("failed to remove expr", K(ret)); } else if (NULL != offset_cond && OB_FAIL(ObOptimizerUtil::remove_item(upper_conds, offset_cond))) { LOG_WARN("failed to remove expr", K(ret)); } else if (is_eq_cond) { ret = transform_generated_rownum_eq_cond(limit_value, limit_expr, offset_expr); } else if (NULL != limit_value && OB_FAIL(ObOptimizerUtil::convert_rownum_filter_as_limit(*ctx_->expr_factory_, ctx_->session_info_, limit_cmp_type, limit_value, init_limit_expr))) { LOG_WARN("failed to create limit expr from rownum", K(ret)); } else if (NULL != limit_value && OB_FAIL(ObRawExprUtils::build_case_when_expr_for_limit(*ctx_->expr_factory_, init_limit_expr, init_limit_expr))) { LOG_WARN("failed to build case when expr for limit", K(ret)); } else if (NULL != offset_value && OB_FAIL(ObOptimizerUtil::convert_rownum_filter_as_offset(*ctx_->expr_factory_, ctx_->session_info_, offset_cmp_type, offset_value, init_offset_expr))) { LOG_WARN("failed to create limit expr from rownum", K(ret)); } else if (NULL != offset_value && OB_FAIL(ObRawExprUtils::build_case_when_expr_for_limit(*ctx_->expr_factory_, init_offset_expr, init_offset_expr))) { LOG_WARN("failed to build case when expr for limit", K(ret)); } else if (NULL == init_offset_expr || NULL == init_limit_expr) { limit_expr = init_limit_expr; offset_expr = init_offset_expr; } else if (OB_FAIL(ObRawExprUtils::create_double_op_expr(*ctx_->expr_factory_, ctx_->session_info_, T_OP_MINUS, minus_expr, init_limit_expr, init_offset_expr))) { LOG_WARN("failed to create double op expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr_for_limit(*ctx_->expr_factory_, minus_expr, limit_expr))) { LOG_WARN("failed to build case when expr for limit", K(ret)); } else { offset_expr = init_offset_expr; } } return ret; } //select * from (select rownum rn, ... from t) where rn = val; // => select * from (select rownum rn, ... from t limit ? offset ?); // val 正整数: limit 1 offset val - 1; // 其它: limit 0 offset 0; int ObTransformPreProcess::transform_generated_rownum_eq_cond(ObRawExpr *eq_value, ObRawExpr *&limit_expr, ObRawExpr *&offset_expr) { int ret = OB_SUCCESS; limit_expr = NULL; offset_expr = NULL; ObRawExpr *minus_expr = NULL; ObRawExpr *cmp_gt_expr = NULL; ObRawExpr *cmp_eq_expr = NULL; ObRawExpr *and_expr = NULL; ObConstRawExpr *zero_expr = NULL; ObConstRawExpr *one_expr = NULL; ObSysFunRawExpr *floor_expr = NULL; if (OB_ISNULL(eq_value) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); } else if (!eq_value->get_result_type().is_integer_type() && !eq_value->get_result_type().is_number()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected eq_value", K(ret), K(*eq_value)); } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, ObIntType, 0, zero_expr))) { LOG_WARN("failed to build const int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, ObIntType, 1, one_expr))) { LOG_WARN("failed to build const int expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::create_double_op_expr(*ctx_->expr_factory_, ctx_->session_info_, T_OP_MINUS, minus_expr, eq_value, one_expr))) { LOG_WARN("failed to create double op expr", K(ret)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_FUN_SYS_FLOOR, floor_expr))) { LOG_WARN("failed to create fun sys floor", K(ret)); } else if (OB_ISNULL(floor_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("floor expr is null", K(ret)); } else if (OB_FAIL(floor_expr->set_param_expr(eq_value))) { LOG_WARN("failed to set param expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(*ctx_->expr_factory_, T_OP_GT, eq_value, zero_expr, cmp_gt_expr))) { LOG_WARN("failed to build common binary op expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(*ctx_->expr_factory_, T_OP_EQ, eq_value, floor_expr, cmp_eq_expr))) { LOG_WARN("failed to build common binary op expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(*ctx_->expr_factory_, T_OP_AND, cmp_gt_expr, cmp_eq_expr, and_expr))) { LOG_WARN("failed to build common binary op expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(*ctx_->expr_factory_, and_expr, one_expr, zero_expr, limit_expr))) { LOG_WARN("failed to build case when expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(*ctx_->expr_factory_, and_expr, minus_expr, zero_expr, offset_expr))) { LOG_WARN("failed to build case when expr", K(ret)); } return ret; } int ObTransformPreProcess::transformer_rowid_expr(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; ObSEArray rowid_exprs; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is NULL", K(ret)); } else if (is_mysql_mode()) { /*do nothing*/ } else if (OB_FAIL(stmt->get_stmt_rowid_exprs(rowid_exprs))) { LOG_WARN("failed to get stmt rowid exprs", K(ret)); } else if (!rowid_exprs.empty()) { ObSEArray old_rowid_exprs; ObSEArray new_rowid_exprs; //before transform pre, rowid expr just only have two expr types: // 1. sys calc urowid expr is used to calc rowid or sys calc urowid expr have been calculated. // 2. empty rowid column expr for generate table, we need transform empty rowid column expr // to real sys calc urowid expr here. for (int i = 0; OB_SUCC(ret) && i < rowid_exprs.count(); ++i) { ObRawExpr *expr = NULL; if (OB_ISNULL(expr = rowid_exprs.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(expr)); } else if (expr->get_expr_type() == T_FUN_SYS_CALC_UROWID || expr->get_expr_type() == T_QUESTIONMARK) { /*do nothing*/ } else if (expr->is_column_ref_expr()) { ObRawExpr *new_rowid_expr = NULL; if (OB_FAIL(old_rowid_exprs.push_back(expr))) { LOG_WARN("failed to push back rowid expr", K(ret)); } else if (OB_FAIL(do_transform_rowid_expr(*stmt, static_cast(expr), new_rowid_expr))) { LOG_WARN("failed to do transform rowid expr", K(ret)); } else if (OB_ISNULL(new_rowid_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(new_rowid_expr)); } else if (OB_FAIL(new_rowid_exprs.push_back(new_rowid_expr))) { LOG_WARN("failed to push back rowid expr", K(ret)); } else if (OB_FAIL(stmt->remove_column_item( static_cast(expr)->get_table_id(), static_cast(expr)->get_column_id()))) { LOG_WARN("failed to remove column item", K(ret)); } else {/*do nothing*/} } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected rowid expr", K(ret), KPC(expr)); } } if (OB_SUCC(ret) && !old_rowid_exprs.empty()) { if (OB_UNLIKELY(old_rowid_exprs.count() != new_rowid_exprs.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(old_rowid_exprs), K(new_rowid_exprs), K(ret)); } else if (OB_FAIL(stmt->replace_inner_stmt_expr(old_rowid_exprs, new_rowid_exprs))) { LOG_WARN("replace inner stmt expr failed", K(ret)); } else { trans_happened = true; LOG_DEBUG("Succeed to transformer rowid expr", K(*stmt), K(old_rowid_exprs), K(new_rowid_exprs)); } } } return ret; } int ObTransformPreProcess::do_transform_rowid_expr(ObDMLStmt &stmt, ObColumnRefRawExpr *empty_rowid_col_expr, ObRawExpr *&new_rowid_expr) { int ret = OB_SUCCESS; new_rowid_expr = NULL; if (OB_ISNULL(empty_rowid_col_expr) || OB_UNLIKELY(!ObCharset::case_insensitive_equal(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME, empty_rowid_col_expr->get_column_name()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret), KPC(empty_rowid_col_expr)); } else { TableItem *table_item = NULL; if (OB_ISNULL(table_item = stmt.get_table_item_by_id(empty_rowid_col_expr->get_table_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_item is NULL", K(ret), K(empty_rowid_col_expr->get_table_id())); } else if (OB_UNLIKELY(!table_item->is_generated_table() && !table_item->is_temp_table())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret), K(*table_item)); } else if (OB_FAIL(recursive_generate_rowid_select_item(table_item->ref_query_, new_rowid_expr))) { LOG_WARN("failed to recursive generate rowid select item", K(ret)); } else if (OB_ISNULL(new_rowid_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("new_rowid_expr cannot be NULL", K(ret)); } else if (OB_FAIL(create_rowid_item_for_stmt(&stmt, table_item, new_rowid_expr))) { LOG_WARN("create rowid item for stmt failed", K(ret)); } else { LOG_TRACE("succeed to do transform rowid expr", K(*new_rowid_expr), K(stmt)); } } return ret; } int ObTransformPreProcess::add_rowid_constraint(ObDMLStmt &stmt) { int ret = OB_SUCCESS; ObExecContext *exec_ctx = NULL; if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->allocator_) || OB_ISNULL (exec_ctx = ctx_->exec_ctx_)|| OB_ISNULL(stmt.get_query_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ctx_ or query_ctx is NULL", K(ret), KP(ctx_), KP(stmt.get_query_ctx())); } for (int i = 0; OB_SUCC(ret) && i < stmt.get_condition_size(); ++i) { ObRawExpr *expr = stmt.get_condition_expr(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret)); } else if (expr->get_param_count() == 2) { ObRawExpr *l_expr = expr->get_param_expr(0); ObRawExpr *r_expr = expr->get_param_expr(1); ObRawExpr *calc_urowid_expr = NULL; ObRawExpr *const_expr = NULL; if (OB_ISNULL(l_expr) || OB_ISNULL(r_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret), KP(l_expr), KP(r_expr)); } else if ((l_expr->get_expr_type() == T_FUN_SYS_CALC_UROWID && r_expr->is_static_scalar_const_expr())) { calc_urowid_expr = l_expr; const_expr = r_expr; } else if ((r_expr->get_expr_type() == T_FUN_SYS_CALC_UROWID && l_expr->is_static_scalar_const_expr())) { calc_urowid_expr = r_expr; const_expr = l_expr; } if (OB_SUCC(ret) && OB_NOT_NULL(calc_urowid_expr)) { void *cons_buf = NULL; ObRowidConstraint *rowid_cons = NULL; if (OB_ISNULL(cons_buf = ctx_->allocator_->alloc(sizeof(ObRowidConstraint)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory failed", K(ret)); } rowid_cons = new(cons_buf)ObRowidConstraint(exec_ctx->get_allocator()); if (OB_SUCC(ret)) { if (OB_FAIL(rowid_cons->rowid_type_array_.init(calc_urowid_expr->get_param_count()))) { LOG_WARN("failed to init array", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < calc_urowid_expr->get_param_count(); ++i) { if (calc_urowid_expr->get_param_expr(i)->has_flag(IS_COLUMN)) { const ObColumnRefRawExpr *col_expr = static_cast(calc_urowid_expr->get_param_expr(i)); // pk_vals may store generated col which is partition key but not primary key if (!col_expr->is_rowkey_column()) { /*do nothing*/ } else if OB_FAIL(rowid_cons->rowid_type_array_.push_back(col_expr->get_data_type())) { LOG_WARN("push back pk_column item failed", K(ret)); } } } if (OB_SUCC(ret)) { ObPhysicalPlanCtx *plan_ctx = NULL; ObObj rowid_val; bool got_result = false; if (OB_ISNULL(plan_ctx = exec_ctx->get_physical_plan_ctx()) || OB_ISNULL(exec_ctx->get_sql_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("plan ctx is NULL", K(ret)); } else if (OB_FAIL(ObSQLUtils::calc_const_or_calculable_expr(exec_ctx, const_expr, rowid_val, got_result, *ctx_->allocator_, false))) { LOG_WARN("failed to calc const or calculable expr", K(ret)); } else if (rowid_val.is_null()) { //do nothing } else if (!rowid_val.is_urowid()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("val should be urowid", K(ret), K(rowid_val)); } else { ObSEArray pk_vals; const ObURowIDData &urowid_data = rowid_val.get_urowid(); if (OB_FAIL(urowid_data.get_pk_vals(pk_vals))) { LOG_WARN("get pk values failed", K(ret)); } else { rowid_cons->rowid_version_ = urowid_data.get_version(); int64_t pk_cnt = urowid_data.get_real_pk_count(pk_vals); if (pk_cnt != rowid_cons->rowid_type_array_.count()) { ret = OB_INVALID_ROWID; LOG_WARN("invalid rowid, table rowkey cnt and encoded row cnt mismatch", K(ret), K(pk_cnt), K(rowid_cons->rowid_type_array_.count())); } else { for (int i = 0; OB_SUCC(ret) && i < pk_cnt; i++) { if (!pk_vals.at(i).is_null() && pk_vals.at(i).get_type() != rowid_cons->rowid_type_array_.at(i)) { ret = OB_INVALID_ROWID; LOG_WARN("invalid rowid, table rowkey type and encoded type mismatch", K(ret), K(pk_vals.at(i).get_type()), K(rowid_cons->rowid_type_array_.at(i))); } } } } } if (OB_SUCC(ret)) { ObStaticEngineExprCG expr_cg(exec_ctx->get_allocator(), exec_ctx->get_my_session(), exec_ctx->get_sql_ctx()->schema_guard_, plan_ctx->get_original_param_cnt(), plan_ctx->get_datum_param_store().count()); rowid_cons->expect_result_ = PreCalcExprExpectResult::PRE_CALC_ROWID; if (OB_FAIL(expr_cg.generate_calculable_expr(const_expr, rowid_cons->pre_calc_expr_info_))) { LOG_WARN("failed to generate calculable expr", K(ret)); } else if (OB_UNLIKELY(!stmt.get_query_ctx()->all_pre_calc_constraints_.add_last(rowid_cons))) { LOG_WARN("failed to add rowid constraint", K(ret)); } else { LOG_TRACE("Succeed to add rowid constraint", KPC(expr)); } } } } } } return ret; } int ObTransformPreProcess::recursive_generate_rowid_select_item(ObSelectStmt *select_stmt, ObRawExpr *&rowid_expr) { int ret = OB_SUCCESS; bool can_gen_rowid = false; rowid_expr = NULL; if (OB_ISNULL(select_stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt or ctx_ is NULL", K(ret), KP(select_stmt), KP(ctx_)); } else { ObIArray &table_items = select_stmt->get_table_items(); TableItem *table_item = NULL; ObSysFunRawExpr *rowid_func_expr = NULL; LOG_DEBUG("transformer rowid_expr recursively begin", KPC(select_stmt), K(table_items)); for (int64_t i = 0; OB_SUCC(ret) && NULL == rowid_expr && i < table_items.count(); ++i) { if (OB_ISNULL(table_item = table_items.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_item is NULL", K(ret), K(i), K(table_items)); } else if (OB_FAIL(check_can_gen_rowid_on_this_table(select_stmt, table_item, can_gen_rowid))) { LOG_WARN("check_can_gen_rowid failed", K(ret)); } else if (!can_gen_rowid) { LOG_DEBUG("cannot gen rowid in this table item", K(ret), KPC(table_item)); } else if (table_item->is_generated_table() || table_item->is_temp_table()) { if (OB_FAIL(SMART_CALL(recursive_generate_rowid_select_item(table_item->ref_query_, rowid_expr)))) { LOG_WARN("failed to recursive generate rowid select item", K(ret)); } else if (NULL == rowid_expr) { // ignore create rowid item. } else if (OB_FAIL(create_rowid_item_for_stmt(select_stmt, table_item, rowid_expr))) { LOG_WARN("create rowid item for stmt failed", K(ret)); } else if (ObTransformUtils::create_select_item(*(ctx_->allocator_), rowid_expr, select_stmt)) { LOG_WARN("failed to create select item", K(ret)); } else {/*do nothing*/} } else if (OB_FAIL(build_rowid_expr(select_stmt, table_item, rowid_func_expr))) { LOG_WARN("build rowid_expr failed", K(ret), KPC(table_item)); } else if (OB_FAIL(ObTransformUtils::create_select_item(*(ctx_->allocator_), rowid_func_expr, select_stmt))) { LOG_WARN("create_select_item failed", K(ret)); } else { rowid_expr = rowid_func_expr; } } // end for if (OB_SUCC(ret) && OB_ISNULL(rowid_expr)) { ret = OB_ROWID_VIEW_NO_KEY_PRESERVED; LOG_WARN("rowid view no key preserved", K(ret)); LOG_USER_ERROR(OB_ROWID_VIEW_NO_KEY_PRESERVED); } else { LOG_TRACE("succeed to recursive generate rowid select item", KPC(select_stmt), KPC(rowid_expr)); } } return ret; } // select rowid from (select * from t1, t2 where t1.c1 = t2.pk; // t1: this_table // t2: other_table // we check if other_table's join exprs is unique or not, // if is unique, we can generate rowid on this_table int ObTransformPreProcess::check_can_gen_rowid_on_this_table(ObSelectStmt *select_stmt, TableItem *this_table, bool &can_gen_rowid) { int ret = OB_SUCCESS; can_gen_rowid = false; if (OB_ISNULL(select_stmt) || OB_ISNULL(this_table)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt or table_item is null", K(ret), KP(select_stmt), KP(this_table)); } else if (select_stmt->has_group_by() || select_stmt->has_distinct()) { ret = OB_ROWID_VIEW_HAS_DISTINCT_ETC; LOG_WARN("stmt got group by or distinct", K(ret), K(select_stmt->has_group_by()), K(select_stmt->has_distinct())); LOG_USER_ERROR(OB_ROWID_VIEW_HAS_DISTINCT_ETC); } else if (is_ora_sys_view_table(this_table->ref_id_)) { // Because the implementation of these views is differnet from oracle, // therefore, the check is added to prevent these views from trying to build rowid expr // v$sesstat,v$session_wait,v$sysstat ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "view trying to build rowid"); LOG_WARN("stmt got system table", K(ret)); } else { ObSEArray unique_tables; ObSEArray non_unique_tables; ObIArray &table_items = select_stmt->get_table_items(); for (int64_t i = 0; OB_SUCC(ret) && i < table_items.count(); ++i) { TableItem *item = table_items.at(i); if (OB_ISNULL(item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is NULL", K(ret), K(i)); } else if (item->table_id_ == this_table->table_id_) { if (OB_FAIL(unique_tables.push_back(item))) { LOG_WARN("push table item failed", K(ret)); } } else if (OB_FAIL(non_unique_tables.push_back(item))) { LOG_WARN("push table item failed", K(ret)); } } if (OB_SUCC(ret) && non_unique_tables.empty()) { can_gen_rowid = true; } if (OB_SUCC(ret) && !can_gen_rowid) { bool found_unique = true; ObSEArray join_exprs; const ObIArray &cond_exprs = select_stmt->get_condition_exprs(); while (OB_SUCC(ret) && found_unique && !non_unique_tables.empty()) { found_unique = false; for (int64_t i = non_unique_tables.count() - 1; OB_SUCC(ret) && i >= 0; --i) { bool is_unique = false; join_exprs.reuse(); TableItem *table = non_unique_tables.at(i); if (OB_ISNULL(table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is NULL", K(ret)); } else if (OB_FAIL(ObTransformUtils::get_table_joined_exprs(*select_stmt, unique_tables, *table, cond_exprs, join_exprs))) { LOG_WARN("get_table_joined_exprs failed", K(ret)); } else if (join_exprs.empty()) { } else if (OB_FAIL(ObTransformUtils::check_exprs_unique(*select_stmt, table, join_exprs, ctx_->session_info_, ctx_->schema_checker_, is_unique))) { LOG_WARN("check exprs unique failed", K(ret)); } else if (!is_unique) { } else if (OB_FAIL(unique_tables.push_back(table))) { LOG_WARN("push table table failed", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::remove_item(non_unique_tables, table))) { LOG_WARN("remove table table failed", K(ret)); } else { found_unique = true; } } // for end } // while end if (OB_SUCC(ret) && non_unique_tables.empty()) { can_gen_rowid = true; } } LOG_DEBUG("check_can_gen_rowid_on_this_table done", K(ret), KPC(select_stmt), KPC(this_table), K(can_gen_rowid)); } return ret; } int ObTransformPreProcess::build_rowid_expr(ObSelectStmt *select_stmt, TableItem *table_item, ObSysFunRawExpr *&rowid_expr) { int ret = OB_SUCCESS; rowid_expr = NULL; if (OB_ISNULL(select_stmt) || OB_ISNULL(table_item) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->allocator_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt or table_item is NULL", K(ret), KP(select_stmt), KP(table_item), KP(ctx_)); } else { const ObTableSchema *table_schema = NULL; ObSEArray index_keys; uint64_t tid = table_item->ref_id_; ObRawExpr *same_rowid_expr = NULL; if (OB_FAIL(ctx_->schema_checker_->get_table_schema(ctx_->session_info_->get_effective_tenant_id(), tid, table_schema, table_item->is_link_table()))) { LOG_WARN("fail to get table schema", K(ret), K(tid)); } else if (OB_ISNULL(table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_schema is NULL", K(ret)); } else { const ObRowkeyInfo &rowkey_info = table_schema->get_rowkey_info(); ObColumnRefRawExpr *expr = NULL; for (int i = 0; OB_SUCC(ret) && i < rowkey_info.get_size(); ++i) { uint64_t column_id = OB_INVALID_ID; if (OB_FAIL(rowkey_info.get_column_id(i, column_id))) { LOG_WARN("Failed to get column_id from rowkey_info", K(ret)); } else if (OB_ISNULL(expr = select_stmt->get_column_expr_by_id(table_item->table_id_, column_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null, rowkey column not exists in stmt", K(ret), K(table_item->table_id_), K(column_id)); } else if (OB_FAIL(index_keys.push_back(expr))) { LOG_WARN("failed to add row key expr", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObRawExprUtils::build_rowid_expr(select_stmt, *(ctx_->expr_factory_), *(ctx_->allocator_), *(ctx_->session_info_), *table_schema, table_item->table_id_, index_keys, rowid_expr))) { LOG_WARN("build rowid col_expr failed", K(ret)); } else if (OB_FAIL(select_stmt->check_and_get_same_rowid_expr(rowid_expr, same_rowid_expr))) { LOG_WARN("failed to check and get same rowid expr", K(ret)); } else if (same_rowid_expr != NULL) { rowid_expr = static_cast(same_rowid_expr); } else {/*do nothing*/} } } return ret; } int ObTransformPreProcess::create_rowid_item_for_stmt(ObDMLStmt *dml_stmt, TableItem *table_item, ObRawExpr *&rowid_expr) { int ret = OB_SUCCESS; ObSEArray column_exprs; rowid_expr = NULL; if (OB_ISNULL(dml_stmt) || OB_ISNULL(table_item)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt or item is NULL", K(ret), K(dml_stmt), K(table_item)); } else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *table_item, dml_stmt, column_exprs))) { LOG_WARN("create columns for view failed", K(ret), KPC(table_item), KPC(dml_stmt)); } else if (column_exprs.count() < 1) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column_expr is invalid", K(ret), K(column_exprs)); } else { ObRawExpr *expr = column_exprs.at(column_exprs.count() - 1); if (OB_ISNULL(expr) || OB_UNLIKELY(!(expr->is_column_ref_expr())) || OB_UNLIKELY(!(expr->get_result_type().is_urowid()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("last col must be rowid col", K(ret), KPC(expr)); } else { rowid_expr = expr; } } return ret; } //transform batch update stmt to multiple update with nlj: // update t1 set b=1 where a=1; update t1 set b=2 where a=2; update t1 set b=3 where a=3;... //-> update t1, (select 1, 1 from dual ...) v set t1.b=v.b where t1.a=v.a; // batch delete is as batch update int ObTransformPreProcess::transform_for_upd_del_batch_stmt(ObDMLStmt *batch_stmt, ObSelectStmt *inner_view_stmt, bool &trans_happened) { int ret = OB_SUCCESS; // create select list if (OB_FAIL(mock_select_list_for_upd_del(*batch_stmt, *inner_view_stmt))) { LOG_WARN("mock select list for batch stmt failed", K(ret)); } else if (OB_FAIL(formalize_batch_stmt(batch_stmt, inner_view_stmt, batch_stmt->get_query_ctx()->ab_param_exprs_, trans_happened))) { LOG_WARN("fail to formalize batch stmt", K(ret), KPC(batch_stmt)); } return ret; } int ObTransformPreProcess::transform_for_ins_batch_stmt(ObDMLStmt *batch_stmt, bool &trans_happened) { int ret = OB_SUCCESS; ObInsertStmt *insert_stmt = NULL; ObExecContext *exec_ctx = nullptr; ObPhysicalPlanCtx *plan_ctx = nullptr; ObSQLSessionInfo *session_info = NULL; if (OB_ISNULL(ctx_) || OB_ISNULL(exec_ctx = ctx_->exec_ctx_) || OB_ISNULL(plan_ctx = exec_ctx->get_physical_plan_ctx()) || OB_ISNULL(session_info = ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ctx_), K(exec_ctx), K(plan_ctx), K(ret)); } else if (OB_ISNULL(batch_stmt) || OB_UNLIKELY(!batch_stmt->is_insert_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("batch_stmt or inner_view_stmt is null", K(ret), K(batch_stmt)); } else if (FALSE_IT(insert_stmt = static_cast(batch_stmt))) { } else if (insert_stmt->is_insert_up() || insert_stmt->is_replace()) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; LOG_WARN("insert on duplicate key and replace is not support batch now", K(ret), KPC(batch_stmt)); } else if (insert_stmt->value_from_select()) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; LOG_TRACE("insert select stmt not supported batch exec opt", K(ret), KPC(batch_stmt)); } else { // insert values stmt ObSEArray params; ObPseudoColumnRawExpr *stmt_id_expr = NULL; common::ObIArray &value_desc = insert_stmt->get_values_desc(); common::ObIArray &value_vector = insert_stmt->get_values_vector(); int64_t row_count = value_vector.count() / value_desc.count(); if (row_count > 1) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; LOG_TRACE("insert stmt with multi rows not supported batch exec", K(ret), KPC(batch_stmt)); } else if (OB_FAIL(create_stmt_id_expr(stmt_id_expr))) { LOG_WARN("fail to create stmt id expr", K(ret)); } else if (FALSE_IT(batch_stmt->get_query_ctx()->ins_values_batch_opt_ = true)) { } else if (FALSE_IT(static_cast(batch_stmt)->set_ab_stmt_id_expr(stmt_id_expr))) { } else if (OB_FAIL(ObRawExprUtils::extract_params(value_vector, params))) { LOG_WARN("extract param expr from related exprs failed", K(ret)); } else { const ParamStore ¶m_store = plan_ctx->get_param_store(); for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) { ObConstRawExpr *param_expr = static_cast(params.at(i)); ObPseudoColumnRawExpr *group_id = NULL; int64_t param_idx = param_expr->get_value().get_unknown(); if (param_idx < 0 || param_idx >= param_store.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param_idx is invalid", K(ret), K(param_idx), K(param_store)); } else if (!param_store.at(param_idx).is_batch_parameters()) { // 不是batch 参数, 不需要打标记 } else { param_expr->set_is_batch_stmt_parameter(); } } // 给所有的batch参数表达上边打上了标记,需要重新做表达式推导 // 这里因为insert values的特殊性,所以只需要推导value_vector中的表达式即可 for (int64_t i = 0; OB_SUCC(ret) && i < value_vector.count(); ++i) { if (OB_FAIL(value_vector.at(i)->formalize(session_info))) { LOG_WARN("formalize expr failed", K(ret), K(i), KPC(value_vector.at(i))); } } } } return ret; } int ObTransformPreProcess::check_contain_param_expr(ObDMLStmt *stmt, TableItem *table_item, bool &contain_param) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("failed to check stack overflow", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); } else if (contain_param) { // break; } else { if (table_item->is_joined_table()) { JoinedTable *joined_table_item = static_cast(table_item); if (OB_FAIL(ObRawExprUtils::is_contain_params(joined_table_item->get_join_conditions(), contain_param))) { LOG_WARN("fail to get releation exprs", K(ret)); } else if (OB_FAIL(SMART_CALL(check_contain_param_expr(stmt, joined_table_item->left_table_, contain_param)))) { LOG_WARN("failed to collect temp table item", K(ret)); } else if (OB_FAIL(SMART_CALL(check_contain_param_expr(stmt, joined_table_item->right_table_, contain_param)))) { LOG_WARN("failed to collect temp table item", K(ret)); } } else if (table_item->is_generated_table()) { ObDMLStmt *ref_query_stmt = NULL; if (OB_ISNULL(ref_query_stmt = table_item->ref_query_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ref_query is null", K(ret), KPC(table_item)); } else if (OB_FAIL(check_stmt_contain_param_expr(ref_query_stmt, contain_param))) { LOG_WARN("fail to check contain param expr", K(ret)); } } } return ret; } int ObTransformPreProcess::check_stmt_contain_param_expr(ObDMLStmt *stmt, bool &contain) { int ret = OB_SUCCESS; ObSEArray related_exprs; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret)); } else if (OB_FAIL(stmt->get_relation_exprs(related_exprs))) { LOG_WARN("fail to get releation exprs", K(ret), KPC(stmt)); } else if (OB_FAIL(ObRawExprUtils::is_contain_params(related_exprs, contain))) { LOG_WARN("fail to get releation exprs", K(ret)); } return ret; } int ObTransformPreProcess::check_stmt_can_batch(ObDMLStmt *batch_stmt, bool &contain_param) { int ret = OB_SUCCESS; contain_param = false; if (OB_ISNULL(batch_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("batch_stmt is null", K(ret)); } else { const common::ObIArray &from_items = batch_stmt->get_from_items(); for (int64_t i = 0; OB_SUCC(ret) && !contain_param && i < from_items.count(); ++i) { TableItem *table_item = NULL; const FromItem &from_item = from_items.at(i); if (OB_ISNULL(table_item = batch_stmt->get_table_item(from_item))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table_item is null", K(ret), K(from_item)); } else if (OB_FAIL(check_contain_param_expr(batch_stmt, table_item, contain_param))) { LOG_WARN("fail to check contain param expr", K(ret), KPC(table_item)); } } } return ret; } int ObTransformPreProcess::create_inner_view_stmt(ObDMLStmt *batch_stmt, ObSelectStmt*& inner_view_stmt) { int ret = OB_SUCCESS; ObStmtFactory *stmt_factory = NULL; if (OB_ISNULL(stmt_factory = ctx_->stmt_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ctx_), K(stmt_factory), K(ret)); } else if (OB_FAIL(stmt_factory->create_stmt(inner_view_stmt))) { LOG_WARN("failed to create stmt", K(ret)); } else { inner_view_stmt->set_stmt_type(stmt::T_SELECT); inner_view_stmt->set_current_level(batch_stmt->get_current_level()); inner_view_stmt->set_parent_namespace_stmt(batch_stmt->get_parent_namespace_stmt()); inner_view_stmt->set_query_ctx(batch_stmt->get_query_ctx()); stmt::StmtType stmt_type = batch_stmt->get_stmt_type(); if (OB_FAIL(inner_view_stmt->adjust_statement_id(ctx_->allocator_, ctx_->src_qb_name_, ctx_->src_hash_val_))) { LOG_WARN("failed to recursive adjust statement id", K(ret)); } } return ret; } int ObTransformPreProcess::transform_for_batch_stmt(ObDMLStmt *batch_stmt, bool &trans_happened) { int ret = OB_SUCCESS; ObSelectStmt* inner_view_stmt = NULL; ObExecContext *exec_ctx = nullptr; stmt::StmtType stmt_type = batch_stmt->get_stmt_type(); if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->allocator_) || OB_ISNULL(exec_ctx = ctx_->exec_ctx_) || OB_ISNULL(batch_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ctx_), K(exec_ctx), K(ret)); } else if (!exec_ctx->get_sql_ctx()->multi_stmt_item_.is_batched_multi_stmt()) { //rewrite only when stmt is batch multi statement } else if (!batch_stmt->is_dml_write_stmt()) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; LOG_TRACE("only DML Stmt without subquery supports batch execution, need to rollback", K(ret), K(batch_stmt->get_stmt_type())); } else if (stmt_type == stmt::T_UPDATE || stmt_type == stmt::T_DELETE) { if (OB_FAIL(create_inner_view_stmt(batch_stmt, inner_view_stmt))) { LOG_WARN("fail to create inner_view_stmt", K(ret)); } else if (OB_FAIL(transform_for_upd_del_batch_stmt(batch_stmt, inner_view_stmt, trans_happened))) { LOG_WARN("fail to transform upd or del batch stmt", K(ret)); } } else if (stmt_type == stmt::T_INSERT) { // insert的改写 ObSQLSessionInfo *session_info = NULL; if (OB_ISNULL(session_info = ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is null", K(ret)); } else if (OB_FAIL(transform_for_ins_batch_stmt(batch_stmt, trans_happened))) { LOG_WARN("fail to transform ins batch stmt", K(ret)); } } return ret; } int ObTransformPreProcess::formalize_batch_stmt(ObDMLStmt *batch_stmt, ObSelectStmt* inner_view_stmt, const ObIArray &other_exprs, bool &trans_happened) { int ret = OB_SUCCESS; TableItem *view_table_item = NULL; ObSEArray view_columns; ObSQLSessionInfo *session_info = NULL; if (OB_ISNULL(session_info = ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is null", K(ret)); } else if (OB_FAIL(ObTransformUtils::add_new_table_item(ctx_, batch_stmt, inner_view_stmt, view_table_item))) { //create generated table item for inner view LOG_WARN("failed to add new table item", K(ret)); } else if (OB_ISNULL(view_table_item)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (OB_FAIL(batch_stmt->add_from_item(view_table_item->table_id_, false))) { LOG_WARN("add from item to batch stmt failed", K(ret), KPC(view_table_item)); } else if (OB_FAIL(ObTransformUtils::create_columns_for_view(ctx_, *view_table_item, batch_stmt, view_columns))) { LOG_WARN("failed to create columns for view", K(ret)); } else if (OB_FAIL(batch_stmt->replace_inner_stmt_expr(other_exprs, view_columns))) { LOG_WARN("replace inner stmt expr failed", K(ret)); } else if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(*batch_stmt))) { LOG_WARN("failed to adjust pseudo column like exprs", K(ret)); } else if (OB_FAIL(batch_stmt->formalize_stmt(session_info))) { LOG_WARN("failed to formalize stmt", K(ret)); } else { trans_happened = true; ObRawExpr *ab_stmt_id = view_columns.at(view_columns.count() - 1); static_cast(batch_stmt)->set_ab_stmt_id_expr(ab_stmt_id); LOG_DEBUG("debug transform_for_batch_stmt", K(batch_stmt->get_query_ctx()->ab_param_exprs_), K(view_columns)); } return ret; } int ObTransformPreProcess::create_stmt_id_expr(ObPseudoColumnRawExpr *&stmt_id_expr) { int ret = OB_SUCCESS; ObRawExprFactory *expr_factory = NULL; if (OB_ISNULL(expr_factory = ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("assign value_vector failed", K(ret)); } else if (OB_FAIL(expr_factory->create_raw_expr(T_PSEUDO_STMT_ID, stmt_id_expr))) { LOG_WARN("create pseudo column raw expr failed", K(ret)); } else if (OB_ISNULL(stmt_id_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt id expr is null", K(ret)); } else { stmt_id_expr->set_data_type(ObIntType); stmt_id_expr->set_accuracy(ObAccuracy::MAX_ACCURACY[ObIntType]); stmt_id_expr->set_table_id(OB_INVALID_ID); stmt_id_expr->set_explicited_reference(); stmt_id_expr->set_expr_name(ObString::make_string("stmt_id")); } return ret; } int ObTransformPreProcess::create_params_expr(ObPseudoColumnRawExpr *&pseudo_param_expr, ObRawExpr *origin_param_expr, int64_t name_id) { int ret = OB_SUCCESS; char *pseudo_name = nullptr; ObRawExprFactory *expr_factory = NULL; const int64_t buf_len = 64; int64_t pos = 0; if (OB_ISNULL(expr_factory = ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("assign value_vector failed", K(ret)); } else if (OB_ISNULL(pseudo_name = static_cast(ctx_->allocator_->alloc(buf_len)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate name buffer failed", K(ret)); } else if (OB_FAIL(databuff_printf(pseudo_name, buf_len, pos, "group_param_%ld", name_id))) { LOG_WARN("databuff print column name failed", K(ret)); } else if (OB_FAIL(expr_factory->create_raw_expr(T_PSEUDO_GROUP_PARAM, pseudo_param_expr))) { LOG_WARN("create pseudo colmn raw expr failed", K(ret)); } else { pseudo_param_expr->set_expr_name(ObString(pos, pseudo_name)); pseudo_param_expr->set_result_type(origin_param_expr->get_result_type()); pseudo_param_expr->set_table_id(OB_INVALID_ID); pseudo_param_expr->set_explicited_reference(); } return ret; } int ObTransformPreProcess::create_params_exprs(ObDMLStmt &batch_stmt, ObIArray ¶ms_exprs) { int ret = OB_SUCCESS; const ObIArray &ab_param_exprs = batch_stmt.get_query_ctx()->ab_param_exprs_; for (int64_t i = 0; OB_SUCC(ret) && i < ab_param_exprs.count(); i++) { ObPseudoColumnRawExpr *group_param_expr = nullptr; if (OB_FAIL(create_params_expr(group_param_expr, ab_param_exprs.at(i), i))) { LOG_WARN("create pseudo colmn raw expr failed", K(ret), K(i), K(ab_param_exprs)); } else if (OB_ISNULL(group_param_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("group_param_expr is null", K(ret)); } else if (OB_FAIL(params_exprs.push_back(group_param_expr))) { LOG_WARN("fail to push group param exprs", K(ret), KPC(group_param_expr), K(params_exprs)); } } return ret; } // 1、make value_vector as select_list,then extract_calculable_expr // 2、after pre_calc, generate the mock select_list for inner_view int ObTransformPreProcess::mock_select_list_for_ins_values(ObDMLStmt &batch_stmt, ObSelectStmt &inner_view, bool &trans_happened) { int ret = OB_SUCCESS; ObExecContext *exec_ctx = nullptr; ObPhysicalPlanCtx *plan_ctx = nullptr; const ParamStore *param_store = nullptr; ObSEArray select_list; ObInsertStmt &insert_stmt = static_cast(batch_stmt); ObIArray &value_vector = insert_stmt.get_values_vector(); ObIArray &value_descs = insert_stmt.get_values_desc(); if (OB_ISNULL(ctx_) || OB_ISNULL(exec_ctx = ctx_->exec_ctx_) || OB_ISNULL(plan_ctx = exec_ctx->get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ctx_), K(exec_ctx), K(plan_ctx), K(ret)); } else { param_store = &plan_ctx->get_param_store(); } for (int64_t i = 0; OB_SUCC(ret) && i < value_vector.count(); ++i) { ObConstRawExpr *param_expr = static_cast(value_vector.at(i)); ObRawExpr *value_desc = value_descs.at(i); int64_t param_idx = param_expr->get_value().get_unknown(); if (param_idx < 0 || param_idx >= param_store->count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param_idx is invalid", K(ret), K(param_idx), KPC(param_store)); } else { ObPseudoColumnRawExpr *group_param_expr = nullptr; //create pseudo column for the sql array param if (OB_FAIL(create_params_expr(group_param_expr, value_desc, select_list.count()))) { LOG_WARN("fail to create group param expr", K(ret), K(value_desc)); } else if (OB_FAIL(batch_stmt.get_query_ctx()->ab_param_exprs_.push_back(param_expr))) { LOG_WARN("add param expr to select list exprs failed", K(ret)); } else if (OB_FAIL(select_list.push_back(group_param_expr))) { LOG_WARN("store group id expr failed", K(ret)); } } } //create stmt id expr with inner view if (OB_SUCC(ret)) { ObPseudoColumnRawExpr *stmt_id_expr = NULL; if (OB_FAIL(create_stmt_id_expr(stmt_id_expr))) { LOG_WARN("fail to create stmt id expr", K(ret)); } else if (OB_FAIL(select_list.push_back(stmt_id_expr))) { LOG_WARN("store select id expr failed", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, select_list, &inner_view))) { LOG_WARN("failed to create select items", K(ret)); } else if (!batch_stmt.get_query_ctx()->ab_param_exprs_.empty()) { inner_view.set_ab_param_flag(true); batch_stmt.get_query_ctx()->ins_values_batch_opt_ = true; } } return ret; } int ObTransformPreProcess::mock_select_list_for_ins_select(ObDMLStmt &batch_stmt, ObSelectStmt &inner_view, bool &trans_happened) { int ret = OB_SUCCESS; const ParamStore *param_store = nullptr; ObExecContext *exec_ctx = nullptr; ObPhysicalPlanCtx *plan_ctx = nullptr; ObSEArray params; ObSEArray related_exprs; ObSEArray select_list; int64_t child_size = 0; bool need_rollback = false; if (OB_ISNULL(ctx_) || OB_ISNULL(exec_ctx = ctx_->exec_ctx_) || OB_ISNULL(plan_ctx = exec_ctx->get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ctx_), K(exec_ctx), K(plan_ctx), K(ret)); } else if (OB_ISNULL(param_store = &plan_ctx->get_param_store())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param store is null", K(ret)); } else if (batch_stmt.get_child_stmt_size(child_size)) { LOG_WARN("get child size failed", K(ret)); } else if (child_size > 0) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; LOG_WARN("child size greater than 0", K(ret), K(child_size)); } else if (OB_FAIL(check_stmt_can_batch(&batch_stmt, need_rollback))) { LOG_WARN("fail to check multi_batch stmt", K(ret)); } else if (need_rollback) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; } else if (OB_FAIL(batch_stmt.get_relation_exprs(related_exprs))) { LOG_WARN("get relation exprs failed", K(ret)); } else if (OB_FAIL(ObRawExprUtils::extract_params(related_exprs, params))) { LOG_WARN("extract param expr from related exprs failed", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) { ObConstRawExpr *param_expr = static_cast(params.at(i)); ObPseudoColumnRawExpr *group_id = NULL; int64_t param_idx = param_expr->get_value().get_unknown(); if (param_idx < 0 || param_idx >= param_store->count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param_idx is invalid", K(ret), K(param_idx), KPC(param_store)); } else if (param_store->at(param_idx).is_ext_sql_array() && !has_exist_in_array(batch_stmt.get_query_ctx()->ab_param_exprs_, static_cast(param_expr))) { ObPseudoColumnRawExpr *group_param_expr = nullptr; //create pseudo column for the sql array param if (OB_FAIL(create_params_expr(group_param_expr, param_expr, select_list.count()))) { LOG_WARN("fail to create group param expr", K(ret), K(param_expr)); } else if (OB_FAIL(batch_stmt.get_query_ctx()->ab_param_exprs_.push_back(param_expr))) { LOG_WARN("add param expr to select list exprs failed", K(ret)); } else if (OB_FAIL(select_list.push_back(group_param_expr))) { LOG_WARN("store group id expr failed", K(ret)); } } } //create stmt id expr with inner view if (OB_SUCC(ret)) { ObPseudoColumnRawExpr *stmt_id_expr = NULL; if (OB_FAIL(create_stmt_id_expr(stmt_id_expr))) { LOG_WARN("fail to create stmt id expr", K(ret)); } else if (OB_FAIL(select_list.push_back(stmt_id_expr))) { LOG_WARN("store select id expr failed", K(ret)); } } // create select item if (OB_SUCC(ret)) { if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, select_list, &inner_view))) { LOG_WARN("failed to create select items", K(ret)); } else if (!batch_stmt.get_query_ctx()->ab_param_exprs_.empty()) { inner_view.set_ab_param_flag(true); } } } return ret; } int ObTransformPreProcess::mock_select_list_for_upd_del(ObDMLStmt &batch_stmt, ObSelectStmt &inner_view) { int ret = OB_SUCCESS; const ParamStore *param_store = nullptr; ObExecContext *exec_ctx = nullptr; ObPhysicalPlanCtx *plan_ctx = nullptr; ObSEArray params; ObSEArray related_exprs; ObSEArray select_list; int64_t child_stmts_size = 0; if (OB_ISNULL(ctx_) || OB_ISNULL(exec_ctx = ctx_->exec_ctx_) || OB_ISNULL(plan_ctx = exec_ctx->get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ctx_), K(exec_ctx), K(plan_ctx), K(ret)); } else if (OB_FAIL(batch_stmt.get_child_stmt_size(child_stmts_size))) { LOG_WARN("get child_stmt size failed", K(ret)); } else if (child_stmts_size != 0) { ret = OB_BATCHED_MULTI_STMT_ROLLBACK; LOG_WARN("for delete or update batch exec, child_stmt_size != 0", K(ret), K(child_stmts_size)); } else { param_store = &plan_ctx->get_param_store(); if (OB_FAIL(batch_stmt.get_relation_exprs(related_exprs))) { LOG_WARN("get relation exprs failed", K(ret)); } else if (OB_FAIL(ObRawExprUtils::extract_params(related_exprs, params))) { LOG_WARN("extract param expr from related exprs failed", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) { ObConstRawExpr *param_expr = static_cast(params.at(i)); ObPseudoColumnRawExpr *group_id = NULL; int64_t param_idx = param_expr->get_value().get_unknown(); if (param_idx < 0 || param_idx >= param_store->count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param_idx is invalid", K(ret), K(param_idx), KPC(param_store)); } else if (param_store->at(param_idx).is_batch_parameters() && !has_exist_in_array(batch_stmt.get_query_ctx()->ab_param_exprs_, static_cast(param_expr))) { ObPseudoColumnRawExpr *group_param_expr = nullptr; ObSqlArrayObj *array_obj = reinterpret_cast(param_store->at(param_idx).get_ext()); //create pseudo column for the sql array param if (OB_FAIL(create_params_expr(group_param_expr, param_expr, select_list.count()))) { LOG_WARN("fail to create group param expr", K(ret), K(param_expr)); } else if (OB_FAIL(batch_stmt.get_query_ctx()->ab_param_exprs_.push_back(param_expr))) { LOG_WARN("add param expr to select list exprs failed", K(ret)); } else if (OB_FAIL(select_list.push_back(group_param_expr))) { LOG_WARN("store group id expr failed", K(ret)); } } } //create stmt id expr with inner view if (OB_SUCC(ret)) { ObPseudoColumnRawExpr *stmt_id_expr = NULL; if (OB_FAIL(create_stmt_id_expr(stmt_id_expr))) { LOG_WARN("fail to create stmt id expr", K(ret)); } else if (OB_FAIL(select_list.push_back(stmt_id_expr))) { LOG_WARN("store select id expr failed", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, select_list, &inner_view))) { LOG_WARN("failed to create select items", K(ret)); } else if (!batch_stmt.get_query_ctx()->ab_param_exprs_.empty()) { inner_view.set_ab_param_flag(true); } } return ret; } int ObTransformPreProcess::transform_full_outer_join(ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; ObSEArray joined_tables; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(stmt)); } else if (OB_FAIL(joined_tables.assign(stmt->get_joined_tables()))) { LOG_WARN("failed to assign joined table", K(ret)); } else { bool is_happened = false; for (int64_t i = 0; OB_SUCC(ret) && i < joined_tables.count(); ++i) { if (OB_ISNULL(joined_tables.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(i), K(joined_tables)); } else if (OB_FAIL(recursively_eliminate_full_join(*stmt, *joined_tables.at(i), is_happened))) { LOG_WARN("failed to recursively eliminate full join", K(ret)); } else { trans_happened |= is_happened; } } } return ret; } int ObTransformPreProcess::recursively_eliminate_full_join(ObDMLStmt &stmt, TableItem &table_item, bool &trans_happened) { int ret = OB_SUCCESS; JoinedTable *joined_table = NULL; TableItem *view_table = NULL; bool has_euqal = false; bool has_subquery = false; if (!table_item.is_joined_table()) { /* do nothing */ } else if (OB_FALSE_IT(joined_table = static_cast(&table_item))) { } else 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(recursively_eliminate_full_join(stmt, *joined_table->left_table_, trans_happened))) { LOG_WARN("failed to transform full nl join.", K(ret)); } else if (OB_FAIL(recursively_eliminate_full_join(stmt, *joined_table->right_table_, trans_happened))) { LOG_WARN("failed to transform full nl join.", K(ret)); } else if (!joined_table->is_full_join()) { /* do nothing */ } else if (OB_FAIL(check_join_condition(&stmt, joined_table, has_euqal, has_subquery))) { LOG_WARN("failed to check join condition", K(ret)); } else if (has_euqal || has_subquery) { /* do nothing */ } else if (OB_FAIL(ObTransformUtils::create_view_with_table(&stmt, ctx_, joined_table, view_table))) { LOG_WARN("failed to create view with table", K(ret)); } else if (OB_FAIL(expand_full_outer_join(view_table->ref_query_))) { LOG_WARN("failed to create view for full nl join.", K(ret)); } else { trans_happened = true; } return ret; } int ObTransformPreProcess::check_join_condition(ObDMLStmt *stmt, JoinedTable *table, bool &has_equal, bool &has_subquery) { int ret = OB_SUCCESS; has_equal = false; has_subquery = false; ObSqlBitSet<> left_tables; ObSqlBitSet<> right_tables; if (OB_ISNULL(stmt) || OB_ISNULL(table) || OB_ISNULL(table->left_table_) || OB_ISNULL(table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); } else if (OB_FAIL(stmt->get_table_rel_ids(*table->left_table_, left_tables))) { LOG_WARN("failed to get table rel ids", K(ret)); } else if (OB_FAIL(stmt->get_table_rel_ids(*table->right_table_, right_tables))) { LOG_WARN("failed to get table rel ids", K(ret)); } else { ObRawExpr *cond = NULL; ObRawExpr *left_param = NULL; ObRawExpr *right_param = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < table->join_conditions_.count(); i++) { if (OB_ISNULL(cond = table->join_conditions_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null condition", K(ret)); } else if (OB_FALSE_IT(has_subquery |= cond->has_flag(CNT_SUB_QUERY))) { } else if (cond->get_relation_ids().is_empty() || !cond->has_flag(IS_JOIN_COND)) { /* do nothing */ } else if (OB_UNLIKELY(cond->get_param_count() != 2) || OB_ISNULL(left_param = cond->get_param_expr(0)) || OB_ISNULL(right_param = cond->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null param", K(ret)); } else if ((left_param->get_relation_ids().is_subset(left_tables) && right_param->get_relation_ids().is_subset(right_tables)) || (right_param->get_relation_ids().is_subset(left_tables) && left_param->get_relation_ids().is_subset(right_tables))) { has_equal = true; } } } return ret; } int ObTransformPreProcess::expand_full_outer_join(ObSelectStmt *&ref_query) { int ret = OB_SUCCESS; ObSelectStmt *left_stmt = NULL; ObSelectStmt *right_stmt = NULL; ObSelectStmt *union_stmt = NULL; JoinedTable *joined_table = NULL; const int64_t sub_num = 1; if (OB_ISNULL(left_stmt = ref_query) || OB_UNLIKELY(left_stmt->get_joined_tables().count() != 1) || OB_ISNULL(joined_table = left_stmt->get_joined_tables().at(0)) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->stmt_factory_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected joined table count.", K(ret), K(ctx_), K(left_stmt), K(joined_table)); } else if (OB_FALSE_IT(joined_table->joined_type_ = LEFT_OUTER_JOIN)) { } else if (OB_FAIL(ctx_->stmt_factory_->create_stmt(right_stmt))) { LOG_WARN("failed to create select stmt", K(ret)); } else if (OB_FAIL(SMART_CALL(right_stmt->deep_copy(*ctx_->stmt_factory_, *ctx_->expr_factory_, *left_stmt)))) { LOG_WARN("failed to deep copy select stmt", K(ret)); } else if (OB_FAIL(right_stmt->recursive_adjust_statement_id(ctx_->allocator_, ctx_->src_hash_val_, sub_num))) { LOG_WARN("failed to recursive adjust statement id", K(ret)); } else if (OB_FAIL(right_stmt->update_stmt_table_id(*left_stmt))) { LOG_WARN("failed to updatew table id in stmt.", K(ret)); } else if (right_stmt->get_joined_tables().count() != 1) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected joined table count.", K(ret), K(right_stmt->get_joined_tables())); } else if (OB_FAIL(switch_left_outer_to_semi_join(right_stmt, right_stmt->get_joined_tables().at(0), right_stmt->get_select_items()))) { LOG_WARN("failed to switch join table to semi.", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_set_stmt(ctx_, ObSelectStmt::UNION, false, left_stmt, right_stmt, union_stmt))) { LOG_WARN("failed to create union stmt.", K(ret)); } else if (OB_ISNULL(union_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(union_stmt)); } else { ref_query = union_stmt; } return ret; } int ObTransformPreProcess::switch_left_outer_to_semi_join(ObSelectStmt *&sub_stmt, JoinedTable *joined_table, const ObIArray &select_items) { int ret = OB_SUCCESS; SemiInfo *semi_info = NULL; ObSEArray output_select_items; TableItem *view_item = NULL; ObSEArray from_items; ObSEArray semi_infos; ObSEArray joined_tables; if (OB_ISNULL(joined_table) || OB_ISNULL(sub_stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null pointer.", K(ret)); } else if (OB_ISNULL(joined_table->left_table_) || OB_ISNULL(joined_table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null pointer.", K(ret)); } else if (joined_table->left_table_->is_joined_table() && OB_FAIL(ObTransformUtils::create_view_with_table(sub_stmt, ctx_, joined_table->left_table_, view_item))) { LOG_WARN("failed to create view with table", K(ret)); } else if (OB_ISNULL(semi_info = static_cast(ctx_->allocator_->alloc( sizeof(SemiInfo))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to alloc semi info", K(ret)); } else if (FALSE_IT(semi_info = new(semi_info)SemiInfo())) { } else if (OB_FAIL(semi_infos.push_back(semi_info))) { LOG_WARN("failed to push back semi info", K(ret)); } else if (joined_table->right_table_->type_ == TableItem::JOINED_TABLE && OB_FAIL(joined_tables.push_back(static_cast(joined_table->right_table_)))) { LOG_WARN("failed push back joined table.", K(ret)); } else if (OB_FAIL(create_select_items_for_semi_join(sub_stmt, joined_table->left_table_, select_items, output_select_items))) { LOG_WARN("failed to assign to column itmes.", K(ret)); } else if (OB_FAIL(sub_stmt->get_select_items().assign(output_select_items))) { LOG_WARN("failed to assign select items.", K(ret)); } else if (OB_FAIL(semi_info->semi_conditions_.assign(joined_table->join_conditions_))) { LOG_WARN("failed to assign to condition exprs.", K(ret)); } else { FromItem from_item; from_item.is_joined_ = joined_table->right_table_->type_ == TableItem::JOINED_TABLE; from_item.table_id_ = joined_table->right_table_->table_id_; semi_info->join_type_ = LEFT_ANTI_JOIN; semi_info->right_table_id_ = joined_table->left_table_->table_id_; semi_info->semi_id_ = sub_stmt->get_query_ctx()->available_tb_id_--; if (OB_FAIL(from_items.push_back(from_item))) { LOG_WARN("failed to push back from item", K(ret)); } else if (from_item.is_joined_) { JoinedTable *table = static_cast(joined_table->right_table_); ret = semi_info->left_table_ids_.assign(table->single_table_ids_); } else { ret = semi_info->left_table_ids_.push_back(from_item.table_id_); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(sub_stmt->get_joined_tables().assign(joined_tables))) { LOG_WARN("failed to assign join table.", K(ret)); } else if (OB_FAIL(sub_stmt->get_semi_infos().assign(semi_infos))) { LOG_WARN("failed to assign semi infos.", K(ret)); } else if (OB_FAIL(sub_stmt->get_from_items().assign(from_items))) { LOG_WARN("failed to assign from items.", K(ret)); } else if (OB_FAIL(sub_stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize stmt", K(ret)); } return ret; } int ObTransformPreProcess::create_select_items_for_semi_join(ObDMLStmt *stmt, TableItem *table_item, const ObIArray &select_items, ObIArray &output_select_items) { int ret = OB_SUCCESS; ObSqlBitSet<> index_left; if (OB_ISNULL(stmt) || OB_ISNULL(table_item) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null error.", K(ret)); } else if (OB_FAIL(extract_idx_from_table_items(stmt, table_item, index_left))) { LOG_WARN("failed to extract idx from join table.", K(ret)); } else if (OB_FAIL(output_select_items.assign(select_items))) { LOG_WARN("failed to assign select items", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < output_select_items.count(); i++) { if (output_select_items.at(i).expr_->get_relation_ids().overlap(index_left)) { ObRawExpr *null_expr = NULL; ObRawExpr *cast_expr = NULL; if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx_->expr_factory_, null_expr))) { LOG_WARN("failed build null exprs.", K(ret)); } else if (OB_ISNULL(null_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect null expr", K(ret)); } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above( ctx_->expr_factory_, ctx_->session_info_, *null_expr, output_select_items.at(i).expr_->get_result_type(), cast_expr))) { LOG_WARN("try add cast expr above failed", K(ret)); } else { output_select_items.at(i).expr_ = cast_expr; } } else { /*do nothing.*/ } } return ret; } int ObTransformPreProcess::extract_idx_from_table_items(ObDMLStmt *sub_stmt, const TableItem *table_item, ObSqlBitSet<> &rel_ids) { int ret = OB_SUCCESS; if (OB_ISNULL(table_item) || OB_ISNULL(sub_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null error.", K(ret)); } else if (table_item->is_joined_table()) { const JoinedTable *joined_table = static_cast(table_item); if (OB_FAIL(extract_idx_from_table_items(sub_stmt, joined_table->left_table_, rel_ids))) { LOG_WARN("failed to extract idx from join table.", K(ret)); } else if (OB_FAIL(extract_idx_from_table_items(sub_stmt, joined_table->right_table_, rel_ids))) { LOG_WARN("failed to extract idx from join table.", K(ret)); } else {} } else { if (OB_FAIL(rel_ids.add_member(sub_stmt->get_table_bit_index(table_item->table_id_)))) { LOG_WARN("failed to add member to rel ids.", K(ret)); } else {} } return ret; } } // end namespace sql } // end namespace oceanbase