/** * 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 PL #include "lib/worker.h" #include "pl/ob_pl_resolver.h" #include "pl/ob_pl_stmt.h" #include "pl/ob_pl_router.h" #include "common/sql_mode/ob_sql_mode_utils.h" #include "pl/ob_pl_package.h" #include "pl/parser/parse_stmt_item_type.h" #include "pl/ob_pl_exception_handling.h" #include "pl/ob_pl_interface_pragma.h" #include "sql/parser/ob_parser.h" #include "sql/parser/parse_malloc.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/resolver/expr/ob_raw_expr_printer.h" #include "sql/resolver/ob_resolver_utils.h" #include "sql/resolver/ddl/ob_ddl_resolver.h" #include "sql/resolver/expr/ob_raw_expr_resolver_impl.h" #include "sql/resolver/dml/ob_select_resolver.h" #include "sql/resolver/expr/ob_raw_expr_wrap_enum_set.h" #include "observer/ob_server_struct.h" #include "sql/rewrite/ob_transform_pre_process.h" #include "share/schema/ob_trigger_info.h" #include "sql/resolver/expr/ob_raw_expr_copier.h" #ifdef OB_BUILD_ORACLE_PL #include "pl/ob_pl_warning.h" #include "pl/ob_pl_udt_object_manager.h" #include "pl/sys_package/ob_json_pl_utils.h" #include "pl/dblink/ob_pl_dblink_util.h" #endif namespace oceanbase { using namespace common; using namespace share; using namespace sql; using namespace share::schema; namespace pl { const char *ObPLResolver::ANONYMOUS_BLOCK = "__anonymous_block__"; const char *ObPLResolver::ANONYMOUS_ARG = "__anonymous_argument__"; const char *ObPLResolver::ANONYMOUS_SQL_ARG = "__anonymous_argument__for_static_sql__"; const char *ObPLResolver::ANONYMOUS_INOUT_ARG = "__anonymous_argument__for_inout__"; int ObPLResolver::init(ObPLFunctionAST &func_ast) { int ret = OB_SUCCESS; if (OB_FAIL(make_block(func_ast, NULL, current_block_, true))) { LOG_WARN("failed to make block", K(current_block_), K(ret)); } else { current_level_ = 0; func_ast.set_body(current_block_); arg_cnt_ = func_ast.get_arg_count(); question_mark_cnt_ = 0; external_ns_.set_dependency_table(&func_ast.get_dependency_table()); if (!OB_ISNULL(external_ns_.get_parent_ns())) { uint64_t type_start_gen_id = external_ns_.get_parent_ns()->get_type_table()->get_type_start_gen_id(); func_ast.get_user_type_table().set_type_start_gen_id(type_start_gen_id); } if (OB_SUCC(ret) && lib::is_oracle_mode() && !func_ast.is_udt_cons()) { OZ (current_block_->get_namespace().add_label( func_ast.get_name(), ObPLLabelTable::ObPLLabelType::LABEL_BLOCK, NULL)); } if (OB_SUCC(ret)) { if (!resolve_ctx_.package_guard_.is_inited()) { if (OB_FAIL(resolve_ctx_.package_guard_.init())) { LOG_WARN("package guard init failed", K(ret)); } } } for (int64_t i = 0; OB_SUCC(ret) && i < func_ast.get_arg_count(); ++i) { if (OB_FAIL(current_block_->get_namespace().get_symbols().push_back(i))) { LOG_WARN("failed to add variable to symbol table", K(i),K(ret)); } else { common::ObString name; ObPLDataType type; OZ (func_ast.get_argument(i, name, type)); if (OB_SUCC(ret) && type.is_cursor_type()) { OZ (current_block_->get_namespace().get_cursors().push_back( current_block_->get_namespace().get_cursors().count())); } if (OB_SUCC(ret) && type.is_composite_type()) { // 将参数中的复杂类型在本ns中展开, 避免参数类型在符号表中不全 if (type.is_local_type() && STANDALONE_ANONYMOUS == func_ast.get_proc_type()) { OZ (current_block_->get_namespace().get_types().push_back( current_block_->get_namespace().get_types().count())); } else { const ObUserDefinedType *user_type = NULL; OZ (current_block_->get_namespace().get_pl_data_type_by_id(type.get_user_type_id(), user_type), type, i); CK (OB_NOT_NULL(user_type)); OZ (user_type->get_all_depended_user_type(resolve_ctx_, current_block_->get_namespace()), user_type); } } } } if (func_ast.is_function()) { const ObPLDataType &type = func_ast.get_ret_type(); if (type.is_composite_type()) { const ObUserDefinedType *user_type = NULL; OZ (current_block_->get_namespace().get_pl_data_type_by_id(type.get_user_type_id(), user_type), type); CK (OB_NOT_NULL(user_type)); OZ (user_type->get_all_depended_user_type(resolve_ctx_, current_block_->get_namespace()), user_type); } } } return ret; } int ObPLResolver::init_default_exprs( ObPLFunctionAST &func, const ObIArray ¶ms) { int ret = OB_SUCCESS; for (int64_t i = 0, idx = 0; OB_SUCC(ret) && i < params.count(); ++i) { if (params.at(i)->is_ret_param()) { // do nothing ... } else { OZ (init_default_expr(func, idx, *(params.at(i)))); OX (idx++); } } return ret; } int ObPLResolver::init_default_exprs( ObPLFunctionAST &func, const ObIArray ¶ms) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) { CK (OB_NOT_NULL(params.at(i))); OZ (init_default_expr(func, i, *(params.at(i)))); } return ret; } int ObPLResolver::init_default_expr( ObPLFunctionAST &func_ast, int64_t idx, const share::schema::ObIRoutineParam ¶m) { int ret = OB_SUCCESS; if (!param.get_default_value().empty()) { ObPLSymbolTable &symbol_table = func_ast.get_symbol_table(); const ObPLVar *var = symbol_table.get_symbol(idx); CK (OB_NOT_NULL(var)); OZ (init_default_expr(func_ast, param, var->get_type())); OX ((const_cast(var))->set_default(func_ast.get_expr_count() - 1)); } return ret; } int ObPLResolver::init_default_expr(ObPLFunctionAST &func_ast, const share::schema::ObIRoutineParam ¶m, const ObPLDataType &expected_type) { int ret = OB_SUCCESS; if (!param.get_default_value().empty()) { const ParseNode *default_node = NULL; ObRawExpr *default_expr = NULL; ObString default_value = param.get_default_value(); OZ (ObSQLUtils::convert_sql_text_from_schema_for_resolve( resolve_ctx_.allocator_, resolve_ctx_.session_info_.get_dtc_params(), default_value)); OZ (ObRawExprUtils::parse_default_expr_from_str( default_value, resolve_ctx_.session_info_.get_charsets4parser(), resolve_ctx_.allocator_, default_node)); CK (OB_NOT_NULL(default_node)); OZ (resolve_expr(default_node, func_ast, default_expr, combine_line_and_col(default_node->stmt_loc_), true, &expected_type)); CK (OB_NOT_NULL(default_expr)); } return ret; } #define RESOLVE_CHILDREN(node, compile_unit) \ do { \ if (OB_NOT_NULL(node)) { \ for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; ++i) { \ if (NULL != node->children_[i]) { \ OZ (SMART_CALL(resolve(node->children_[i], compile_unit))); \ } \ } \ } \ } while (0) #define RESOLVE_STMT(stmt_type, resolve_func, stmt_def) \ do { \ ObPLStmtType type = stmt_type; \ if (OB_FAIL(stmt_factory_.allocate(type, current_block_, stmt))) { \ LOG_WARN("failed to alloc stmt", K(ret)); \ } else if (OB_FAIL(resolve_func(parse_tree, static_cast(stmt), func))) { \ LOG_WARN("failed to resolve pl stmt", K(parse_tree->type_), K(parse_tree), K(stmt), K(ret)); \ } else if (type != PL_SQL) { \ func.set_is_all_sql_stmt(false); \ } \ } while (0) #define NO_EXCEPTION_STMT(type) ( PL_BLOCK == type \ || PL_USER_TYPE == type \ || PL_LEAVE == type \ || PL_ITERATE == type \ || PL_LOOP == type \ || PL_COND == type \ || PL_HANDLER == type \ || PL_CURSOR == type \ || PL_ROUTINE_DEF == type \ || PL_ROUTINE_DECL == type \ ) int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &func) { int ret = OB_SUCCESS; if (OB_ISNULL(parse_tree)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("parse_tree is NULL", K(parse_tree), K(ret)); } else { ObPLStmt *stmt = NULL; ObString label; ObSEArray labels; ObString end_label; ObPLLabelTable *pl_label = NULL; int64_t label_idx = OB_INVALID_INDEX; if (T_SP_LABELED_BLOCK == parse_tree->type_ || T_SP_LABELED_CONTROL == parse_tree->type_) { // Oracle可以只有EndLabel,没有BeginLabel, 且EndLabel可以与BeginLabel不匹配 // 如下用例在Oracle下是合法的 // example 1: <