/** * 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 "ob_transform_min_max.h" #include "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/schema/ob_column_schema.h" #include "share/schema/ob_table_schema.h" #include "sql/resolver/ob_resolver_utils.h" #include "sql/resolver/dml/ob_select_stmt.h" #include "sql/resolver/expr/ob_raw_expr.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/resolver/expr/ob_raw_expr_resolver_impl.h" #include "sql/ob_sql_context.h" #include "sql/rewrite/ob_transform_utils.h" #include "sql/optimizer/ob_optimizer_util.h" using namespace oceanbase::common; using namespace oceanbase::share::schema; namespace oceanbase { namespace sql { ObTransformMinMax::ObTransformMinMax(ObTransformerCtx *ctx) : ObTransformRule(ctx, TransMethod::POST_ORDER, T_FAST_MINMAX) { } ObTransformMinMax::~ObTransformMinMax() { } int ObTransformMinMax::transform_one_stmt(common::ObIArray &parent_stmts, ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; bool is_valid = false; trans_happened = false; UNUSED(parent_stmts); if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(stmt), K(ctx_)); } else if (!stmt->is_select_stmt()) { //do nothing OPT_TRACE("not select stmt"); } else if (OB_FAIL(check_transform_validity(*ctx_, static_cast(stmt), is_valid))) { LOG_WARN("failed to check transform validity", K(ret)); } else if (!is_valid) { //do nothing OPT_TRACE("can not do min max transform"); } else if (OB_FAIL(do_transform(static_cast(stmt)))) { LOG_WARN("failed to transform column aggregate", K(ret)); } else if (OB_FAIL(add_transform_hint(*stmt))) { LOG_WARN("failed to add transform hint", K(ret)); } else { trans_happened = true; } return ret; } int ObTransformMinMax::check_transform_validity(ObTransformerCtx &ctx, ObSelectStmt *select_stmt, bool &is_valid) { int ret = OB_SUCCESS; is_valid = false; bool has_rownum = false; if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(select_stmt)); } else if (select_stmt->has_recursive_cte() || select_stmt->has_hierarchical_query()) { OPT_TRACE("stmt has recusive cte or hierarchical query"); } else if (select_stmt->get_from_item_size() != 1 || select_stmt->get_from_item(0).is_joined_ || select_stmt->get_aggr_item_size() < 1 || !select_stmt->is_scala_group_by() || select_stmt->is_contains_assignment() || (select_stmt->get_aggr_item_size() > 1 && select_stmt->get_semi_info_size() > 0)) { OPT_TRACE("not a simple aggr query"); } else if (OB_FAIL(select_stmt->has_rownum(has_rownum))) { LOG_WARN("failed to check if select stmt has rownum", K(ret)); } else if (has_rownum) { OPT_TRACE("stmt has rownum"); } else if (OB_FAIL(is_valid_aggr_items(ctx, *select_stmt, is_valid))) { LOG_WARN("failed to check aggr items", K(ret)); } else if (!is_valid) { OPT_TRACE("aggr expr is invalid"); } else if (OB_FAIL(is_valid_select_list(*select_stmt, is_valid))) { LOG_WARN("failed to check is valid select list", K(ret)); } else if (!is_valid) { OPT_TRACE("select list is not const or aggr_expr"); } else if (OB_FAIL(is_valid_having_list(*select_stmt, is_valid))) { LOG_WARN("failed to check is valid having", K(ret)); } else if (!is_valid) { OPT_TRACE("having condition is invalid"); } else if (select_stmt->get_aggr_item_size() > 1 && OB_FAIL(is_valid_order_list(*select_stmt, is_valid))) { LOG_WARN("failed to check is valid order by", K(ret)); } else if (!is_valid) { OPT_TRACE("order by is invalid for multi min/max"); } else { LOG_TRACE("Succeed to check minmax transform validity", K(is_valid)); } return ret; } int ObTransformMinMax::do_transform(ObSelectStmt *select_stmt) { int ret = OB_SUCCESS; if (OB_ISNULL(select_stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("params have null", K(ret), K(select_stmt)); } else if (select_stmt->get_aggr_item_size() == 1) { if (OB_FAIL(do_single_minmax_transform(select_stmt))) { LOG_WARN("failed to transform single minmax", K(ret)); } } else if (select_stmt->get_aggr_item_size() > 1) { if (OB_FAIL(do_multi_minmax_transform(select_stmt))) { LOG_WARN("failed to transform multi minmax", K(ret)); } } return ret; } int ObTransformMinMax::do_single_minmax_transform(ObSelectStmt *select_stmt) { int ret = OB_SUCCESS; ObRawExpr *aggr_param = NULL; ObRawExpr *new_aggr_param = NULL; ObSelectStmt *child_stmt = NULL; ObSEArray old_exprs; ObSEArray new_exprs; if (OB_ISNULL(select_stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("params have null", K(ret), K(select_stmt), K(ctx_)); } else if (select_stmt->get_aggr_item_size() != 1) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected param", K(ret)); } else { ObAggFunRawExpr *aggr_expr = select_stmt->get_aggr_item(0); ObRawExprCopier copier(*ctx_->expr_factory_); if (OB_ISNULL(aggr_expr) || OB_ISNULL(aggr_param = aggr_expr->get_param_expr(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("aggr expr unexpected null", K(ret)); } else if (OB_FAIL(ObTransformUtils::create_simple_view(ctx_, select_stmt, child_stmt))) { LOG_WARN("failed to create simple view", K(ret)); } else if (OB_FAIL(select_stmt->get_column_exprs(old_exprs))) { LOG_WARN("failed to get column exprs", K(ret)); } else if (OB_FAIL(child_stmt->get_select_exprs(new_exprs))) { LOG_WARN("failed to get select exprs", K(ret)); } else if (OB_FAIL(copier.add_replaced_expr(old_exprs, new_exprs))) { LOG_WARN("failed to add replace pair", K(ret)); } else if (OB_FAIL(copier.copy(aggr_param, new_aggr_param))) { LOG_WARN("failed to copy expr", K(ret)); } else if (OB_FAIL(set_child_condition(child_stmt, new_aggr_param))) { LOG_WARN("failed to set child condition", K(ret)); } else if (OB_FAIL(set_child_order_item(child_stmt, new_aggr_param, aggr_expr->get_expr_type()))) { LOG_WARN("failed to set child order item", K(ret)); } else if (OB_FAIL(ObTransformUtils::set_limit_expr(child_stmt, ctx_))) { LOG_WARN("failed to set child limit item", K(ret)); } else { LOG_TRACE("Succeed to do transform min max", K(*select_stmt)); } } return ret; } int ObTransformMinMax::do_multi_minmax_transform(ObSelectStmt *select_stmt) { int ret = OB_SUCCESS; ObSelectStmt *view_child_stmt = NULL; ObSelectStmt *child_stmt = NULL; ObAggFunRawExpr *aggr_expr = NULL; ObRawExpr *aggr_param = NULL; ObRawExpr *new_aggr_param = NULL; ObSEArray old_exprs; ObSEArray new_exprs; ObArray aggr_items; ObArray query_ref_exprs; ObQueryRefRawExpr *query_ref_expr = NULL; ObRawExpr *target_expr = NULL; if (OB_ISNULL(select_stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("params have null", K(ret), K(select_stmt), K(ctx_)); } else { ObRawExprCopier copier(*ctx_->expr_factory_); if (OB_FAIL(ObTransformUtils::create_simple_view(ctx_, select_stmt, view_child_stmt))) { LOG_WARN("failed to create simple view", K(ret)); } else if (OB_FAIL(select_stmt->get_column_exprs(old_exprs))) { LOG_WARN("failed to get column exprs", K(ret)); } else if (OB_FAIL(view_child_stmt->get_select_exprs(new_exprs))) { LOG_WARN("failed to get select exprs", K(ret)); } else if (OB_FAIL(copier.add_replaced_expr(old_exprs, new_exprs))) { LOG_WARN("failed to add replace pair", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_aggr_item_size(); ++i) { if (OB_ISNULL(aggr_expr = select_stmt->get_aggr_item(i)) || OB_ISNULL(aggr_param = aggr_expr->get_param_expr(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (OB_FAIL(copier.copy(aggr_param, new_aggr_param))) { LOG_WARN("failed to copy expr", K(ret)); } else if (OB_FAIL(deep_copy_subquery_for_aggr(*view_child_stmt, new_aggr_param, aggr_expr->get_expr_type(), child_stmt))) { LOG_WARN("failed to deep copy subquery for aggr", K(ret)); } else if (OB_FAIL(aggr_items.push_back(aggr_expr))) { LOG_WARN("failed to push back aggr item", K(ret)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_REF_QUERY, query_ref_expr))) { LOG_WARN("failed to create query ref expr", K(ret)); } else if (OB_ISNULL(query_ref_expr) || OB_ISNULL(child_stmt) || OB_UNLIKELY(child_stmt->get_select_item_size() != 1) || OB_ISNULL(target_expr = child_stmt->get_select_item(0).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr or select item size of child stmt", K(ret)); } else { query_ref_expr->set_ref_stmt(child_stmt); query_ref_expr->set_output_column(1); if (OB_FAIL(query_ref_expr->add_column_type(target_expr->get_result_type()))) { LOG_WARN("add column type to subquery ref expr failed", K(ret)); } else if (OB_FAIL(query_ref_expr->formalize(ctx_->session_info_))) { LOG_WARN("failed to formalize coalesce query expr", K(ret)); } else if (OB_FAIL(query_ref_exprs.push_back(query_ref_expr))) { LOG_WARN("failed to push back query ref expr", K(ret)); } } } // adjust select_stmt if (OB_FAIL(ret)) { } else if (OB_FAIL(select_stmt->replace_relation_exprs(aggr_items, query_ref_exprs))) { LOG_WARN("failed to replace aggr exprs to query ref exprs", K(ret)); } else if (OB_FAIL(select_stmt->get_condition_exprs().assign(select_stmt->get_having_exprs()))) { LOG_WARN("failed to assign condition exprs", K(ret)); } else { select_stmt->get_from_items().reset(); select_stmt->get_table_items().reset(); select_stmt->get_aggr_items().reset(); select_stmt->get_having_exprs().reset(); select_stmt->get_column_items().reset(); if (OB_FAIL(select_stmt->adjust_subquery_list())) { LOG_WARN("failed to adjust subquery list", K(ret)); } else if (OB_FAIL(select_stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize stmt", K(ret)); } else { LOG_TRACE("succeed to do transform min max", KPC(select_stmt)); } } } return ret; } int ObTransformMinMax::deep_copy_subquery_for_aggr(const ObSelectStmt &copied_stmt, ObRawExpr *aggr_param, ObItemType aggr_type, ObSelectStmt *&child_stmt) { int ret = OB_SUCCESS; ObDMLStmt *dml_stmt = NULL; ObRawExpr *new_aggr_param = NULL; ObString qb_name; TableItem *table = NULL; ObArray select_exprs; ObArray new_select_exprs; int64_t new_aggr_param_index = -1; if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->stmt_factory_) || OB_ISNULL(ctx_->allocator_) || OB_ISNULL(aggr_param)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("params have null", K(ret), K(aggr_param), K(ctx_)); } else if (OB_FAIL(ObTransformUtils::deep_copy_stmt(*ctx_->stmt_factory_, *ctx_->expr_factory_, &copied_stmt, dml_stmt))) { LOG_WARN("failed to deep copy stmt", K(ret)); } else if (OB_ISNULL(child_stmt = static_cast(dml_stmt))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child stmt is null", K(ret)); } else if (OB_FAIL(child_stmt->adjust_statement_id(ctx_->allocator_, ctx_->src_qb_name_, ctx_->src_hash_val_))) { LOG_WARN("failed to adjust statement id", K(ret)); } else if (OB_FAIL(child_stmt->get_qb_name(qb_name))) { LOG_WARN("failed to get qb name", K(ret)); } else if (child_stmt->get_table_size() != 1 || OB_ISNULL(table = child_stmt->get_table_item(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected table size or table item is null", K(ret), KPC(child_stmt)); } else if (OB_FALSE_IT(table->qb_name_ = qb_name)) { } else if (OB_FAIL(child_stmt->update_stmt_table_id(ctx_->allocator_, copied_stmt))) { LOG_WARN("failed to update stmt table id", K(ret)); } else if (OB_FAIL(copied_stmt.get_select_exprs(select_exprs))) { LOG_WARN("failed to get select exprs", K(ret)); } else if (!ObOptimizerUtil::find_item(select_exprs, aggr_param, &new_aggr_param_index)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to find new aggr param", K(ret)); } else if (OB_FAIL(child_stmt->get_select_exprs(new_select_exprs))) { LOG_WARN("failed to get select exprs", K(ret)); } else if (new_aggr_param_index < 0 || new_aggr_param_index >= new_select_exprs.count() || OB_ISNULL(new_aggr_param = new_select_exprs.at(new_aggr_param_index))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to find new aggr param", K(ret)); } else { child_stmt->get_select_items().reset(); } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, new_aggr_param, child_stmt))) { LOG_WARN("failed to create select item", K(ret)); } else if (OB_FAIL(set_child_condition(child_stmt, new_aggr_param))) { LOG_WARN("failed to set child condition", K(ret)); } else if (OB_FAIL(set_child_order_item(child_stmt, new_aggr_param, aggr_type))) { LOG_WARN("failed to set child order item", K(ret)); } else if (OB_FAIL(ObTransformUtils::set_limit_expr(child_stmt, ctx_))) { LOG_WARN("failed to set child limit item", K(ret)); } else if (OB_FAIL(child_stmt->rebuild_tables_hash())) { LOG_WARN("failed to rebuild table hash", K(ret)); } else if (OB_FAIL(child_stmt->update_column_item_rel_id())) { LOG_WARN("failed to update column item by id", K(ret)); } else if (OB_FAIL(child_stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize stmt", K(ret)); } return ret; } int ObTransformMinMax::is_valid_aggr_items(ObTransformerCtx &ctx, const ObSelectStmt &stmt, bool &is_valid) { int ret = OB_SUCCESS; const ObAggFunRawExpr *expr = NULL; bool valid = true; EqualSets &equal_sets = ctx.equal_sets_; ObSEArray const_exprs; ObSEArray valid_col_exprs; ObArenaAllocator alloc(ObMemAttr(MTL_ID(), "RewriteMinMax")); if (OB_FAIL(stmt.get_stmt_equal_sets(equal_sets, alloc, true))) { LOG_WARN("failed to get stmt equal sets", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(stmt.get_condition_exprs(), const_exprs))) { LOG_WARN("failed to compute const equivalent exprs", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && valid && i < stmt.get_aggr_item_size(); ++i) { if (OB_ISNULL(expr = stmt.get_aggr_item(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have null", K(ret), KP(expr)); } else if ((T_FUN_MAX != expr->get_expr_type() && T_FUN_MIN != expr->get_expr_type()) || expr->get_real_param_count() != 1) { OPT_TRACE("aggr expr is not min/max expr"); valid = false; } else if (OB_ISNULL(expr->get_param_expr(0))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null expr", K(ret)); } else if (is_contain(valid_col_exprs, expr->get_param_expr(0))) { valid = true; } else if (OB_FAIL(is_valid_index_column(ctx, &stmt, expr->get_param_expr(0), &equal_sets, &const_exprs, valid))) { LOG_WARN("failed to check is valid index column", K(ret)); } else if (!valid) { OPT_TRACE("aggr expr is not include index column"); } else if (OB_FAIL(valid_col_exprs.push_back(expr->get_param_expr(0)))) { LOG_WARN("failed to push back valid column", K(ret)); } } equal_sets.reuse(); is_valid = valid; return ret; } int ObTransformMinMax::is_valid_select_list(const ObSelectStmt &stmt, bool &is_valid) { int ret = OB_SUCCESS; bool valid = true; for (int64_t i = 0; OB_SUCC(ret) && valid && i < stmt.get_select_item_size(); ++i) { if (OB_FAIL(is_valid_select_expr(stmt.get_select_item(i).expr_, valid))) { LOG_WARN("failed to check expr is valid aggr", K(ret)); } } is_valid = valid; return ret; } int ObTransformMinMax::is_valid_select_expr(const ObRawExpr *expr, bool &is_valid) { int ret = OB_SUCCESS; bool is_stack_overflow = false; bool valid = true; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr should not be NULL", K(ret), KP(expr)); } else if (expr->has_flag(IS_AGG) || expr->is_const_expr()) { /* do nothing */ } else if (expr->has_flag(CNT_AGG)) { for (int64_t i = 0; OB_SUCC(ret) && valid && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(is_valid_select_expr(expr->get_param_expr(i), valid)))) { LOG_WARN("failed to check is_valid_expr", K(ret)); } } } else { valid = false; } is_valid = valid; return ret; } int ObTransformMinMax::is_valid_having_list(const ObSelectStmt &stmt, bool &is_valid) { int ret = OB_SUCCESS; bool valid = true; for (int64_t i = 0; OB_SUCC(ret) && valid && i < stmt.get_having_expr_size(); ++i) { if (OB_FAIL(is_valid_having_expr(stmt.get_having_exprs().at(i), valid))) { LOG_WARN("failed to check having expr", K(ret), K(i)); } } is_valid = valid; return ret; } int ObTransformMinMax::is_valid_having_expr(const ObRawExpr *expr, bool &is_valid) { int ret = OB_SUCCESS; bool valid = true; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("current expr is null", K(ret)); } else if (expr->has_flag(IS_AGG)) { /* do nothing*/ } else if (expr->is_column_ref_expr() || expr->has_flag(CNT_SUB_QUERY)) { valid = false; } else if (expr->has_flag(CNT_COLUMN)) { for (int64_t i = 0; OB_SUCC(ret) && valid && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(is_valid_having_expr(expr->get_param_expr(i), valid)))) { LOG_WARN("failed to check having expr", K(ret)); } } } is_valid = valid; return ret; } int ObTransformMinMax::is_valid_order_list(const ObSelectStmt &stmt, bool &is_valid) { int ret = OB_SUCCESS; bool valid = true; for (int64_t i = 0; OB_SUCC(ret) && valid && i < stmt.get_order_item_size(); ++i) { if (OB_FAIL(is_valid_order_expr(stmt.get_order_item(i).expr_, valid))) { LOG_WARN("failed to check having expr", K(ret), K(i)); } } is_valid = valid; return ret; } int ObTransformMinMax::is_valid_order_expr(const ObRawExpr *expr, bool &is_valid) { int ret = OB_SUCCESS; bool valid = true; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("current expr is null", K(ret)); } else if (expr->has_flag(IS_AGG)) { /* do nothing*/ } else if (expr->is_column_ref_expr()) { valid = false; } else if (expr->has_flag(CNT_COLUMN)) { for (int64_t i = 0; OB_SUCC(ret) && valid && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(is_valid_order_expr(expr->get_param_expr(i), valid)))) { LOG_WARN("failed to check order expr", K(ret)); } } } is_valid = valid; return ret; } int ObTransformMinMax::is_valid_index_column(ObTransformerCtx &ctx, const ObSelectStmt *stmt, const ObRawExpr *expr, EqualSets *equal_sets, ObIArray *const_exprs, bool &is_valid) { int ret = OB_SUCCESS; const TableItem *table_item = NULL; const ObColumnRefRawExpr *col_expr = NULL; bool is_match_index = false; bool need_check_query_range = false; is_valid = false; if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid argument", K(ret), K(stmt), K(expr)); } else if (!expr->is_column_ref_expr()) { /* do nothing */ } else if (OB_FALSE_IT(col_expr = static_cast(expr))) { } else if (OB_ISNULL(table_item = stmt->get_table_item_by_id(col_expr->get_table_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); } else if (!table_item->is_basic_table()) { /* do nothing */ } else { if (stmt->get_aggr_item_size() > 1 && stmt->get_condition_size() > 0) { need_check_query_range = true; } if (OB_FAIL(ObTransformUtils::is_match_index(ctx.sql_schema_guard_, stmt, col_expr, is_match_index, equal_sets, const_exprs, NULL, false, need_check_query_range, &ctx))) { LOG_WARN("failed to check whether column matches index", K(ret)); } else if (is_match_index) { is_valid = true; } } return ret; } int ObTransformMinMax::set_child_order_item(ObSelectStmt *stmt, ObRawExpr *aggr_param, ObItemType aggr_type) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt) || OB_ISNULL(aggr_param)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("params have null", K(ret), K(stmt), K(aggr_param)); } else { OrderItem new_order_item; new_order_item.expr_ = aggr_param; if (T_FUN_MAX == aggr_type) { new_order_item.order_type_ = default_desc_direction(); } else if (T_FUN_MIN == aggr_type) { new_order_item.order_type_ = default_asc_direction(); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("aggregate function type must by max or min", K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(stmt->add_order_item(new_order_item))) { LOG_WARN("failed to add order item", K(ret), K(stmt), K(new_order_item)); } } } return ret; } int ObTransformMinMax::set_child_condition(ObSelectStmt *stmt, ObRawExpr *aggr_param) { int ret = OB_SUCCESS; ObRawExpr *not_null_expr = NULL; bool is_not_null = false; ObArray constraints; if (OB_ISNULL(stmt) || OB_ISNULL(aggr_param) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have null", K(ret), K(stmt), K(aggr_param)); } else if (OB_FAIL(ObTransformUtils::is_expr_not_null(ctx_, stmt, aggr_param, NULLABLE_SCOPE::NS_WHERE, is_not_null, &constraints))) { LOG_WARN("failed to check expr not null", K(ret)); } else if (is_not_null) { if (OB_FAIL(ObTransformUtils::add_param_not_null_constraint(*ctx_, constraints))) { LOG_WARN("failed to add param not null constraints", K(ret)); } } else if (OB_FAIL(ObTransformUtils::add_is_not_null(ctx_, aggr_param, not_null_expr))) { LOG_WARN("failed to add is not null", K(ret)); } else if (OB_FAIL(stmt->add_condition_expr(not_null_expr))) { LOG_WARN("failed to add condition expr", K(ret)); } return ret; } } // sql } // oceanbase