/** * 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_RESV #include "sql/resolver/expr/ob_raw_expr_precalc_analyzer.h" #include "sql/resolver/expr/ob_raw_expr.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/resolver/dml/ob_dml_stmt.h" #include "sql/resolver/dml/ob_select_stmt.h" #include "sql/session/ob_sql_session_info.h" #include "sql/ob_sql_context.h" #include "common/ob_smart_call.h" namespace oceanbase { using namespace common; namespace sql { const ObItemType ObRawExprPrecalcAnalyzer::EXPR_FILTER_LIST[] = {T_OP_IN, T_OP_NOT_IN, T_OP_ARG_CASE, T_FUN_SYS_NULLIF}; int ObRawExprPrecalcAnalyzer::analyze_all_expr(ObDMLStmt& stmt) { int ret = OB_SUCCESS; ObArray relation_exprs; ObArray child_stmts; if (OB_ISNULL(my_session_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null session", K(ret)); } else if (OB_FAIL(stmt.get_relation_exprs(relation_exprs))) { LOG_WARN("get relation exprs failed", K(ret)); } else if (OB_FAIL(stmt.get_child_stmts(child_stmts))) { LOG_WARN("get child stmt failed", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < relation_exprs.count(); ++i) { if (OB_FAIL(analyze_expr_tree(relation_exprs.at(i), stmt, my_session_->use_static_typing_engine()))) { LOG_WARN("pre cast expr recursively failed", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) { ObDMLStmt* child_stmt = child_stmts.at(i); if (OB_ISNULL(child_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child stmt is null"); } else if (OB_FAIL(SMART_CALL(analyze_all_expr(*child_stmt)))) { LOG_WARN("analyze child stmt all expr failed", K(ret)); } } return ret; } int ObRawExprPrecalcAnalyzer::pre_cast_const_expr(ObRawExpr* expr) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr is null"); } else if (!expr->has_generalized_column() || !(expr->has_flag(CNT_CONST) || expr->has_flag(CNT_CALCULABLE_EXPR)) || !can_be_pre_cast(expr->get_expr_type())) { // do nothing } else if (expr->is_op_expr() || expr->is_sys_func_expr() || expr->is_udf_expr()) { ObOpRawExpr* op_expr = static_cast(expr); if (op_expr->get_input_types().count() == op_expr->get_param_count()) { for (int64_t i = 0; OB_SUCC(ret) && i < op_expr->get_param_count(); ++i) { ObRawExpr* param_expr = op_expr->get_param_expr(i); if (OB_ISNULL(param_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param expr is null"); } else if (param_expr->has_flag(IS_CONST) || param_expr->has_flag(IS_CALCULABLE_EXPR)) { ObObjType calc_type = op_expr->get_input_types().at(i).get_calc_type(); if (calculation_need_cast(param_expr->get_data_type(), calc_type)) { ObSysFunRawExpr* func_expr = NULL; if (OB_FAIL(ObRawExprUtils::create_to_type_expr( expr_factory_, param_expr, calc_type, func_expr, my_session_))) { LOG_WARN("create cast expr failed", K(ret)); } else if (OB_FAIL(op_expr->replace_param_expr(i, func_expr))) { LOG_WARN("replace param expr failed", K(ret)); } } } } } } return ret; } int ObRawExprPrecalcAnalyzer::pre_cast_recursively(ObRawExpr* expr) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr is null"); } else if (!expr->has_generalized_column() || !(expr->has_flag(CNT_CONST) || expr->has_flag(CNT_CALCULABLE_EXPR))) { // do nothing } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(pre_cast_recursively(expr->get_param_expr(i))))) { LOG_WARN("pre cast recursively failed", K(ret)); } } if (OB_SUCC(ret) && OB_FAIL(pre_cast_const_expr(expr))) { LOG_WARN("pre cast const expr failed", K(ret)); } } return ret; } int ObRawExprPrecalcAnalyzer::extract_calculable_expr(ObRawExpr*& expr, ObDMLStmt& stmt, const bool filter_expr) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || OB_ISNULL(stmt.get_query_ctx())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(expr), K(stmt.get_query_ctx())); } else if (expr->has_flag(IS_CALCULABLE_EXPR)) { if (filter_expr && is_filtered(*expr)) { // do nothing } else { ObHiddenColumnItem hidden_col; hidden_col.hidden_idx_ = stmt.get_pre_param_size(); hidden_col.expr_ = expr; if (expr->has_flag(CNT_CUR_TIME)) { stmt.get_query_ctx()->fetch_cur_time_ = true; } ObRawExpr* orig_expr = expr; if (OB_FAIL(stmt.add_calculable_item(hidden_col))) { LOG_WARN("add calculable item to stmt failed", K(ret)); } else if (OB_FAIL(ObRawExprUtils::create_param_expr(expr_factory_, hidden_col.hidden_idx_, expr))) { LOG_WARN("create param expr failed", K(ret)); } else if (expr != orig_expr) { expr->set_orig_expr(orig_expr); } } } return ret; } int ObRawExprPrecalcAnalyzer::extract_calculable_expr_recursively( ObRawExpr*& expr, ObDMLStmt& stmt, const bool filter_expr) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr is null"); } else if (expr->has_flag(IS_CALCULABLE_EXPR)) { if (OB_FAIL(extract_calculable_expr(expr, stmt, filter_expr))) { LOG_WARN("extract calculabe expr failed", K(ret)); } } else if (expr->has_flag(CNT_CALCULABLE_EXPR)) { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(extract_calculable_expr_recursively(expr->get_param_expr(i), stmt)))) { LOG_WARN("extract calculabe expr recursively failed", K(ret)); } } } return ret; } int ObRawExprPrecalcAnalyzer::analyze_expr_tree(ObRawExpr* expr, ObDMLStmt& stmt, const bool filter_expr /* false */) { int ret = OB_SUCCESS; ObRawExpr* old_expr = expr; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr is null"); } else if (OB_FAIL(pre_cast_recursively(expr))) { LOG_WARN("pre cast expr recursively failed", K(ret)); } else if (OB_FAIL(expr->extract_info())) { LOG_WARN("extract expr info failed", K(ret)); } else if (OB_FAIL(extract_calculable_expr_recursively(expr, stmt, filter_expr))) { LOG_WARN("extract calculabe expr recursively failed", K(ret)); } else if (OB_FAIL(expr->extract_info())) { LOG_WARN("extract expr info failed", K(ret)); } else if (old_expr != expr) { if (OB_FAIL(stmt.replace_expr_in_stmt(old_expr, expr))) { LOG_WARN("replace expr in stmt failed", K(ret)); } } return ret; } bool ObRawExprPrecalcAnalyzer::can_be_pre_cast(ObItemType expr_type) const { bool bret = true; if (T_FUN_SYS_TO_TYPE == expr_type || T_OP_ARG_CASE == expr_type || T_OP_CASE == expr_type || T_FUN_SYS_SET_COLLATION == expr_type || T_FUN_COLUMN_CONV == expr_type || T_FUN_SYS_DEFAULT == expr_type || T_FUN_SYS_AUTOINC_NEXTVAL == expr_type) { bret = false; } return bret; } bool ObRawExprPrecalcAnalyzer::calculation_need_cast(ObObjType param_type, ObObjType calc_type) const { bool bret = false; if (ObNullType == param_type || ObNullType == calc_type) { bret = false; } else if (ObMaxType == param_type || ObMaxType == calc_type) { bret = false; } else if (param_type != calc_type) { // TODO:char vs varchar? bret = true; } return bret; } bool ObRawExprPrecalcAnalyzer::is_filtered(ObRawExpr& expr) { bool is_filtered = false; for (int i = 0; !is_filtered && i < ARRAYSIZEOF(EXPR_FILTER_LIST); i++) { if (expr.get_expr_type() == EXPR_FILTER_LIST[i]) { is_filtered = true; } } return is_filtered; } } // namespace sql } // namespace oceanbase