diff --git a/src/pl/ob_pl.h b/src/pl/ob_pl.h index a716c8b8b..0ed2e327c 100644 --- a/src/pl/ob_pl.h +++ b/src/pl/ob_pl.h @@ -61,20 +61,6 @@ typedef common::ParamStore ParamStore; class ObPLCacheCtx; -enum ObProcType -{ - INVALID_PROC_TYPE = 0, - STANDALONE_PROCEDURE = 1, - STANDALONE_FUNCTION = 2, - PACKAGE_PROCEDURE = 3, /* A subprogram created inside a package is a packaged subprogram */ - PACKAGE_FUNCTION = 4, - NESTED_PROCEDURE = 5, /* A subprogram created inside a PL/SQL block is a nested subprogram */ - NESTED_FUNCTION = 6, - STANDALONE_ANONYMOUS = 7, - UDT_PROCEDURE = 8, - UDT_FUNCTION = 9, -}; - enum ObPLObjectType { INVALID_OBJECT_TYPE = -1, diff --git a/src/pl/ob_pl_code_generator.cpp b/src/pl/ob_pl_code_generator.cpp index 36b0105ad..b40de62ab 100644 --- a/src/pl/ob_pl_code_generator.cpp +++ b/src/pl/ob_pl_code_generator.cpp @@ -2631,7 +2631,7 @@ int ObPLCodeGenerateVisitor::visit(const ObPLCallStmt &s) ObLLVMValue array_value; ObLLVMValue nocopy_array_value; uint64_t package_id = s.get_package_id(); - package_id = 1 == s.get_is_object_udf() + package_id = (1 == s.get_is_object_udf()) ? share::schema::ObUDTObjectType::mask_object_id(package_id) : package_id; if (OB_FAIL(args.push_back(generator_.get_vars().at(generator_.CTX_IDX)))) { //PL的执行环境 LOG_WARN("push_back error", K(ret)); diff --git a/src/pl/ob_pl_resolver.cpp b/src/pl/ob_pl_resolver.cpp index 405076d1d..f6b9fd842 100644 --- a/src/pl/ob_pl_resolver.cpp +++ b/src/pl/ob_pl_resolver.cpp @@ -381,7 +381,10 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun RESOLVE_STMT(PL_RETURN, resolve_return, ObPLReturnStmt); // OB_ERR_FUNCTION_UNKNOWN need set too. // case: CREATE FUNCTION f1() RETURNS INT RETURN f1() - if (lib::is_mysql_mode() && (OB_SUCCESS == ret || OB_ERR_FUNCTION_UNKNOWN == ret)) { + if (lib::is_mysql_mode() + && (OB_SUCCESS == ret + || OB_ERR_FUNCTION_UNKNOWN == ret + || OB_ERR_SP_DOES_NOT_EXIST == ret)) { func.set_return(); } } @@ -5835,7 +5838,7 @@ int ObPLResolver::resolve_cparam_without_assign(ObRawExpr* expr, CK (OB_NOT_NULL(call_expr->get_expr())); CK (has_exist_in_array(func.get_exprs(), call_expr->get_expr(), &expr_idx)); } else { - CK (has_exist_in_array(func.get_exprs(), expr, &expr_idx)); + OV (has_exist_in_array(func.get_exprs(), expr, &expr_idx), OB_ERR_UNEXPECTED, KPC(expr)); } } CK (OB_LIKELY(expr_idx != OB_INVALID_INDEX)); @@ -5961,7 +5964,7 @@ int ObPLResolver::resolve_cparams(ObIArray &exprs, LOG_WARN("routine param does not has default value", K(ret), K(exprs.count()), K(params_list.count())); } - // Step 2: initilize params arraya, put all null. + // Step 2: initilize params array, put all null. for (int64_t i = 0; OB_SUCC(ret) && i < params_list.count(); ++i) { OZ (params.push_back(NULL)); OZ (expr_idx.push_back(OB_INVALID_INDEX)); @@ -8006,17 +8009,7 @@ int ObPLResolver::build_raw_expr(const ParseNode *node, } else { OZ (resolve_columns(expr, columns, unit_ast)); } - for (uint64_t i = 0; OB_SUCC(ret) && i < udf_info.count(); ++i) { - ObUDFInfo &udf = udf_info.at(i); - ObUDFRawExpr *udf_raw_expr = NULL; - ObSchemaObjVersion obj_version; - OZ (ObRawExprUtils::init_udf_info(resolve_ctx_, expr_factory_, udf)); - CK (OB_NOT_NULL(udf_raw_expr = udf.ref_expr_)); - if (OB_SUCC(ret) && udf_raw_expr->need_add_dependency()) { - OZ (udf_raw_expr->get_schema_object_version(obj_version)); - OZ (unit_ast.add_dependency_object(obj_version)); - } - } + OV (udf_info.count() <= 0, OB_ERR_UNEXPECTED, K(udf_info)); if (OB_SUCC(ret) && op_exprs.count() > 0) { if (OB_FAIL(ObRawExprUtils::resolve_op_exprs_for_oracle_implicit_cast(expr_factory_, &resolve_ctx_.session_info_, op_exprs))) { @@ -8671,7 +8664,7 @@ int ObPLResolver::resolve_columns(ObRawExpr *&expr, ObArray &co ObQualifiedName &q_name = columns.at(i); ObRawExpr *ref_expr = NULL; OZ (resolve_qualified_identifier(q_name, columns, real_exprs, unit_ast, ref_expr), - q_name, columns, real_exprs, unit_ast, ref_expr); + K(q_name), K(columns), K(real_exprs), K(unit_ast), K(ref_expr)); CK (OB_NOT_NULL(ref_expr)); OZ (real_exprs.push_back(ref_expr), ref_expr); OZ (ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, ref_expr)); @@ -8839,6 +8832,30 @@ int ObPLResolver::resolve_raw_expr(const ParseNode &node, return ret; } +int ObPLResolver::init_udf_info_of_accessidents(ObIArray &access_idents) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < access_idents.count(); ++i) { + ObObjAccessIdent &access_ident = access_idents.at(i); + ObUDFRawExpr *func_expr = NULL; + OX (new (&access_ident.udf_info_) ObUDFInfo()); + OZ (expr_factory_.create_raw_expr(T_FUN_UDF, func_expr)); + CK (OB_NOT_NULL(func_expr)); + for (int64_t i = 0; OB_SUCC(ret) && i < access_ident.params_.count(); ++i) { + std::pair ¶m = access_ident.params_.at(i); + if (0 == param.second) { + OZ (func_expr->add_param_expr(param.first)); + OX (access_ident.udf_info_.udf_param_num_++); + } else { + break; + } + } + OX (func_expr->set_func_name(access_ident.access_name_)); + OX (access_ident.udf_info_.ref_expr_ = func_expr); + } + return ret; +} + int ObPLResolver::resolve_inner_call( const ParseNode *parse_tree, ObPLStmt *&stmt, ObPLFunctionAST &func) { @@ -8850,16 +8867,46 @@ int ObPLResolver::resolve_inner_call( ObArray obj_access_idents; ObArray access_idxs; ObArray self_access_idxs; + ObArray expr_params; OZ (resolve_obj_access_idents(*parse_tree->children_[0], obj_access_idents, func)); + OZ (init_udf_info_of_accessidents(obj_access_idents)); for (int64_t i = 0; OB_SUCC(ret) && i < obj_access_idents.count(); ++i) { + bool is_routine = obj_access_idents.at(i).is_pl_udf(); + if (i == obj_access_idents.count() - 1) { + if (access_idxs.count() > 0) { + if (access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_DB_NS + || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_PKG_NS + || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_LABEL_NS + || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_UDT_NS) { + is_routine = true; + } + } else { + is_routine = true; + } + } else { + obj_access_idents.at(i).set_pl_udf(); + } + int64_t idx_cnt = access_idxs.count(); OZ (resolve_access_ident(obj_access_idents.at(i), current_block_->get_namespace(), expr_factory_, &resolve_ctx_.session_info_, access_idxs, func, - (i == (obj_access_idents.count() - 1)) ? true : false), + is_routine), K(access_idxs), K(i)); + OZ (obj_access_idents.at(i).extract_params(0, expr_params)); + OX (idx_cnt = (idx_cnt >= access_idxs.count()) ? 0 : idx_cnt); + if (OB_SUCC(ret) + && expr_params.count() > 0 + && !access_idxs.at(idx_cnt).is_procedure() + && !access_idxs.at(idx_cnt).is_system_procedure() + && !access_idxs.at(idx_cnt).is_type_method() + && !access_idxs.at(idx_cnt).var_type_.is_composite_type()) { + ret = OB_ERR_OUT_OF_SCOPE; + LOG_WARN("PLS-00225: subprogram or cursor reference is out of scope", K(ret), K(access_idxs.at(access_idxs.count()-1))); + LOG_USER_ERROR(OB_ERR_OUT_OF_SCOPE, obj_access_idents.at(i).access_name_.length(), obj_access_idents.at(i).access_name_.ptr()); + } if (OB_SUCC(ret) && obj_access_idents.count() >= 2 && i == (obj_access_idents.count() - 2)) { @@ -8867,7 +8914,6 @@ int ObPLResolver::resolve_inner_call( } } -#if 1 #define MOCK_SELF_PARAM(need_rotate) \ do { \ uint64_t acc_cnt = obj_access_idents.count(); \ @@ -8886,16 +8932,20 @@ do { \ ret = OB_SUCCESS; \ } \ if (need_mock) { \ - OZ (make_var_from_access(self_access_idxs, \ - expr_factory_, \ - &resolve_ctx_.session_info_, \ - &resolve_ctx_.schema_guard_, \ - current_block_->get_namespace(), \ - self_arg), K(obj_access_idents), K(self_access_idxs)); \ - OZ (func.add_obj_access_expr(self_arg)); \ + if (self_access_idxs.at(self_access_idxs.count() - 1).is_udf_type()) { \ + OX (self_arg = self_access_idxs.at(self_access_idxs.count() - 1).get_sysfunc_); \ + CK (OB_NOT_NULL(self_arg)); \ + } else { \ + OZ (make_var_from_access(self_access_idxs, \ + expr_factory_, \ + &resolve_ctx_.session_info_, \ + &resolve_ctx_.schema_guard_, \ + current_block_->get_namespace(), \ + self_arg), K(obj_access_idents), K(self_access_idxs)); \ + OZ (func.add_obj_access_expr(self_arg)); \ + } \ OZ (func.add_expr(self_arg)); \ - OZ (obj_access_idents.at(acc_cnt - 1).params_.push_back( \ - std::make_pair(self_arg, 0))); \ + OZ (obj_access_idents.at(acc_cnt - 1).params_.push_back(std::make_pair(self_arg, 0))); \ if (OB_SUCC(ret) && need_rotate) { \ std::rotate(obj_access_idents.at(acc_cnt - 1).params_.begin(), \ obj_access_idents.at(acc_cnt - 1).params_.begin() \ @@ -8904,55 +8954,6 @@ do { \ } \ } \ } while(0) -#else -#define MOCK_SELF_PARAM(need_rotate) \ -do { \ - /* two case, implict self param is at end, explicit self param is at 0 */ \ - if (OB_SUCC(ret)) { \ - ObRawExpr *self_arg = NULL; \ - ObArray access_name; \ - uint64_t acc_cnt = obj_access_idents.count(); \ - for (int64_t i = 0; OB_SUCC(ret) && i < acc_cnt - 1; ++i) { \ - OZ (access_name.push_back(obj_access_idents.at(i).access_name_)); \ - } \ - /* 构造一个self实参,这个实参是名字就是这个调用这个procedure的前一个字段,如obj.procedure */ \ - /* 就是obj,被构造成为一个T_OBJ_ACCESS_REF,它的ident就是obj */ \ - /* obj_type.procedure is also possible, do not mock self param while in this case*/ \ - const ObUserDefinedType *user_type = NULL; \ - bool need_mock = true; \ - if (OB_SUCC(ret) && acc_cnt > 1) { \ - OZ (current_block_->get_namespace().get_pl_data_type_by_name(resolve_ctx_, \ - acc_cnt > 2 ? obj_access_idents.at(acc_cnt - 3).access_name_ : ObString(""), \ - ObString(""), \ - obj_access_idents.at(acc_cnt - 2).access_name_, \ - user_type), ret, obj_access_idents); \ - if (OB_SUCC(ret) && OB_NOT_NULL(user_type)) { \ - need_mock = false; \ - } \ - /* reset err code intentionally, we just want to test need_mock, it may failed because */ \ - /* it may not obj_type.procedure */ \ - ret = OB_SUCCESS; \ - } \ - if (OB_SUCC(ret) && need_mock) { \ - if (OB_FAIL(make_udt_udf_self_expr(access_name, func, self_arg))) { \ - LOG_WARN("failed to contruct udt udf self node", K(ret), K(access_name)); \ - } else { \ - std::pair param_pair(self_arg, 0); \ - if (OB_FAIL(obj_access_idents.at(acc_cnt-1).params_.push_back(param_pair))) { \ - LOG_WARN("failed to push self param", K(ret)); \ - } \ - if (need_rotate) { \ - /* self param is the first param, if not, rotate to the first pos */ \ - std::rotate(obj_access_idents.at(acc_cnt-1).params_.begin(), \ - obj_access_idents.at(acc_cnt-1).params_.begin() \ - + obj_access_idents.at(acc_cnt-1).params_.count() - 1, \ - obj_access_idents.at(acc_cnt-1).params_.end()); \ - } \ - } \ - } \ - } \ -} while(0) -#endif if (OB_SUCC(ret)) { int64_t idx_cnt = access_idxs.count(); @@ -9023,8 +9024,13 @@ do { \ } } if (OB_NOT_NULL(self_param)) { + const ObIRoutineInfo* routine_info = NULL; CK (0 == self_param_pos || self_param_pos == routine_params.count() - 1); - if (obj_access_idents.at(idents_cnt - 1).udf_info_.is_udf_udt_member()) { + CK (OB_NOT_NULL(routine_info = access_idxs.at(idx_cnt - 1).routine_info_)); + + if (OB_FAIL(ret)) { + } else if (routine_info->is_udt_routine() + && !(routine_info->is_udt_static_routine() || routine_info->is_udt_cons())) { if (idx_cnt > 1 && idents_cnt > 1) { MOCK_SELF_PARAM(0 == self_param_pos); } else { @@ -9060,6 +9066,7 @@ do { \ OZ (null_expr->add_flag(IS_UDT_UDF_SELF_PARAM)); OZ (obj_access_idents.at(idents_cnt - 1) .params_.push_back(std::make_pair(null_expr, 0))); + OZ (func.add_expr(null_expr)); if (OB_SUCC(ret) && 0 == self_param_pos) { std::rotate(obj_access_idents.at(idents_cnt-1).params_.begin(), obj_access_idents.at(idents_cnt-1).params_.begin() @@ -9083,10 +9090,11 @@ do { \ } else if (access_idxs.at(idx_cnt - 1).is_external_procedure()) { ObArray params; const share::schema::ObRoutineInfo *schema_routine_info - = static_cast(access_idxs.at(idx_cnt-1).routine_info_); + = static_cast(access_idxs.at(idx_cnt - 1).routine_info_); CK (OB_NOT_NULL(schema_routine_info)); - call_stmt->set_package_id(schema_routine_info->get_package_id()); - if (OB_INVALID_ID == schema_routine_info->get_package_id()) { + OX (call_stmt->set_package_id(schema_routine_info->get_package_id())); + if (OB_FAIL(ret)) { + } else if (OB_INVALID_ID == schema_routine_info->get_package_id()) { call_stmt->set_proc_id(schema_routine_info->get_routine_id()); } else { call_stmt->set_proc_id(schema_routine_info->get_subprogram_id()); @@ -9102,10 +9110,8 @@ do { \ call_stmt->set_is_object_udf(); } if (OB_SUCC(ret) && !schema_routine_info->is_udt_static_routine()) { - if (idents_cnt > 1 - && obj_access_idents.at(idents_cnt - 1).udf_info_.is_udf_udt_member() - && idx_cnt > 1) { - call_stmt->set_is_object_udf(); + if (idents_cnt > 1 && idx_cnt > 1) { + // call_stmt->set_is_object_udf(); const ObRoutineParam *self_param = NULL; int64_t self_param_pos = OB_INVALID_INDEX; for (int64_t i = 0; i < routine_params.count(); ++i) { @@ -9537,6 +9543,24 @@ int ObPLResolver::resolve_sqlcode_or_sqlerrm(ObQualifiedName &q_name, return ret; } +int ObPLResolver::resolve_construct(const ObQualifiedName &q_name, + const ObUDFInfo &udf_info, + const ObUserDefinedType &user_type, + ObRawExpr *&expr) +{ + int ret = OB_SUCCESS; + if (user_type.is_nested_table_type() || user_type.is_varray_type()) { + OZ (resolve_collection_construct(q_name, udf_info, &user_type, expr)); + } else if (user_type.is_object_type() && user_type.is_udt_type()) { + OZ (resolve_object_construct(q_name, udf_info, &user_type, expr)); + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("only allow collection construct and user define record construct", K(ret), K(user_type)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "Constructs other than collection constructs and user-defined record constructs"); + } + return ret; +} + int ObPLResolver::resolve_construct(const ObQualifiedName &q_name, const ObUDFInfo &udf_info, ObRawExpr *&expr) @@ -9573,22 +9597,20 @@ int ObPLResolver::resolve_construct(const ObQualifiedName &q_name, } int ObPLResolver::resolve_object_construct(const sql::ObQualifiedName &q_name, - const sql::ObUDFInfo &udf_info, - const ObUserDefinedType *user_type, - ObRawExpr *&expr) + const sql::ObUDFInfo &udf_info, + const ObUserDefinedType *user_type, + ObRawExpr *&expr) { int ret = OB_SUCCESS; const ObRecordType *object_type = NULL; - CK (OB_NOT_NULL(object_type = static_cast(user_type))); uint64_t type_id = OB_INVALID_ID; bool is_sys_type = false; + CK (OB_NOT_NULL(object_type = static_cast(user_type))); OX (type_id = object_type->get_user_type_id()); OX (is_sys_type = (OB_SYS_TENANT_ID == get_tenant_id_by_object_id(type_id))); if (OB_SUCC(ret)) { ObUDFInfo &uinfo = const_cast(udf_info); - if (is_sys_type) { - // do nothing - } else if (uinfo.udf_package_.empty()) { + if (uinfo.udf_package_.empty()) { // object type name should same as constructor name uinfo.udf_package_ = uinfo.udf_name_; } else if (0 != uinfo.udf_package_.case_compare(uinfo.udf_name_)) { @@ -9604,9 +9626,8 @@ int ObPLResolver::resolve_object_construct(const sql::ObQualifiedName &q_name, } if (OB_SUCC(ret) && (!is_sys_type || user_type->is_opaque_type())) { SMART_VAR(ObPLFunctionAST, dummy_ast, resolve_ctx_.allocator_) { - ObArray access_name; - OZ (access_name.push_back(ObString("SELF"))); - OZ (resolve_udf(uinfo, access_name, dummy_ast)); + ObSEArray access_idxs; + OZ (resolve_udf_info(uinfo, access_idxs, dummy_ast)); } } // @@ -9616,6 +9637,8 @@ int ObPLResolver::resolve_object_construct(const sql::ObQualifiedName &q_name, // actually, here we need to use the default construtor, that is: reolsve record construct // on the other side: object(a number, constructor(a number) constructor object(a varchar)); // resolve_udf will pick the right one, we dont need to resolve record_construct. + + // if pick routine not pick default construct, here pick agin. what if we add mock default construct to pick routine logic. bool use_default_cons = is_sys_type ? (user_type->is_opaque_type() ? false : true) : false; if (OB_SUCC(ret) && !uinfo.is_udt_overload_default_cons() && !use_default_cons) { // must have same attribute and param, exclude self param @@ -9631,8 +9654,9 @@ int ObPLResolver::resolve_object_construct(const sql::ObQualifiedName &q_name, } else { const ObExprResType ¶m_res_type = param_expr->get_result_type(); const ObPLDataType *pl_type = object_type->get_record_member_type(i - 1); - if (OB_NOT_NULL(pl_type) && OB_NOT_NULL(pl_type->get_meta_type()) && - (param_res_type.get_type() == pl_type->get_meta_type()->get_type())) { + if (OB_NOT_NULL(pl_type) + && OB_NOT_NULL(pl_type->get_meta_type()) + && (param_res_type.get_type() == pl_type->get_meta_type()->get_type())) { // do nothing } else { use_default_cons = false; @@ -9642,6 +9666,7 @@ int ObPLResolver::resolve_object_construct(const sql::ObQualifiedName &q_name, } } } + OX (expr = udf_info.ref_expr_); // if cant find user define construtor, try default construct if ((OB_SUCCESS == ret && use_default_cons) || OB_ERR_SP_WRONG_ARG_NUM == ret @@ -9684,7 +9709,7 @@ int ObPLResolver::resolve_record_construct(const ObQualifiedName &q_name, if (OB_SUCC(ret) && ((!udf_info.is_udf_udt_cons() && param_cnt != member_cnt) - || (udf_info.is_udf_udt_cons() && param_cnt - 1 != member_cnt)) + || (udf_info.is_udf_udt_cons() && param_cnt - 1 != member_cnt)) && !is_opaque_cons_and_no_self_param) { ret = OB_ERR_CALL_WRONG_ARG; LOG_WARN("PLS-00306: wrong number or types of arguments in call", @@ -9748,52 +9773,73 @@ int ObPLResolver::resolve_collection_construct(const ObQualifiedName &q_name, return ret; } -int ObPLResolver::resolve_udf_without_brackets(ObQualifiedName &q_name, - ObPLCompileUnitAST &unit_ast, - ObRawExpr *&expr) +int ObPLResolver::resolve_udf_without_brackets( + ObQualifiedName &q_name, ObPLCompileUnitAST &unit_ast, ObRawExpr *&expr) { int ret = OB_SUCCESS; - bool check_success = false; - ObSchemaChecker schema_checker; - UNUSED(unit_ast); - OZ (schema_checker.init(resolve_ctx_.schema_guard_)); - CK (OB_NOT_NULL(current_block_)); - OZ (ObRawExprResolverImpl::check_pl_udf(q_name, - &resolve_ctx_.session_info_, - &schema_checker, - ¤t_block_->get_namespace(), - check_success)); - if (OB_ERR_INVOKE_STATIC_BY_INSTANCE == ret) { - // do nothing - } else if (OB_FAIL(ret)) { + ObUDFRawExpr *udf_expr = NULL; + ObObjAccessIdent &access_ident = q_name.access_idents_.at(q_name.access_idents_.count() - 1); + ObUDFInfo &udf_info = access_ident.udf_info_; + ObSEArray access_idxs; + OX (access_ident.set_pl_udf()); + OZ (expr_factory_.create_raw_expr(T_FUN_UDF, udf_expr), K(q_name)); + CK (OB_NOT_NULL(udf_expr)); + OX (udf_expr->set_func_name(q_name.col_name_)); + OX (udf_info.ref_expr_ = udf_expr); + OX (udf_info.udf_name_ = access_ident.access_name_); + OZ (resolve_name(q_name, current_block_->get_namespace(), expr_factory_, &resolve_ctx_.session_info_, access_idxs, unit_ast)); + OV (access_idxs.at(access_idxs.count() - 1).is_udf_type()); + OX (expr = access_idxs.at(access_idxs.count() - 1).get_sysfunc_); + CK (OB_NOT_NULL(expr)); + if (OB_FAIL(ret) && ret != OB_ERR_INSUFFICIENT_PRIVILEGE) { ret = OB_ERR_SP_UNDECLARED_VAR; - } else if (!check_success) { - ret = OB_ERR_SP_UNDECLARED_VAR; - } else if (check_success) { - ObUDFRawExpr *udf_expr = NULL; - ObObjAccessIdent &access_ident = q_name.access_idents_.at(q_name.access_idents_.count() - 1); - ObUDFInfo &udf_info = access_ident.udf_info_; - CK (q_name.is_pl_udf()); - OZ (expr_factory_.create_raw_expr(T_FUN_UDF, udf_expr), q_name); - CK (OB_NOT_NULL(udf_expr)); // 无参的函数调用, 走到这里一定没有参数 - OX (udf_expr->set_func_name(q_name.col_name_)); - OX (udf_info.ref_expr_ = udf_expr); - OX (udf_info.udf_name_ = q_name.col_name_); - OX (udf_info.udf_package_ = q_name.tbl_name_); - OX (udf_info.udf_database_ = q_name.database_name_); - ObArray access_name; - if (udf_info.is_udt_udf_) { - for (int64_t i = 0; OB_SUCC(ret) && i < q_name.access_idents_.count() - 1; ++i) { - if (!q_name.access_idents_.at(i).access_name_.empty()) { - OZ (access_name.push_back(q_name.access_idents_.at(i).access_name_)); + } + return ret; +} + +int ObPLResolver::replace_udf_param_expr( + ObQualifiedName &q_name, ObIArray &columns, ObIArray &real_exprs) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < q_name.access_idents_.count(); ++i) { + ObObjAccessIdent &access_ident = q_name.access_idents_.at(i); + if (access_ident.is_pl_udf()) { + OZ (replace_udf_param_expr(access_ident, columns, real_exprs)); + } + } + return ret; +} + +int ObPLResolver::replace_udf_param_expr( + ObObjAccessIdent &access_ident, ObIArray &columns, ObIArray &real_exprs) +{ + int ret = OB_SUCCESS; + ObUDFInfo &udf_info = access_ident.udf_info_; + ObRawExpr *expr = static_cast(udf_info.ref_expr_); + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("udf expr is null", K(ret)); + } else { + //如果是UDF,要先把UDF INFO里的参数替换掉,否则重载匹配的时候会失败 + for (int64_t i = 0; OB_SUCC(ret) && i < real_exprs.count(); ++i) { + OZ (ObRawExprUtils::replace_ref_column(expr, columns.at(i).ref_expr_, real_exprs.at(i))); + for (int64_t j = 0; OB_SUCC(ret) && j < udf_info.param_exprs_.count(); ++j) { + CK (OB_NOT_NULL(udf_info.param_exprs_.at(j))); + if (OB_FAIL(ret)) { + } else if (udf_info.param_exprs_.at(j) == columns.at(i).ref_expr_) { + udf_info.param_exprs_.at(j) = real_exprs.at(i); + } else if (T_SP_CPARAM == udf_info.param_exprs_.at(j)->get_expr_type()) { + ObCallParamRawExpr* call_expr = + static_cast(udf_info.param_exprs_.at(j)); + CK (OB_NOT_NULL(call_expr)); + if (OB_SUCC(ret) && call_expr->get_expr() == columns.at(i).ref_expr_) { + call_expr->set_expr(real_exprs.at(i)); + } + } else if (udf_info.param_exprs_.at(j)->get_param_count() > 0) { + OZ (recursive_replace_expr(udf_info.param_exprs_.at(j), columns.at(i), real_exprs.at(i))); } } } - if (0 == access_name.count()) { - OZ (access_name.push_back(ObString("SELF"))); - } - OZ (resolve_udf(udf_info, access_name, unit_ast), q_name, udf_info); - OX (expr = udf_expr); } return ret; } @@ -9808,6 +9854,8 @@ int ObPLResolver::resolve_qualified_name(ObQualifiedName &q_name, SET_LOG_CHECK_MODE(); + OZ (replace_udf_param_expr(q_name, columns, real_exprs)); + if (q_name.is_sys_func()) { if (OB_FAIL(q_name.access_idents_.at(0).sys_func_expr_->check_param_num())) { LOG_WARN("sys func param number not match", K(ret)); @@ -9841,53 +9889,23 @@ int ObPLResolver::resolve_qualified_name(ObQualifiedName &q_name, ret = OB_ERR_UNEXPECTED; LOG_WARN("udf expr is null", K(ret)); } else { - //如果是UDF,要先把UDF INFO里的参数替换掉,否则重载匹配的时候会失败 - for (int64_t i = 0; OB_SUCC(ret) && i < real_exprs.count(); ++i) { - OZ (ObRawExprUtils::replace_ref_column(expr, columns.at(i).ref_expr_, real_exprs.at(i))); - for (int64_t j = 0; OB_SUCC(ret) && j < udf_info.param_exprs_.count(); ++j) { - CK (OB_NOT_NULL(udf_info.param_exprs_.at(j))); - if (OB_FAIL(ret)) { - } else if (udf_info.param_exprs_.at(j) == columns.at(i).ref_expr_) { - udf_info.param_exprs_.at(j) = real_exprs.at(i); - } else if (T_SP_CPARAM == udf_info.param_exprs_.at(j)->get_expr_type()) { - ObCallParamRawExpr* call_expr = - static_cast(udf_info.param_exprs_.at(j)); - CK (OB_NOT_NULL(call_expr)); - if (OB_SUCC(ret) && call_expr->get_expr() == columns.at(i).ref_expr_) { - call_expr->set_expr(real_exprs.at(i)); - } - } else if (udf_info.param_exprs_.at(j)->get_param_count() > 0) { - OZ (recursive_replace_expr(udf_info.param_exprs_.at(j), columns.at(i), real_exprs.at(i))); - } - } - } if (OB_SUCC(ret)) { if (q_name.is_pl_udf()) { - // 首先尝试下是不是复杂类型的构造函数 - int64_t acc_cnt = q_name.access_idents_.count(); - bool is_construct = false; - if (1 < acc_cnt && q_name.access_idents_.at(acc_cnt - 2).is_udt_ns()) { - // udt obj.func(), this func can not be a constructor - ret = OB_ERR_SP_UNDECLARED_TYPE; + ObSEArray access_idxs; + OZ (resolve_name(q_name, current_block_->get_namespace(), expr_factory_, &resolve_ctx_.session_info_, access_idxs, unit_ast)); + if (OB_FAIL(ret)) { + } else if (access_idxs.at(access_idxs.count() - 1).is_udf_type()) { + OX (expr = reinterpret_cast(access_idxs.at(access_idxs.count() - 1).get_sysfunc_)); } else { - OZ (resolve_construct(q_name, udf_info, expr), K(q_name)); - if (OB_SUCC(ret)) { - is_construct = true; - } + OZ (make_var_from_access(access_idxs, + expr_factory_, + &(resolve_ctx_.session_info_), + &(resolve_ctx_.schema_guard_), + current_block_->get_namespace(), + expr)); } - // 其次尝试下是不是UDF - if (OB_ERR_SP_UNDECLARED_TYPE == ret || OB_ERR_PACKAGE_DOSE_NOT_EXIST == ret) { - ret = OB_SUCCESS; - ObArray access_name; - OZ (access_name.push_back(ObString("SELF"))); - OZ (resolve_udf(udf_info, access_name, unit_ast), q_name, udf_info); - } - - if (OB_SUCC(ret) && is_construct == false && udf_info.is_new_keyword_used_) { - ret = OB_ERR_PARSER_SYNTAX; - LOG_WARN("NEW key word is only allowed for constructors", K(q_name)); - } - } else { //如果是udf return access,需要当做var解析 + CK (OB_NOT_NULL(expr)); + } else { // 如果是udf return access,需要当做var解析 if (OB_FAIL(resolve_var(q_name, unit_ast, expr))) { LOG_WARN("failed to resolve var", K(q_name), K(ret)); } @@ -9957,362 +9975,302 @@ int ObPLResolver::resolve_var(ObQualifiedName &q_name, ObPLCompileUnitAST &func, return ret; } -int ObPLResolver::resolve_udf(ObUDFInfo &udf_info, - const ObIArray &access_name, - ObPLCompileUnitAST &func) +int ObPLResolver::make_self_symbol_expr(ObPLCompileUnitAST &func, ObRawExpr *&expr) { int ret = OB_SUCCESS; - ObString db_name; - ObString package_name; - ObString udf_name; + ObObjAccessIdent access_ident; + ObArray access_idxs; + new (&access_ident) ObObjAccessIdent(ObString("SELF"), OB_INVALID_INDEX); + OX (expr = NULL); + CK (OB_NOT_NULL(current_block_)); + OZ (resolve_access_ident(access_ident, + current_block_->get_namespace(), + expr_factory_, + &resolve_ctx_.session_info_, + access_idxs, + func)); + OZ (make_var_from_access(access_idxs, + expr_factory_, + &(resolve_ctx_.session_info_), + &(resolve_ctx_.schema_guard_), + current_block_->get_namespace(), + expr)); + CK (OB_NOT_NULL(expr)); + return ret; +} + + +int ObPLResolver::resolve_udf_info( + ObUDFInfo &udf_info, ObIArray &access_idxs, ObPLCompileUnitAST &func) +{ + int ret = OB_SUCCESS; + ObString db_name = udf_info.udf_database_; + ObString package_name = udf_info.udf_package_; + ObString udf_name = udf_info.udf_name_; ObSchemaChecker schema_checker; + const ObIRoutineInfo *routine_info = NULL; + ObProcType routine_type = STANDALONE_FUNCTION; + ObSEArray expr_params; + CK (OB_NOT_NULL(udf_info.ref_expr_)); CK (OB_NOT_NULL(current_block_)); OZ (schema_checker.init(resolve_ctx_.schema_guard_)); - if (OB_SUCC(ret)) { - // access name like : pkg.obj.routine - // first is pkg, then object instance name, then routine name - if (udf_info.is_udt_udf_inside_pkg_) { - db_name = resolve_ctx_.session_info_.get_database_name(); - package_name = udf_info.udf_package_; - udf_name = udf_info.udf_name_; + OZ (ObRawExprUtils::rebuild_expr_params(udf_info, &expr_factory_, expr_params), K(udf_info), K(access_idxs)); + { + ObPLMockSelfArg self(access_idxs, expr_params, expr_factory_); + OZ (self.mock()); + OZ (current_block_->get_namespace().resolve_routine(resolve_ctx_, + udf_info.udf_database_, + udf_info.udf_package_, + udf_info.udf_name_, + expr_params, + routine_type, + routine_info), K(udf_info)); + } + + + // adjust routine database name, will set to ObUDFRawExpr later. + if (OB_SUCC(ret) && db_name.empty() && OB_NOT_NULL(routine_info)) { + if (routine_info->get_database_id() != OB_INVALID_ID && + routine_info->get_database_id() != resolve_ctx_.session_info_.get_database_id()) { + const ObDatabaseSchema *database_schema = NULL; + OZ (resolve_ctx_.schema_guard_.get_database_schema( + resolve_ctx_.session_info_.get_effective_tenant_id(), routine_info->get_database_id(), database_schema)); + CK (OB_NOT_NULL(database_schema)); + OX (db_name = database_schema->get_database_name_str()); } else { - OZ (ObResolverUtils::resolve_udf_name(schema_checker, - resolve_ctx_.session_info_, - udf_info, - db_name, - package_name, - udf_name)); + OX (db_name = resolve_ctx_.session_info_.get_database_name()); } } + if (OB_SUCC(ret)) { - const ObIRoutineInfo *routine_info = NULL; - ObProcType routine_type = STANDALONE_FUNCTION; - ObSEArray expr_params; - if (OB_FAIL(ObRawExprUtils::rebuild_expr_params(udf_info, &expr_factory_, expr_params))) { - LOG_WARN("failed to rebuild expr params", K(ret), K(udf_info)); - } else if (OB_FAIL(current_block_->get_namespace().resolve_routine( - resolve_ctx_, - db_name, - package_name, - udf_name, - expr_params, - routine_type, - routine_info))) { - LOG_WARN("resolve routine failed", K(db_name), K(package_name), K(udf_name), K(expr_params), K(ret)); - // LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, udf_name.length(), udf_name.ptr()); + if (PACKAGE_PROCEDURE == routine_type + || PACKAGE_FUNCTION == routine_type + || UDT_PROCEDURE == routine_type + || UDT_FUNCTION == routine_type) { + + const ObPLRoutineInfo *package_routine_info = static_cast(routine_info); + + CK (OB_NOT_NULL(package_routine_info)); + + OZ (check_package_accessible( + current_block_, resolve_ctx_.schema_guard_, *package_routine_info)); + + if (OB_SUCC(ret) + && (ObPLBlockNS::BLOCK_PACKAGE_SPEC == current_block_->get_namespace().get_block_type() + || ObPLBlockNS::BLOCK_OBJECT_SPEC == current_block_->get_namespace().get_block_type()) + && package_routine_info->get_pkg_id() == current_block_->get_namespace().get_package_id()) { + ret = OB_ERR_REFER_SAME_PACKAGE; + LOG_WARN("variable or constant initialization may not refer to functions" + "declared in the same package", + K(ret), KPC(package_routine_info)); + } + + if (OB_SUCC(ret) + && resolve_ctx_.is_sql_scope_ + && package_routine_info->is_private_routine()) { + ret = OB_ERR_PRIVATE_UDF_USE_IN_SQL; + LOG_WARN("function 'string' may not be used in SQL", K(ret), K(udf_name)); + LOG_USER_ERROR(OB_ERR_PRIVATE_UDF_USE_IN_SQL, udf_name.length(), udf_name.ptr()); + } + + + OX (package_name = package_name.empty() + ? current_block_->get_namespace().get_package_name() : package_name); + + OZ (ObRawExprUtils::resolve_udf_common_info(db_name, + package_name, + package_routine_info->get_id(), + current_block_->get_namespace().get_package_id(), + package_routine_info->get_subprogram_path(), + common::OB_INVALID_VERSION, /*udf_schema_version*/ + current_block_->get_namespace().get_package_version(), + package_routine_info->is_deterministic(), + package_routine_info->is_parallel_enable(), + ObPLBlockNS::BlockType::BLOCK_PACKAGE_BODY == + current_block_->get_namespace().get_block_type(), + false, + common::OB_INVALID_ID, + udf_info)); + OZ (ObRawExprUtils::resolve_udf_param_types(package_routine_info, + resolve_ctx_.schema_guard_, + resolve_ctx_.session_info_, + resolve_ctx_.allocator_, + resolve_ctx_.sql_proxy_, + udf_info), udf_info); + OZ (ObRawExprUtils::resolve_udf_param_exprs(package_routine_info, + current_block_->get_namespace(), + schema_checker, + resolve_ctx_.session_info_, + resolve_ctx_.allocator_, + resolve_ctx_.is_prepare_protocol_, + expr_factory_, + resolve_ctx_.sql_proxy_, + resolve_ctx_.extern_param_info_, + udf_info), udf_info); + } else if (STANDALONE_PROCEDURE == routine_type + || STANDALONE_FUNCTION == routine_type) { + + const share::schema::ObRoutineInfo *schema_routine_info = static_cast(routine_info); + const ObPackageInfo* package_info = NULL; + const ObUDTTypeInfo *udt_info = NULL; + int64_t schema_version = OB_INVALID_VERSION; + uint64_t routine_id = OB_INVALID_ID; + + CK (OB_NOT_NULL(schema_routine_info)); + + OZ (check_routine_accessible( + current_block_, resolve_ctx_.schema_guard_, *schema_routine_info)); + + OX (routine_id = (OB_INVALID_ID == schema_routine_info->get_package_id()) + ? schema_routine_info->get_routine_id() : schema_routine_info->get_subprogram_id()); + + OX (udf_info.is_udt_udf_ = schema_routine_info->is_udt_routine()); + + if (OB_SUCC(ret) && routine_id == schema_routine_info->get_subprogram_id()) { + if (!udf_info.is_udt_udf_) { + OZ (resolve_ctx_.schema_guard_.get_package_info( + schema_routine_info->get_tenant_id(), schema_routine_info->get_package_id(), package_info)); + CK (OB_NOT_NULL(package_info)); + OX (schema_version = package_info->get_schema_version()); + } + } + OZ (ObRawExprUtils::resolve_udf_common_info(db_name, + package_name, + routine_id, + schema_routine_info->get_package_id(), + ObArray(), + routine_id == schema_routine_info->get_subprogram_id() + ? common::OB_INVALID_VERSION + : schema_routine_info->get_schema_version(), + routine_id == schema_routine_info->get_subprogram_id() + ? schema_version + : common::OB_INVALID_VERSION, /*pkg_schema_version*/ + schema_routine_info->is_deterministic(), + schema_routine_info->is_parallel_enable(), + false, /*is_pkg_body_udf*/ + schema_routine_info->is_aggregate(), + schema_routine_info->get_type_id(), + udf_info)); + OZ (ObRawExprUtils::resolve_udf_param_types(schema_routine_info, + resolve_ctx_.schema_guard_, + resolve_ctx_.session_info_, + resolve_ctx_.allocator_, + resolve_ctx_.sql_proxy_, + udf_info), udf_info); + OZ (ObRawExprUtils::resolve_udf_param_exprs(schema_routine_info, + current_block_->get_namespace(), + schema_checker, + resolve_ctx_.session_info_, + resolve_ctx_.allocator_, + resolve_ctx_.is_prepare_protocol_, + expr_factory_, + resolve_ctx_.sql_proxy_, + resolve_ctx_.extern_param_info_, + udf_info), udf_info); + } else if (NESTED_PROCEDURE == routine_type || NESTED_FUNCTION == routine_type) { + const ObPLRoutineInfo *sub_routine_info = static_cast(routine_info); + + CK (OB_NOT_NULL(sub_routine_info)); + + OZ (ObRawExprUtils::resolve_udf_common_info(db_name, + package_name, + sub_routine_info->get_parent_id(), + current_block_->get_namespace().get_package_id(), + sub_routine_info->get_subprogram_path(), + common::OB_INVALID_VERSION, /*udf_schema_version*/ + common::OB_INVALID_VERSION, /*pkg_schema_version*/ + sub_routine_info->is_deterministic(), + sub_routine_info->is_parallel_enable(), + pl::ObPLBlockNS::BlockType::BLOCK_PACKAGE_BODY + == current_block_->get_namespace().get_block_type(), + false, + common::OB_INVALID_ID, + udf_info)); + OZ (ObRawExprUtils::resolve_udf_param_types(sub_routine_info, + resolve_ctx_.schema_guard_, + resolve_ctx_.session_info_, + resolve_ctx_.allocator_, + resolve_ctx_.sql_proxy_, + udf_info), udf_info); + OZ (ObRawExprUtils::resolve_udf_param_exprs(sub_routine_info, + current_block_->get_namespace(), + schema_checker, + resolve_ctx_.session_info_, + resolve_ctx_.allocator_, + resolve_ctx_.is_prepare_protocol_, + expr_factory_, + resolve_ctx_.sql_proxy_, + resolve_ctx_.extern_param_info_, + udf_info), udf_info); } else { - // while member routine call member routine, we have to fill the callee self param, - // note: caller must have self param, so here wo just use self as first param. - // ex: - /* - * member procedure pp(a number) is begin pp1(a); end; - * while pp has a implicit self argument, we just use this as the self argument - * as the fisrt implicit self arguement of pp1; so wo got: - * member procedure pp (self object, a number) is begin pp1(self, a); end; - * constructor is not fit for this approach, for it has self argument is a new one - * additional case: - * a member function can be used as a static function, - * declare - * ty obj_type := obj_type(3); - * begin - * obj_type.pp(ty, 7); - * end; - * in this case, expr_params count is same as routine info's param, we need not to - * add self argument - */ - bool need_add_self = expr_params.count() < routine_info->get_param_count(); - if (!resolve_ctx_.is_check_mode_ && routine_info->is_udt_routine() - && !(routine_info->is_udt_static_routine() || routine_info->is_udt_cons()) - && !udf_info.is_contain_self_param_ && need_add_self) { - CK (OB_NOT_NULL(udf_info.ref_expr_)); - if (OB_SUCC(ret)) { - ObIArray ¶ms = udf_info.ref_expr_->get_param_exprs(); - int64_t param_cnt = params.count(); - if (0 < param_cnt && params.at(0)->has_flag(IS_UDT_UDF_SELF_PARAM)) { - // do nothing - } else { - OZ (make_udt_udf_self_expr(access_name, func, udf_info.self_arg_)); - CK (OB_NOT_NULL(udf_info.self_arg_)); - OZ (udf_info.ref_expr_->add_param_expr(udf_info.self_arg_)); - OX (udf_info.udf_param_num_++); - param_cnt = params.count(); - // make the self param the first one - if (OB_SUCC(ret) && 1 < param_cnt) { - for(int64_t i = param_cnt - 1; OB_SUCC(ret) && i > 0; --i) { - udf_info.ref_expr_->replace_param_expr(i, params.at(i - 1)); + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected routine type", + K(routine_type), K(db_name), K(package_name), K(udf_name), + K(ret)); + } + if (OB_SUCC(ret) && !resolve_ctx_.is_sql_scope_) { + ObUDFRawExpr *udf_raw_expr = NULL; + const ObPLSymbolTable *table = current_block_->get_symbol_table(); + CK (OB_NOT_NULL(table)); + CK (OB_NOT_NULL(udf_raw_expr = udf_info.ref_expr_)); + for (int64_t i = 0; OB_SUCC(ret) && i < udf_raw_expr->get_params_desc().count(); ++i) { + int64_t position = udf_raw_expr->get_param_position(i); + if (position != OB_INVALID_INDEX + && udf_raw_expr->get_params_desc().at(i).is_local_out()) { + const ObPLVar *var = NULL; + ObExprResType result_type; + CK (OB_NOT_NULL(var = table->get_symbol(position))); + if (OB_SUCC(ret) && var->is_readonly()) { + if (var->get_name().prefix_match(ANONYMOUS_ARG)) { + ObPLVar* shadow_var = const_cast(var); + ObIRoutineParam *iparam = NULL; + OX (shadow_var->set_readonly(false)); + CK (OB_NOT_NULL(routine_info)); + OZ (routine_info->get_routine_param(i, iparam)); + if (OB_SUCC(ret) && iparam->is_inout_param()) { + shadow_var->set_name(ANONYMOUS_INOUT_ARG); } - udf_info.ref_expr_->replace_param_expr(0, udf_info.self_arg_); - } - OX (udf_info.is_contain_self_param_ = true); - } - } - } - if (db_name.empty()) { - db_name = resolve_ctx_.session_info_.get_database_name(); - } - if (PACKAGE_PROCEDURE == routine_type || PACKAGE_FUNCTION == routine_type - || UDT_PROCEDURE == routine_type || UDT_FUNCTION == routine_type) { - const ObPLRoutineInfo *package_routine_info = static_cast(routine_info); - CK (OB_NOT_NULL(package_routine_info)); - if (PACKAGE_PROCEDURE == routine_type || PACKAGE_FUNCTION == routine_type) { - OZ (check_package_accessible( - current_block_, resolve_ctx_.schema_guard_, *package_routine_info)); - } - if (OB_SUCC(ret) - && (ObPLBlockNS::BLOCK_PACKAGE_SPEC - == current_block_->get_namespace().get_block_type() - || ObPLBlockNS::BLOCK_OBJECT_SPEC - == current_block_->get_namespace().get_block_type()) - && package_routine_info->get_pkg_id() - == current_block_->get_namespace().get_package_id()) { - ret = OB_ERR_REFER_SAME_PACKAGE; - LOG_WARN("variable or constant initialization may not refer to functions" - "declared in the same package", - K(ret), KPC(package_routine_info)); - } - /* - * create or replace package body c_pack is - function c_fun(a number) return number is - begin - return a; - end; - procedure c_proc is - v_value number; - begin - v_value = c_func(2); // this is ok - select c_fun(id) into v_value from c_table where c_fun(id) is not null; // prepare - DBMS_OUTPUT.PUT_LINE('v: ' || v_value); - end; - end; - * - * 上例中select dml语句会先prepare,prepare结束后会带回一个反拼的语句,上述反拼语句会变成如下: - * select test.c_fun(c_table.id) into c_pack.v_value - * from test.c_table where test.c_fun(c_table.id) is not null - * 这儿反拼的时候会将c_fun的package前缀漏掉,这个时候拿这条sql去resolve是有问题的,这个函数会找不到。 - * 问题就在于prepare的时候,在resolve c_fun也会进入这儿,但这个时候udf_info中的package name是空的, - * 因为它本来就没有写,所以在构建ObUDFRawExpr的时候,package name字段是空的,反拼的时候就是导致如上的问题。 - * 解决方法是我们知道当前是在package中,知道package id,所以拿这个id找package name,进行赋值。 - * package_name不为空,它可能不是当前的package,所以不能替换,为空,说明要么是当前的,要么是schema函数 - * - * 为何不在dml中的直接使用函数名调用pkg的成员函数是可以的?因为后面用不到package name,只需要package id。 - * - * 是否需要udt_info里面的package name如果是空的是否需要赋值一下? 看起来是没有用到,可以先不赋值。 - */ - ObString pkg_name; - if (PACKAGE_PROCEDURE == routine_type || PACKAGE_FUNCTION == routine_type) { - if (package_name.empty()) { - uint64_t pkg_id = current_block_->get_namespace().get_package_id(); - const uint64_t tenant_id = get_tenant_id_by_object_id(pkg_id); - if (OB_SUCC(ret) && OB_INVALID_ID != pkg_id) { - const ObPackageInfo *pkg_info = NULL; - OZ (resolve_ctx_.schema_guard_.get_package_info(tenant_id, pkg_id, pkg_info)); - CK (OB_NOT_NULL(pkg_info)); - OZ (ob_write_string(resolve_ctx_.allocator_, pkg_info->get_package_name(), pkg_name)); + } else { + ret = OB_ERR_VARIABLE_IS_READONLY; + LOG_WARN("variable is read only", K(ret), K(position), KPC(var)); } } - } - if (OB_SUCC(ret) - && resolve_ctx_.is_sql_scope_ - && package_routine_info->is_private_routine()) { - ret = OB_ERR_PRIVATE_UDF_USE_IN_SQL; - LOG_WARN("function 'string' may not be used in SQL", K(ret), K(udf_name)); - LOG_USER_ERROR(OB_ERR_PRIVATE_UDF_USE_IN_SQL, udf_name.length(), udf_name.ptr()); - } - OZ (check_package_accessible( - current_block_, resolve_ctx_.schema_guard_, *package_routine_info)); - OZ (ObRawExprUtils::resolve_udf_common_info(db_name, - package_name.empty() ? pkg_name : package_name, - package_routine_info->get_id(), - current_block_->get_namespace().get_package_id(), - package_routine_info->get_subprogram_path(), - common::OB_INVALID_VERSION, /*udf_schema_version*/ - current_block_->get_namespace().get_package_version(), - package_routine_info->is_deterministic(), - package_routine_info->is_parallel_enable(), - ObPLBlockNS::BlockType::BLOCK_PACKAGE_BODY == - current_block_->get_namespace().get_block_type(), - false, - common::OB_INVALID_ID, - udf_info)); - OZ (ObRawExprUtils::resolve_udf_param_types(package_routine_info, - resolve_ctx_.schema_guard_, - resolve_ctx_.session_info_, - resolve_ctx_.allocator_, - resolve_ctx_.sql_proxy_, - udf_info), udf_info); - OZ (ObRawExprUtils::resolve_udf_param_exprs(package_routine_info, - current_block_->get_namespace(), - schema_checker, - resolve_ctx_.session_info_, - resolve_ctx_.allocator_, - resolve_ctx_.is_prepare_protocol_, - expr_factory_, - resolve_ctx_.sql_proxy_, - resolve_ctx_.extern_param_info_, - udf_info), udf_info); - } else if (STANDALONE_PROCEDURE == routine_type || STANDALONE_FUNCTION == routine_type) { - const share::schema::ObRoutineInfo *schema_routine_info = static_cast(routine_info); - const ObPackageInfo* package_info = NULL; - const ObUDTTypeInfo *udt_info = NULL; - int64_t schema_version = OB_INVALID_VERSION; - CK (OB_NOT_NULL(schema_routine_info)); - if (OB_SUCC(ret) && schema_routine_info->is_udt_routine()) { - udf_info.is_udt_udf_ = true; - } - OZ (check_routine_accessible( - current_block_, resolve_ctx_.schema_guard_, *schema_routine_info)); - uint64_t routine_id = OB_INVALID_ID == schema_routine_info->get_package_id() ? - schema_routine_info->get_routine_id() : schema_routine_info->get_subprogram_id(); - if (OB_SUCC(ret) && routine_id == schema_routine_info->get_subprogram_id()) { - if (!udf_info.is_udt_udf_) { - OZ (resolve_ctx_.schema_guard_.get_package_info( - schema_routine_info->get_tenant_id(), - schema_routine_info->get_package_id(), - package_info)); - CK (OB_NOT_NULL(package_info)); - OX (schema_version = package_info->get_schema_version()); - } - } - OZ (ObRawExprUtils::resolve_udf_common_info(db_name, - package_name, - routine_id, - schema_routine_info->get_package_id(), - ObArray(), - routine_id == schema_routine_info->get_subprogram_id() - ? common::OB_INVALID_VERSION - : schema_routine_info->get_schema_version(), - routine_id == schema_routine_info->get_subprogram_id() - ? schema_version - : common::OB_INVALID_VERSION, /*pkg_schema_version*/ - schema_routine_info->is_deterministic(), - schema_routine_info->is_parallel_enable(), - false, /*is_pkg_body_udf*/ - schema_routine_info->is_aggregate(), - schema_routine_info->get_type_id(), - udf_info)); - OZ (ObRawExprUtils::resolve_udf_param_types(schema_routine_info, - resolve_ctx_.schema_guard_, - resolve_ctx_.session_info_, - resolve_ctx_.allocator_, - resolve_ctx_.sql_proxy_, - udf_info), udf_info); - OZ (ObRawExprUtils::resolve_udf_param_exprs(schema_routine_info, - current_block_->get_namespace(), - schema_checker, - resolve_ctx_.session_info_, - resolve_ctx_.allocator_, - resolve_ctx_.is_prepare_protocol_, - expr_factory_, - resolve_ctx_.sql_proxy_, - resolve_ctx_.extern_param_info_, - udf_info), udf_info); - } else if (NESTED_PROCEDURE == routine_type || NESTED_FUNCTION == routine_type) { - const ObPLRoutineInfo *sub_routine_info - = static_cast(routine_info); - CK (OB_NOT_NULL(sub_routine_info)); - OZ (ObRawExprUtils::resolve_udf_common_info(db_name, - package_name, - sub_routine_info->get_parent_id(), - current_block_->get_namespace().get_package_id(), - sub_routine_info->get_subprogram_path(), - common::OB_INVALID_VERSION, /*udf_schema_version*/ - common::OB_INVALID_VERSION, /*pkg_schema_version*/ - sub_routine_info->is_deterministic(), - sub_routine_info->is_parallel_enable(), - pl::ObPLBlockNS::BlockType::BLOCK_PACKAGE_BODY - == current_block_->get_namespace().get_block_type(), - false, - common::OB_INVALID_ID, - udf_info)); - OZ (ObRawExprUtils::resolve_udf_param_types(sub_routine_info, - resolve_ctx_.schema_guard_, - resolve_ctx_.session_info_, - resolve_ctx_.allocator_, - resolve_ctx_.sql_proxy_, - udf_info), udf_info); - OZ (ObRawExprUtils::resolve_udf_param_exprs(sub_routine_info, - current_block_->get_namespace(), - schema_checker, - resolve_ctx_.session_info_, - resolve_ctx_.allocator_, - resolve_ctx_.is_prepare_protocol_, - expr_factory_, - resolve_ctx_.sql_proxy_, - resolve_ctx_.extern_param_info_, - udf_info), udf_info); - } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("Unexpected routine type", - K(routine_type), - K(db_name), - K(package_name), - K(udf_name), - K(ret)); - } - if (OB_SUCC(ret) && !resolve_ctx_.is_sql_scope_) { - ObUDFRawExpr *udf_raw_expr = NULL; - const ObPLSymbolTable *table = current_block_->get_symbol_table(); - CK (OB_NOT_NULL(table)); - CK (OB_NOT_NULL(udf_raw_expr = udf_info.ref_expr_)); - for (int64_t i = 0; OB_SUCC(ret) && i < udf_raw_expr->get_params_desc().count(); ++i) { - int64_t position = udf_raw_expr->get_param_position(i); - if (position != OB_INVALID_INDEX - && udf_raw_expr->get_params_desc().at(i).is_local_out()) { - const ObPLVar *var = NULL; - ObExprResType result_type; - CK (OB_NOT_NULL(var = table->get_symbol(position))); - if (OB_SUCC(ret) && var->is_readonly()) { - if (var->get_name().prefix_match(ANONYMOUS_ARG)) { - ObPLVar* shadow_var = const_cast(var); - ObIRoutineParam *iparam = NULL; - OX (shadow_var->set_readonly(false)); - CK (OB_NOT_NULL(routine_info)); - OZ (routine_info->get_routine_param(i, iparam)); - if (OB_SUCC(ret) && iparam->is_inout_param()) { - shadow_var->set_name(ANONYMOUS_INOUT_ARG); - } - } else { - ret = OB_ERR_VARIABLE_IS_READONLY; - LOG_WARN("variable is read only", K(ret), K(position), KPC(var)); - } + if (OB_SUCC(ret)) { + const ObPLDataType &pl_type = var->get_type(); + if (pl_type.is_obj_type() + && pl_type.get_data_type()->get_obj_type() != ObNullType) { + ObExprResTypes ¶ms_type + = static_cast(udf_raw_expr->get_params_type()); + CK (OB_NOT_NULL(pl_type.get_data_type())); + OX (result_type = params_type.at(i)); + OX (result_type.set_meta(pl_type.get_data_type()->get_meta_type())); + OX (result_type.set_accuracy(pl_type.get_data_type()->get_accuracy())); + OX (params_type[i] = result_type); } if (OB_SUCC(ret)) { - const ObPLDataType &pl_type = var->get_type(); - if (pl_type.is_obj_type() - && pl_type.get_data_type()->get_obj_type() != ObNullType) { - ObExprResTypes ¶ms_type - = static_cast(udf_raw_expr->get_params_type()); - CK (OB_NOT_NULL(pl_type.get_data_type())); - OX (result_type = params_type.at(i)); - OX (result_type.set_meta(pl_type.get_data_type()->get_meta_type())); - OX (result_type.set_accuracy(pl_type.get_data_type()->get_accuracy())); - OX (params_type[i] = result_type); - } - if (OB_SUCC(ret)) { - LOG_DEBUG("rewrite params type", - K(ret), K(i), KPC(pl_type.get_data_type()), - K(udf_raw_expr->get_params_type().at(i)), - K(udf_raw_expr->get_params_type().at(i).get_accuracy()), - K(result_type)); - } else { - LOG_WARN("rewrite params type failed", K(ret), K(i), K(pl_type)); - } + LOG_DEBUG("rewrite params type", + K(ret), K(i), KPC(pl_type.get_data_type()), + K(udf_raw_expr->get_params_type().at(i)), + K(udf_raw_expr->get_params_type().at(i).get_accuracy()), + K(result_type)); + } else { + LOG_WARN("rewrite params type failed", K(ret), K(i), K(pl_type)); } } } } - if (OB_SUCC(ret)) { - ObUDFRawExpr *udf_raw_expr = NULL; - CK (OB_NOT_NULL(udf_raw_expr = udf_info.ref_expr_)); - OX (udf_raw_expr->set_is_udt_cons(udf_info.is_udf_udt_cons())); - OX (udf_raw_expr->set_is_udt_udf(routine_info->is_udt_routine())); - OX (udf_raw_expr->set_is_deterministic(routine_info->is_deterministic())); - if (OB_SUCC(ret) - && udf_info.is_udf_udt_cons() - && OB_NOT_NULL(udf_raw_expr->get_param_expr(0))) { - OX (udf_raw_expr->set_pkg_id(udf_raw_expr->get_param_expr(0)->get_result_type().get_udt_id())); - } + } + if (OB_SUCC(ret)) { + ObUDFRawExpr *udf_raw_expr = NULL; + CK (OB_NOT_NULL(udf_raw_expr = udf_info.ref_expr_)); + OX (udf_raw_expr->set_is_udt_cons(udf_info.is_udf_udt_cons())); + OX (udf_raw_expr->set_is_udt_udf(routine_info->is_udt_routine())); + OX (udf_raw_expr->set_is_deterministic(routine_info->is_deterministic())); + if (OB_SUCC(ret) + && udf_info.is_udf_udt_cons() + && OB_NOT_NULL(udf_raw_expr->get_param_expr(0))) { + OX (udf_raw_expr->set_pkg_id(udf_raw_expr->get_param_expr(0)->get_result_type().get_udt_id())); } } } @@ -11130,6 +11088,9 @@ int ObPLResolver::resolve_var(ObQualifiedName &q_name, ObPLBlockNS &ns, ObSEArray access_idxs; if (OB_FAIL(resolve_name(q_name, ns, expr_factory, session_info, access_idxs, func))) { LOG_IN_CHECK_MODE("failed to resolve symbol", K(q_name), K(ret)); + ret = (OB_ERR_SP_DOES_NOT_EXIST == ret + || OB_ERR_FUNCTION_UNKNOWN == ret + || OB_ERR_SP_WRONG_ARG_NUM == ret) ? OB_ERR_SP_UNDECLARED_VAR : ret; } else if (!ObObjAccessIdx::is_local_variable(access_idxs) && !ObObjAccessIdx::is_function_return_variable(access_idxs) && !ObObjAccessIdx::is_package_variable(access_idxs) @@ -11245,7 +11206,12 @@ int ObPLResolver::build_obj_access_func_name(const ObIArray &acc } else if (OB_INVALID_INDEX != access_idxs.at(i).var_index_) { OZ (buf.append_fmt("_var_index_%ld", access_idxs.at(i).var_index_), i, access_idxs); - } else if (NULL != access_idxs.at(i).get_sysfunc_) { + } else if (NULL == access_idxs.at(i).get_sysfunc_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Cannot generate function name for Unexpected ObjAccess", + K(access_idxs), K(ret)); + } + if (NULL != access_idxs.at(i).get_sysfunc_) { OZ (buf.append_fmt("_get_sysfunc_"), i, access_idxs); if (OB_SUCC(ret)) { HEAP_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf) { @@ -11267,10 +11233,6 @@ int ObPLResolver::build_obj_access_func_name(const ObIArray &acc } } } - } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("Cannot generate function name for Unexpected ObjAccess", - K(access_idxs), K(ret)); } } OZ (ob_write_string(expr_factory.get_allocator(), buf.string(), result)); @@ -11328,7 +11290,7 @@ int ObPLResolver::make_var_from_access(const ObIArray &access_id OZ (expr_factory.create_raw_expr(T_OBJ_ACCESS_REF, obj_access_ref)); CK (OB_NOT_NULL(obj_access_ref)); - OZ (obj_access_ref->add_access_indexs(access_idxs)); + OZ (obj_access_ref->add_access_indexs(access_idxs), K(access_idxs)); OZ (build_obj_access_func_name(access_idxs, expr_factory, session_info, schema_guard, for_write, func_name)); OX (obj_access_ref->set_enum_set_values(access_idxs.at(access_idxs.count() - 1).elem_type_.get_type_info())); @@ -11376,14 +11338,15 @@ int ObPLResolver::resolve_name(ObQualifiedName &q_name, } } else { for (int64_t i = 0; OB_SUCC(ret) && i < q_name.access_idents_.count(); ++i) { - if (OB_FAIL(resolve_access_ident(q_name.access_idents_.at(i), + ObObjAccessIdent &access_ident = q_name.access_idents_.at(i); + if (OB_FAIL(resolve_access_ident(access_ident, ns, expr_factory, session_info, access_idxs, func, - q_name.access_idents_.at(i).is_pl_udf()))) { - LOG_IN_CHECK_MODE("match var idents failed", K(ret)); + access_ident.is_pl_udf()))) { + LOG_IN_CHECK_MODE("match var idents failed", K(ret), K(i), K(q_name.access_idents_)); } } } @@ -11451,105 +11414,31 @@ int ObPLResolver::resolve_access_ident(const ObObjAccessIdent &access_ident, int ObPLResolver::check_is_udt_routine(const ObObjAccessIdent &access_ident, // 当前正在resolve的ident const ObPLBlockNS &ns, ObIArray &access_idxs, - ObObjAccessIdx &access_idx, - ObString &udt_type_name, - uint64_t &udt_id, bool &is_routine) { - UNUSED(access_idx); int ret = OB_SUCCESS; + is_routine = false; + uint64_t udt_id = OB_INVALID_ID; uint64_t cnt = access_idxs.count(); - if (0 < cnt) { - const ObPLDataType &parent_type = access_idxs.at(cnt-1).elem_type_; + if (cnt > 0 && access_idxs.at(cnt - 1).elem_type_.is_object_type()) { + const ObPLDataType &parent_type = access_idxs.at(cnt - 1).elem_type_; const ObUserDefinedType *user_type = NULL; - if (OB_INVALID_ID == parent_type.get_user_type_id()) { - is_routine = false; - } else if (OB_FAIL(ns.get_pl_data_type_by_id(parent_type.get_user_type_id(), user_type))) { - LOG_WARN("get user type by id failed", K(ret)); - } else if (OB_ISNULL(user_type)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("user type is NULL", K(ret)); - } else { - if ((user_type->is_record_type() - || user_type->is_opaque_type()) - && user_type->is_udt_type()) { - common::ObArray expr_params; - ObObjAccessIdx::AccessType acc_proc_type = ObObjAccessIdx::AccessType::IS_INVALID; - ObRoutineType routine_type = ROUTINE_FUNCTION_TYPE; - ObProcType proc_type = INVALID_PROC_TYPE; - bool is_exist = false; - ObString tmp_db_name; - // 可能写了dbname,如: db.obj.xxx, - for (int64_t i = 0; i < cnt; ++i) { - if (ObObjAccessIdx::IS_DB_NS == access_idxs.at(i).access_type_) { - tmp_db_name = access_idxs.at(i).var_name_; - break; - } - } - udt_id = parent_type.get_user_type_id(); - uint64_t db_id = OB_INVALID_ID; - ObString db_name; - // get the type database name - if (tmp_db_name.empty()) { - OZ (get_udt_database_name(resolve_ctx_.schema_guard_, udt_id, db_name)); - } - const ObString &udt_name = user_type->get_name(); - const ObString &routine_name = access_ident.access_name_; - // todo: check is udt is valid - if (OB_INVALID_ID == udt_id || udt_name.empty() || db_name.empty()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("can not get info about udt object", K(udt_id), K(db_name), K(udt_name)); - } else { - if (OB_FAIL(access_ident.extract_params(0, expr_params))) { - LOG_WARN("extract params failed", K(ret)); - } else if (OB_FAIL(ns.check_routine_exists(db_name, - udt_name, - routine_name, - routine_type, - is_exist, - proc_type, - udt_id))) { - LOG_WARN("failed to get udt function type", K(udt_name), K(ret)); - } else if (!is_exist && OB_FAIL(ns.check_routine_exists(db_name, - udt_name, - routine_name, - ROUTINE_PROCEDURE_TYPE, - is_exist, - proc_type, - udt_id))) { - LOG_WARN("failed to get udt procedure type", K(udt_name), K(ret)); - // } else if (OB_FAIL(ns.resolve_routine(resolve_ctx_, - // db_name, - // udt_name, - // routine_name, - // expr_params, - // proc_type, - // routine_info))) { - // LOG_WARN("failed to resolve udt function", K(ret)); - } else { - ObPLDataType invalid_pl_data_type; - if (INVALID_PROC_TYPE == proc_type) { - ret = OB_ERR_NO_PROGRAM_UNIT; - LOG_WARN("invalid object routine", K(ret), K(udt_id), K(udt_name), K(proc_type)); - } else if (NESTED_FUNCTION == proc_type || NESTED_PROCEDURE == proc_type) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("udt function type unexpected", K(ret), K(proc_type),K(udt_name), K(udt_id)); - } else { - acc_proc_type = ObObjAccessIdx::AccessType::IS_EXTERNAL_PROC; - is_routine = true; - } - if (OB_SUCC(ret)) { - // invalid_pl_data_type.reset(); - // new(&access_idx)ObObjAccessIdx(invalid_pl_data_type, acc_proc_type, routine_name, - // invalid_pl_data_type, reinterpret_cast(routine_info)); - udt_type_name = udt_name; - } - } - } - } else { - is_routine = false; - } - } + common::ObArray expr_params; + ObProcType proc_type = INVALID_PROC_TYPE; + bool is_exist = false; + ObString database_name; + ObString object_name; + ObString routine_name = access_ident.access_name_; + + OZ (ns.get_pl_data_type_by_id(parent_type.get_user_type_id(), user_type)); + CK (OB_NOT_NULL(user_type)); + CK (user_type->is_udt_type() && (user_type->is_record_type() || user_type->is_opaque_type())); + OZ (get_udt_database_name(resolve_ctx_.schema_guard_, parent_type.get_user_type_id(), database_name)); + OX (object_name = user_type->get_name()); + OZ (access_ident.extract_params(0, expr_params)); + OZ (ns.check_routine_exists(database_name, object_name, routine_name, ROUTINE_FUNCTION_TYPE, is_exist, proc_type, udt_id)); + OZ (!is_exist ? ns.check_routine_exists(database_name, object_name, routine_name, ROUTINE_PROCEDURE_TYPE, is_exist, proc_type, udt_id) : OB_SUCCESS); + OX (is_routine = is_exist); } return ret; } @@ -11594,13 +11483,570 @@ int ObPLResolver::convert_pltype_to_restype(ObIAllocator &alloc, return ret; } +int ObPLResolver::get_names_by_access_ident(ObObjAccessIdent &access_ident, + ObIArray &access_idxs, + ObString &database_name, + ObString &package_name, + ObString &routine_name) +{ + int ret = OB_SUCCESS; + int64_t cnt = access_idxs.count(); + routine_name = access_ident.access_name_; + if (cnt <= 0) { + // do nothing ... + } else if (ObObjAccessIdx::IS_PKG_NS == access_idxs.at(cnt - 1).access_type_ + || ObObjAccessIdx::IS_UDT_NS == access_idxs.at(cnt - 1).access_type_) { + package_name = access_idxs.at(cnt - 1).var_name_; + if (cnt >= 2) { + OV (2 == cnt, OB_ERR_UNEXPECTED, K(cnt)); + OV (ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt - 2).access_type_, OB_ERR_UNEXPECTED, K(access_idxs.at(cnt - 2))); + OX (database_name = access_idxs.at(cnt - 2).var_name_); + } + } else if (ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt - 1).access_type_) { + database_name = access_idxs.at(cnt - 1).var_name_; + OV (1 == cnt, OB_ERR_UNEXPECTED, K(cnt)); + } else if (access_idxs.at(cnt - 1).var_type_.is_object_type()) { + OZ (get_udt_names( + resolve_ctx_.schema_guard_, access_idxs.at(cnt - 1).var_type_.get_user_type_id(), database_name, package_name)); + } + return ret; +} + +int ObPLResolver::construct_name(ObString &database_name, + ObString &package_name, + ObString &routine_name, + ObSqlString &object_name) +{ + int ret = OB_SUCCESS; + if (!database_name.empty()) { + OZ (object_name.append_fmt("%.*s.", database_name.length(), database_name.ptr())); + } + if (!package_name.empty()) { + OZ (object_name.append_fmt("%.*s.", package_name.length(), package_name.ptr())); + } + CK (!routine_name.empty()); + OZ (object_name.append(routine_name)); + return ret; +} + +int ObPLMockSelfArg::mock() +{ + int ret = OB_SUCCESS; + if (access_idxs_.count() > 0 && expr_params_.count() > 0) { + if (ObObjAccessIdx::IS_UDT_NS == access_idxs_.at(access_idxs_.count() - 1).access_type_ + && expr_params_.at(0)->get_result_type().get_udt_id() + == access_idxs_.at(access_idxs_.count() - 1).var_index_) { + expr_params_.at(0)->add_flag(IS_UDT_UDF_SELF_PARAM); + mocked_ = true; + mark_only_ = true; + } else if (access_idxs_.at(access_idxs_.count() - 1).elem_type_.is_composite_type() + && expr_params_.at(0)->get_result_type().get_udt_id() + == access_idxs_.at(access_idxs_.count() - 1).elem_type_.get_user_type_id()) { + ObConstRawExpr *null_expr = NULL; + OZ (expr_factory_.create_raw_expr(T_NULL, null_expr)); + CK (OB_NOT_NULL(null_expr)); + OZ (null_expr->add_flag(IS_UDT_UDF_SELF_PARAM)); + OZ (expr_params_.push_back(null_expr)); + OX (std::rotate(expr_params_.begin(), expr_params_.begin() + expr_params_.count() - 1, expr_params_.end())); + OX (mocked_ = true); + } + } + return ret; +} + +ObPLMockSelfArg::~ObPLMockSelfArg() +{ + int ret = OB_SUCCESS; + if (mocked_) { + if (mark_only_) { + expr_params_.at(0)->clear_flag(IS_UDT_UDF_SELF_PARAM); + } else { + std::rotate(expr_params_.begin(), expr_params_.begin() + 1, expr_params_.end()); + if (!expr_params_.at(expr_params_.count() - 1)->has_flag(IS_UDT_UDF_SELF_PARAM)) { + LOG_ERROR("rotate failed", K(expr_params_)); + } + expr_params_.pop_back(); + } + } +} + +int ObPLResolver::resolve_routine(ObObjAccessIdent &access_ident, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + ObPLCompileUnitAST &func) +{ + int ret = OB_SUCCESS; + + ObString database_name, package_name, routine_name; + const ObIRoutineInfo *routine_info = NULL; + ObSEArray expr_params; + ObProcType routine_type = access_ident.is_pl_udf() ? STANDALONE_FUNCTION : STANDALONE_PROCEDURE; + + OZ (get_names_by_access_ident( + access_ident, access_idxs, database_name, package_name, routine_name)); + + if (access_ident.is_pl_udf()) { + OZ (ObRawExprUtils::rebuild_expr_params(access_ident.udf_info_, &expr_factory_, expr_params), + K(access_ident), K(access_idxs)); + } else { + OZ (access_ident.extract_params(0, expr_params)); + } + + if (database_name.empty() && package_name.empty() && 0 == routine_name.case_compare("RAISE_APPLICATION_ERROR")) { + ObObjAccessIdx access_idx; + if (expr_params.count() != 2 && expr_params.count() != 3) { + ret = OB_ERR_WRONG_TYPE_FOR_VAR; + LOG_WARN("PLS-00306: wrong number or types of arguments in call to 'RAISE_APPLICATION_ERROR'", K(ret));; + LOG_USER_ERROR(OB_ERR_WRONG_TYPE_FOR_VAR, routine_name.length(), routine_name.ptr()); + } else { + ObPLDataType invalid_pl_data_type; + new(&access_idx)ObObjAccessIdx(invalid_pl_data_type, + ObObjAccessIdx::AccessType::IS_SYSTEM_PROC, + routine_name, + invalid_pl_data_type); + OZ (access_idxs.push_back(access_idx)); + } + } else { + + { + ObPLMockSelfArg self(access_idxs, expr_params, expr_factory_); + OZ (self.mock()); + OZ (ns.resolve_routine(resolve_ctx_, + database_name, + package_name, + routine_name, + expr_params, + routine_type, + routine_info)); + } + + if (OB_FAIL(ret) + && OB_ERR_UNEXPECTED != ret + && OB_ERR_SP_WRONG_ARG_NUM != ret + && OB_ERR_CALL_WRONG_ARG != ret + && OB_ERR_FUNC_DUP != ret + && OB_ERR_POSITIONAL_FOLLOW_NAME != ret + && OB_ALLOCATE_MEMORY_FAILED != ret) { + // Not A Routine, try compostie access again. + if (access_idxs.count() > 0 + && (access_idxs.at(access_idxs.count() - 1)).elem_type_.is_composite_type() + && OB_FAIL(resolve_composite_access(access_ident, access_idxs, ns, func))) { + LOG_WARN("failed to access composite access", K(ret), K(access_ident), K(access_idxs)); + } + if (OB_FAIL(ret)) { + LOG_INFO("failed to resolve routine", + K(ret), K(database_name), K(package_name), K(routine_name), K(routine_type), K(access_ident), K(access_idxs)); + ret = OB_ERR_FUNCTION_UNKNOWN; + ObSqlString object_name; + construct_name(database_name, package_name, routine_name, object_name); + LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, + access_ident.is_pl_udf() ? "FUNCTION" : "PROCEDURE", + object_name.string().length(), object_name.string().ptr()); + } + } else { // find A routine, resolve it. + CK (OB_NOT_NULL(routine_info)); + if (OB_FAIL(ret)) { + } else if (OB_NOT_NULL(routine_info->get_ret_info())) { + CK (access_ident.is_pl_udf()); + OZ (resolve_function(access_ident, access_idxs, routine_info, func)); + } else { + OZ (resolve_procedure(access_ident, access_idxs, routine_info, routine_type)); + } + } + } + return ret; +} + + +int ObPLResolver::resolve_function(ObObjAccessIdent &access_ident, + ObIArray &access_idxs, + const ObIRoutineInfo *routine_info, + ObPLCompileUnitAST &func) +{ + int ret = OB_SUCCESS; + + ObPLDataType return_type; + ObObjAccessIdx access_idx; + CK (OB_NOT_NULL(routine_info)); + CK (OB_NOT_NULL(routine_info->get_ret_info())); + if (OB_FAIL(ret)) { + } else if (routine_info->get_ret_info()->is_schema_routine_param()) { + const ObRoutineParam *iparam = static_cast(routine_info->get_ret_info()); + CK (OB_NOT_NULL(iparam)); + OZ (pl::ObPLDataType::transform_from_iparam(iparam, + resolve_ctx_.schema_guard_, + resolve_ctx_.session_info_, + resolve_ctx_.allocator_, + resolve_ctx_.sql_proxy_, + return_type)); + } else { + OX (return_type = routine_info->get_ret_info()->get_pl_data_type()); + } + if (OB_SUCC(ret) + && access_ident.udf_info_.ref_expr_->get_udf_id() == OB_INVALID_ID) { + OZ (get_names_by_access_ident(access_ident, + access_idxs, + access_ident.udf_info_.udf_database_, + access_ident.udf_info_.udf_package_, + access_ident.udf_info_.udf_name_)); + OZ (resolve_udf_info(access_ident.udf_info_, access_idxs, func), K(access_ident)); + if (OB_SUCC(ret) + && access_ident.udf_info_.is_new_keyword_used_ + && !access_ident.udf_info_.is_udf_udt_cons()) { + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("NEW key word is only allowed for constructors", K(ret), K(access_ident)); + } + } + OX (new(&access_idx)ObObjAccessIdx(return_type, + ObObjAccessIdx::AccessType::IS_UDF_NS, + access_ident.udf_info_.udf_name_, + return_type, + reinterpret_cast(access_ident.udf_info_.ref_expr_))); + OZ (access_idxs.push_back(access_idx)); + + if (OB_SUCC(ret) + && access_ident.is_pl_udf() + && access_ident.params_.count() > access_ident.udf_info_.param_exprs_.count()) { + OZ (build_return_access(access_ident, access_idxs, func)); + } + return ret; +} + +int ObPLResolver::resolve_procedure(ObObjAccessIdent &access_ident, + ObIArray &access_idxs, + const ObIRoutineInfo *routine_info, + ObProcType routine_type) +{ + int ret = OB_SUCCESS; + ObObjAccessIdx access_idx; + ObObjAccessIdx::AccessType access_type; + ObPLDataType invalid_type; + switch (routine_type) { + case STANDALONE_PROCEDURE: { + access_type = ObObjAccessIdx::AccessType::IS_EXTERNAL_PROC; + } break; + case NESTED_PROCEDURE: { + access_type = ObObjAccessIdx::AccessType::IS_NESTED_PROC; + } break; + default: { + access_type = ObObjAccessIdx::AccessType::IS_INTERNAL_PROC; + } break; + } + CK (OB_NOT_NULL(routine_info)); + OX (new (&access_idx) ObObjAccessIdx(invalid_type, + access_type, + access_ident.access_name_, + invalid_type, + reinterpret_cast(routine_info))); + OZ (access_idxs.push_back(access_idx)); + return ret; +} + +int ObPLResolver::resolve_construct(ObObjAccessIdent &access_ident, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + uint64_t user_type_id, + ObPLCompileUnitAST &func) +{ + int ret = OB_SUCCESS; + ObQualifiedName q_name; + ObRawExpr* expr = NULL; + const ObUserDefinedType *user_type = NULL; + ObObjAccessIdx access_idx; + OV (access_ident.is_pl_udf(), OB_ERR_UNEXPECTED, K(access_ident)); + OZ (q_name.access_idents_.push_back(access_ident)); + OZ (ns.get_pl_data_type_by_id(user_type_id, user_type)); + CK (OB_NOT_NULL(user_type)); + OZ (get_names_by_access_ident(access_ident, + access_idxs, + access_ident.udf_info_.udf_database_, + access_ident.udf_info_.udf_package_, + access_ident.udf_info_.udf_name_)); + OZ (resolve_construct(q_name, access_ident.udf_info_, *user_type, expr)); + CK (OB_NOT_NULL(expr)); + OZ (func.add_expr(expr)); + OX (new(&access_idx)ObObjAccessIdx(*user_type, + ObObjAccessIdx::AccessType::IS_UDF_NS, + access_ident.access_name_, + *user_type, + reinterpret_cast(expr))); + OZ (access_idxs.push_back(access_idx)); + if (OB_SUCC(ret) + && access_ident.is_pl_udf() + && access_ident.params_.count() > access_ident.udf_info_.param_exprs_.count()) { + OZ (build_return_access(access_ident, access_idxs, func)); + } + return ret; +} + +int ObPLResolver::resolve_self_element_access(ObObjAccessIdent &access_ident, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + ObPLCompileUnitAST &func) +{ + int ret = OB_SUCCESS; + const ObPLBlockNS *udt_routine_ns = ns.get_udt_routine_ns(); + + if (0 == access_idxs.count() // Element Access Without Prefix [SELF.] + && OB_NOT_NULL(udt_routine_ns) // In UDT Routine Namepspace + && OB_NOT_NULL(udt_routine_ns->get_symbol_table()->get_self_param())) { + + ObObjAccessIdx self_access_idx; + ObObjAccessIdx elem_access_idx; + + const ObUserDefinedType *self_user_type = NULL; + const ObPLVar *self_var = udt_routine_ns->get_symbol_table()->get_self_param(); + ObPLDataType self_data_type = self_var->get_type(); + int64_t self_index = udt_routine_ns->get_symbol_table()->get_self_param_idx(); + uint64_t user_type_id = udt_routine_ns->get_package_id(); + + // Construct A Self AccessIdx + new (&self_access_idx) ObObjAccessIdx(self_data_type, + udt_routine_ns == &ns + ? ObObjAccessIdx::AccessType::IS_LOCAL + : ObObjAccessIdx::AccessType::IS_SUBPROGRAM_VAR, + self_var->get_name(), + self_data_type, + self_index); + + if (self_access_idx.is_subprogram_var()) { + ObExprResType *result_type = NULL; + CK (OB_NOT_NULL(udt_routine_ns)); + OZ (convert_pltype_to_restype(expr_factory_.get_allocator(), self_data_type, result_type)); + OX (self_access_idx.var_ns_ = udt_routine_ns); + OZ (ObRawExprUtils::build_get_subprogram_var(expr_factory_, + udt_routine_ns->get_package_id(), + udt_routine_ns->get_routine_id(), + self_index, + result_type, + self_access_idx.get_sysfunc_, + &resolve_ctx_.session_info_)); + } + OZ (ns.get_pl_data_type_by_id(self_data_type.get_user_type_id(), self_user_type)); + CK (OB_NOT_NULL(self_user_type)); + OZ (self_user_type->get_all_depended_user_type(resolve_ctx_, ns)); + + // Resolve Self AccessIdx with AccessIdent + OZ (udt_routine_ns->find_sub_attr_by_name(*self_user_type, + access_ident, + resolve_ctx_.session_info_, + expr_factory_, + func, + elem_access_idx, + self_data_type, + user_type_id, + self_index)); + OZ (access_idxs.push_back(self_access_idx)); + OZ (access_idxs.push_back(elem_access_idx)); + + if (OB_FAIL(ret)) { + } else if (elem_access_idx.elem_type_.is_composite_type() && !access_ident.params_.empty()) { //collection type + OZ (build_collection_access(access_ident, access_idxs, func)); + } else if (elem_access_idx.elem_type_.is_obj_type() && !access_ident.params_.empty()) { + ret = OB_ERR_NO_FUNCTION_EXIST; + LOG_WARN("PLS-00222: no function with name 'string' exists in this scope", K(ret), K(access_ident)); + } + } else { + ret = OB_ERR_SP_UNDECLARED_VAR; + LOG_IN_CHECK_MODE("undeclared var", K(access_ident), K(ret)); + if (lib::is_mysql_mode() || !resolve_ctx_.is_check_mode_) { + LOG_USER_ERROR(OB_ERR_SP_UNDECLARED_VAR, + access_ident.access_name_.length(), access_ident.access_name_.ptr()); + } + } + return ret; +} + +int ObPLResolver::build_access_idx_sys_func(uint64_t parent_id, ObObjAccessIdx &access_idx) +{ + int ret = OB_SUCCESS; + if (access_idx.is_pkg() || access_idx.is_subprogram_var()) { + ObExprResType *result_type = NULL; + OZ (convert_pltype_to_restype(expr_factory_.get_allocator(), access_idx.elem_type_, result_type)); + if (OB_FAIL(ret)) { + } else if (access_idx.is_pkg()) { + OZ (ObRawExprUtils::build_get_package_var(expr_factory_, + resolve_ctx_.schema_guard_, + parent_id, + access_idx.var_index_, + result_type, + access_idx.get_sysfunc_, + &resolve_ctx_.session_info_)); + } else if (access_idx.is_subprogram_var()) { + const ObPLBlockNS *ns = reinterpret_cast(parent_id);; + CK (OB_NOT_NULL(ns)); + OX (access_idx.var_ns_ = ns); + OZ (ObRawExprUtils::build_get_subprogram_var(expr_factory_, + ns->get_package_id(), + ns->get_routine_id(), + access_idx.var_index_, + result_type, + access_idx.get_sysfunc_, + &resolve_ctx_.session_info_)); + } + } else if (access_idx.is_user_var()) { + OZ (ObRawExprUtils::build_get_user_var(expr_factory_, + access_idx.var_name_, + access_idx.get_sysfunc_, + &resolve_ctx_.session_info_), K(access_idx)); + } else if (access_idx.is_session_var()) { + OZ (ObRawExprUtils::build_get_sys_var(expr_factory_, + access_idx.var_name_, + ObObjAccessIdx::IS_GLOBAL == access_idx.access_type_ + ? ObSetVar::SET_SCOPE_GLOBAL : ObSetVar::SET_SCOPE_SESSION, + access_idx.get_sysfunc_, + &resolve_ctx_.session_info_), K(access_idx)); + } + return ret; +} + +int ObPLResolver::build_current_access_idx(uint64_t parent_id, + ObObjAccessIdx &access_idx, + ObObjAccessIdent &access_ident, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + ObPLCompileUnitAST &func) +{ + int ret = OB_SUCCESS; + + OZ (build_access_idx_sys_func(parent_id, access_idx)); + OZ (access_idxs.push_back(access_idx), K(access_idx)); + if (OB_FAIL(ret)) { + } else if (access_idx.elem_type_.is_composite_type() && !access_ident.params_.empty()) { //collection type + OZ (build_collection_access(access_ident, access_idxs, func)); + } else if (access_idx.elem_type_.is_obj_type() && !access_ident.params_.empty()) { + ret = OB_ERR_NO_FUNCTION_EXIST; + LOG_WARN("PLS-00222: no function with name 'string' exists in this scope", + K(ret), K(access_idx.access_type_), K(access_ident)); + } + return ret; +} + +int ObPLResolver::build_collection_index_expr(ObObjAccessIdent &access_ident, + ObObjAccessIdx &access_idx, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + const ObUserDefinedType &user_type, + ObPLCompileUnitAST &func) +{ + int ret = OB_SUCCESS; + if (!access_ident.params_.empty() + && user_type.is_associative_array_type()) { + ObObjAccessIdx index_access_idx; + // associate array 会构造一个额外的表达式。所以调用build函数。例如aa('a'); + // 这里使用一个tmp,而不是传access_idx的原因是, + // build会改变它的类型为IS_EXPR,这里预期需要的类型是IS_PROPERTY, + // 否则的话,objaccess表达式获取的就是expr计算结果,没有collection地址了。 + OZ (build_collection_attribute_access(expr_factory_, + &resolve_ctx_.session_info_, + ns, + func, + user_type, + access_idxs, + OB_INVALID_INDEX, + access_ident.params_.at(0).first, // parameter level + index_access_idx)); + if (OB_SUCC(ret)) { + ObPLAssocIndexRawExpr *index_expr = static_cast(index_access_idx.get_sysfunc_); + CK (OB_NOT_NULL(index_expr)); + OX (index_expr->set_out_of_range_set_err(false)); + OX (access_idx.get_sysfunc_ = index_access_idx.get_sysfunc_); + if (OB_FAIL(ret)) { + } else if (0 == access_idx.var_name_.case_compare("PRIOR")) { + index_expr->set_parent_type(parent_expr_type::EXPR_PRIOR); + } else if (0 == access_idx.var_name_.case_compare("NEXT")) { + index_expr->set_parent_type(parent_expr_type::EXPR_NEXT); + } else if (0 == access_idx.var_name_.case_compare("EXISTS")) { + index_expr->set_parent_type(parent_expr_type::EXPR_EXISTS); + } else { + index_expr->set_parent_type(parent_expr_type::EXPR_UNKNOWN); + } + } + } else { + // 这里暂时不调用build,因为a(1)这种会被build优化掉, + // 没有param,get_attr的时候直接拿这个常量值,不符合next,prior的预期 + for (int64_t i = 0; OB_SUCC(ret) && i < access_idx.type_method_params_.count(); ++i) { + uint64_t expr_idx = access_idx.type_method_params_.at(i); + OV (expr_idx >= 0 && expr_idx < func.get_exprs().count(), + OB_ERR_UNEXPECTED, K(expr_idx), K(func.get_exprs().count())); + OX (access_idx.get_sysfunc_ = func.get_expr(expr_idx)); + } + } + return ret; +} + + +int ObPLResolver::resolve_composite_access(ObObjAccessIdent &access_ident, + ObIArray &access_idxs, + const ObPLBlockNS &ns, + ObPLCompileUnitAST &func) +{ + int ret = OB_SUCCESS; + + const ObPLDataType &parent_type = access_idxs.at(access_idxs.count() - 1).elem_type_; + const ObUserDefinedType *user_type = NULL; + ObObjAccessIdx access_idx; + ObPLDataType pl_data_type; + uint64_t parent_id; + int64_t var_index; + + if (!parent_type.is_composite_type()) { + ret = OB_ERR_OUT_OF_SCOPE; + LOG_WARN("PLS-00225: subprogram or cursor reference is out of scope", K(ret), K(parent_type), K(access_ident)); + } + + OZ (ns.get_pl_data_type_by_id(parent_type.get_user_type_id(), user_type)); + CK (OB_NOT_NULL(user_type)); + OZ (user_type->get_all_depended_user_type(resolve_ctx_, ns)); + + if (OB_FAIL(ret)) { + } else if (access_ident.access_name_.empty()) { // no element name, must be collection access. + OV (!access_ident.params_.empty(), OB_ERR_UNEXPECTED, K(access_ident), K(access_idxs)); + OZ (build_collection_access(access_ident, access_idxs, func)); + } else { // record element access + OZ (ns.find_sub_attr_by_name(*user_type, + access_ident, + resolve_ctx_.session_info_, + expr_factory_, + func, + access_idx, + pl_data_type, + parent_id, + var_index)); + + OZ (build_access_idx_sys_func(parent_id, access_idx)); + + if (OB_FAIL(ret)) { + } else if (0 == access_idx.var_name_.case_compare("NEXT") + || 0 == access_idx.var_name_.case_compare("PRIOR") + || 0 == access_idx.var_name_.case_compare("EXISTS")) { + + CK (access_idx.type_method_params_.count() <= 1); // parameter count must be 0 or 1 + + OZ (build_collection_index_expr(access_ident, access_idx, ns, access_idxs, *user_type, func)); + } + + OZ (access_idxs.push_back(access_idx)); + + if (OB_SUCC(ret) + && !access_idx.is_property() + && !access_idx.is_type_method() + && !access_ident.params_.empty()) { + // second level collection access. "X(1)(2)", here continue resolve "(2)" + OZ (build_collection_access(access_ident, access_idxs, func)); + } + } + return ret; +} + + int ObPLResolver::resolve_access_ident(ObObjAccessIdent &access_ident, // 当前正在resolve的ident const ObPLBlockNS &ns, ObRawExprFactory &expr_factory, const ObSQLSessionInfo *session_info, ObIArray &access_idxs, // 已经resolve过的ident信息, 作为当前ident的父节点 ObPLCompileUnitAST &func, - bool is_proc, + bool is_routine, bool is_resolve_rowtype) { int ret = OB_SUCCESS; @@ -11613,54 +12059,27 @@ int ObPLResolver::resolve_access_ident(ObObjAccessIdent &access_ident, // 当前 ObPLExternalNS::ExternalType type = static_cast(access_ident.access_index_); ObPLDataType pl_data_type; int64_t cnt = access_idxs.count(); - uint64_t udt_type_id = OB_INVALID_ID; - // obj.xxx -> accessidx.var_name_ = 'obj', after check udt routine, if success - // it will become -> accessidx.var_name_ = 'demo_typ2', which demo_typ2 is type name - // we have to record this var name for the udt udf's self argument - // that's rewrite obj.routine(a) to obj.routine(obj, a); - ObString udt_var_name; - if (0 < cnt) { - bool is_udt_routine = false; - ObString udt_type_name; - // udt object类型,这儿需要检查obj.xxx的xxx是属性还是函数,这儿如果是函数需要重置父节点access idx的类型 - // 这是因为 obj.attr 和 obj.routine,obj首先是按照pL_var解析的,如果是后者,需要变化为UDT_NS - // 否者obj.routine就会解析成一个属性。预期是解析成一个udf. - if (OB_FAIL(check_is_udt_routine(access_ident, ns, access_idxs, - access_idx, udt_type_name, - udt_type_id, is_udt_routine))) { - LOG_DEBUG("check is udt rotine failed", K(ret)); - if (OB_ERR_NO_PROGRAM_UNIT != ret) { - ret = OB_SUCCESS; //这儿只是尝试,不成功重置错误码 - } - } else if (is_udt_routine && OB_INVALID_ID != udt_type_id) { - ObObjAccessIdx &pre_idx = access_idxs.at(cnt - 1); - OZ (ob_write_string(resolve_ctx_.allocator_, pre_idx.var_name_, udt_var_name)); - // 重置父节点的类型,从pl_var到udt_ns - new(&pre_idx)ObObjAccessIdx(pl_data_type, - static_cast(ObPLExternalNS::UDT_NS), - udt_type_name, pl_data_type, udt_type_id); - } + + if (!is_routine) { + OZ (check_is_udt_routine(access_ident, ns, access_idxs, is_routine)); } - // 这个if对root节点或者前n-1层节点进行resolve, else里面对第n层进行resolve,即最终的那个变量值或者函数名。 - if (0 == cnt // 当前为根节点 - || ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt - 1).access_type_ // 父节点是DB Name - || ObObjAccessIdx::IS_PKG_NS == access_idxs.at(cnt - 1).access_type_ // 父节点是Package Name - || ObObjAccessIdx::IS_TABLE_NS == access_idxs.at(cnt - 1).access_type_// 父节点是Table Name + if (0 == cnt + || ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt - 1).access_type_ + || ObObjAccessIdx::IS_PKG_NS == access_idxs.at(cnt - 1).access_type_ + || ObObjAccessIdx::IS_TABLE_NS == access_idxs.at(cnt - 1).access_type_ || ObObjAccessIdx::IS_LABEL_NS == access_idxs.at(cnt - 1).access_type_ - || ObObjAccessIdx::IS_UDT_NS == access_idxs.at(cnt-1).access_type_) { + || ObObjAccessIdx::IS_UDT_NS == access_idxs.at(cnt - 1).access_type_ + || is_routine) { bool label_symbol = false; - bool udt_routine = false; if (cnt != 0) { if (ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt - 1).access_type_) { type = ObPLExternalNS::INVALID_VAR; // 父节点是DB Name, 子节点可能是Package Name或者Table Name - } else if (ObObjAccessIdx::IS_PKG_NS == access_idxs.at(cnt - 1).access_type_ && !is_proc) { + } else if (ObObjAccessIdx::IS_PKG_NS == access_idxs.at(cnt - 1).access_type_) { type = ObPLExternalNS::PKG_VAR; // 父节点是PackageName, 子节点尝试解析为Package Var - } else if (ObObjAccessIdx::IS_TABLE_NS == access_idxs.at(cnt - 1).access_type_ && !is_proc) { + } else if (ObObjAccessIdx::IS_TABLE_NS == access_idxs.at(cnt - 1).access_type_ && !is_routine) { type = ObPLExternalNS::TABLE_COL; // 父节点是TableName, 子节点尝试解析为ColumnName } else if (ObObjAccessIdx::IS_LABEL_NS == access_idxs.at(cnt - 1).access_type_) { label_symbol = true; - } else if (ObObjAccessIdx::IS_UDT_NS == access_idxs.at(cnt - 1).access_type_) { - udt_routine = true; //obj.routine,包括了static和member,member在check_is_udt_routine进行了转换 } if (!label_symbol) { parent_id = access_idxs.at(cnt - 1).var_index_; @@ -11676,9 +12095,7 @@ int ObPLResolver::resolve_access_ident(ObObjAccessIdent &access_ident, // 当前 ObPLExternalNS::ExternalType::SUBPROGRAM_VAR == type ? reinterpret_cast(access_idxs.at(cnt - 1).label_ns_) : access_idxs.at(cnt - 1).label_ns_->get_package_id()); - } else if (udt_routine) { - const_cast(access_ident).udf_info_.is_udt_udf_ = true; - } else if (!is_proc) { + } else { if (access_ident.is_pl_var() && access_ident.access_name_.empty()) { // questionmark variable const ObPLSymbolTable *sym_tbl = ns.get_symbol_table(); int64_t var_idx = access_ident.access_index_; @@ -11702,460 +12119,50 @@ int ObPLResolver::resolve_access_ident(ObObjAccessIdent &access_ident, // 当前 const ObPLVar *var = sym_table.get_symbol(var_index); if (OB_NOT_NULL(var) && var->is_formal_param()) { ret = OB_ERR_TYPE_DECL_ILLEGAL; - LOG_WARN("row type illegal, should not be formal parameter", K(ret), - KPC(var), - K(access_ident), - K(var_index)); - LOG_USER_ERROR(OB_ERR_TYPE_DECL_ILLEGAL, - access_ident.access_name_.length(), - access_ident.access_name_.ptr()); + LOG_WARN("row type illegal, should not be formal parameter", K(ret), KPC(var), K(access_ident), K(var_index)); + LOG_USER_ERROR(OB_ERR_TYPE_DECL_ILLEGAL, access_ident.access_name_.length(), access_ident.access_name_.ptr()); } } } - if (OB_FAIL(ret)) { - } else if (ObPLExternalNS::INVALID_VAR == type - || (ObPLExternalNS::TABLE_NS == type && is_proc) - || (ObPLExternalNS::LABEL_NS == type && is_proc) - || (ObPLExternalNS::DB_NS == type && is_proc)) { - if (lib::is_oracle_mode() && is_proc) { - //may be a procedure - ObString db_name; - ObString pkg_name; - ObString proc_name = access_ident.access_name_; - const ObIRoutineInfo *routine_info = NULL; - ObProcType routine_type - = access_ident.is_pl_udf() ? STANDALONE_FUNCTION : STANDALONE_PROCEDURE; - if (cnt > 2) { - // todo: db.pkg.obj.proc(); - } else if (cnt > 1) { - if (ObObjAccessIdx::IS_PKG_NS == access_idxs.at(cnt-1).access_type_) { - pkg_name = access_idxs.at(cnt-1).var_name_; - if (ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt-2).access_type_) { - db_name = access_idxs.at(cnt-2).var_name_; - } - } else if (ObObjAccessIdx::IS_UDT_NS == access_idxs.at(cnt-1).access_type_) { - pkg_name = access_idxs.at(cnt-1).var_name_; - if (ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt-2).access_type_) { - db_name = access_idxs.at(cnt-2).var_name_; - } else { - OZ (get_udt_database_name(resolve_ctx_.schema_guard_, access_idxs.at(cnt-1).var_index_, db_name)); - } - } else if (ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt-1).access_type_) { - db_name = access_idxs.at(cnt-1).var_name_; - } - } else if (cnt > 0) { - if (ObObjAccessIdx::IS_PKG_NS == access_idxs.at(cnt-1).access_type_) { - pkg_name = access_idxs.at(cnt-1).var_name_; - } else if (ObObjAccessIdx::IS_UDT_NS == access_idxs.at(cnt-1).access_type_) { - pkg_name = access_idxs.at(cnt-1).var_name_; - OZ (get_udt_database_name(resolve_ctx_.schema_guard_, access_idxs.at(cnt-1).var_index_, db_name)); - } else if (ObObjAccessIdx::IS_DB_NS == access_idxs.at(cnt-1).access_type_) { - db_name = access_idxs.at(cnt-1).var_name_; - } - } else {} - if (OB_SUCC(ret)) { - // Check RAISE_APPLICATION_ERROR - common::ObArray expr_params; - ObObjAccessIdx::AccessType proc_type = ObObjAccessIdx::AccessType::IS_INVALID; - if (OB_FAIL(access_ident.extract_params(0, expr_params))) { - LOG_WARN("extract params failed", K(db_name), K(pkg_name), K(proc_name), K(ret)); - } else if (db_name.empty() && pkg_name.empty() - && 0 == proc_name.case_compare("RAISE_APPLICATION_ERROR")) { - if (expr_params.count() != 2 && expr_params.count() != 3) { - ret = OB_ERR_WRONG_TYPE_FOR_VAR; - LOG_WARN("PLS-00306: wrong number or types of arguments in call to 'RAISE_APPLICATION_ERROR'", K(ret));; - LOG_USER_ERROR(OB_ERR_WRONG_TYPE_FOR_VAR, proc_name.length(), proc_name.ptr()); - } else { - ObPLDataType invalid_pl_data_type; - proc_type = ObObjAccessIdx::AccessType::IS_SYSTEM_PROC; - new(&access_idx)ObObjAccessIdx(invalid_pl_data_type, - proc_type, proc_name, - invalid_pl_data_type, - reinterpret_cast(routine_info)); - if (OB_FAIL(access_idxs.push_back(access_idx))) { - LOG_WARN("push_back error", K(ret), K(access_idx), K(proc_type), K(proc_name)); - } - } - } else if (OB_FAIL(ns.resolve_routine(resolve_ctx_, - db_name, - pkg_name, - proc_name, - expr_params, - routine_type, - routine_info))) { - LOG_WARN("resolve routine failed", K(db_name), K(pkg_name), K(proc_name), K(ret)); - if (OB_ERR_UNEXPECTED != ret - && OB_ERR_SP_WRONG_ARG_NUM != ret - && OB_ERR_CALL_WRONG_ARG != ret - && OB_ERR_FUNC_DUP != ret - && OB_ERR_POSITIONAL_FOLLOW_NAME != ret - && OB_ALLOCATE_MEMORY_FAILED != ret) { - ret = OB_ERR_SP_DOES_NOT_EXIST; - if (pkg_name.empty()) { - db_name = db_name.empty() ? OB_NOT_NULL(session_info) ? session_info->get_database_name() : db_name : db_name; - LOG_USER_ERROR(OB_ERR_SP_DOES_NOT_EXIST, "PROCEDURE", - db_name.length(), db_name.ptr(), - proc_name.length(), proc_name.ptr()); - } else { - LOG_USER_ERROR(OB_ERR_SP_DOES_NOT_EXIST, "PROCEDURE", - pkg_name.length(), pkg_name.ptr(), - proc_name.length(), proc_name.ptr()); - } - } - } else { - ObPLDataType proc_pl_data_type; - if (STANDALONE_FUNCTION == routine_type - || PACKAGE_FUNCTION == routine_type - || NESTED_FUNCTION == routine_type) { - CK (OB_NOT_NULL(routine_info), OB_NOT_NULL(routine_info->get_ret_info())); - proc_type = ObObjAccessIdx::AccessType::IS_UDF_NS; - if (routine_info->get_ret_info()->is_schema_routine_param()) { - const ObRoutineParam *iparam - = static_cast(routine_info->get_ret_info()); - CK (OB_NOT_NULL(iparam)); - OZ (pl::ObPLDataType::transform_from_iparam(iparam, - resolve_ctx_.schema_guard_, - resolve_ctx_.session_info_, - resolve_ctx_.allocator_, - resolve_ctx_.sql_proxy_, - proc_pl_data_type)); - } else { - OX (proc_pl_data_type = routine_info->get_ret_info()->get_pl_data_type()); - } - ObArray access_name; - OZ (access_name.push_back(udt_var_name)); - OZ (resolve_udf(access_ident.udf_info_, access_name, func), access_ident); - } else { - if (STANDALONE_PROCEDURE == routine_type) { - proc_type = ObObjAccessIdx::AccessType::IS_EXTERNAL_PROC; - } else if (NESTED_PROCEDURE == routine_type) { - proc_type = ObObjAccessIdx::AccessType::IS_NESTED_PROC; - } else { - proc_type = ObObjAccessIdx::AccessType::IS_INTERNAL_PROC; - } - } - if (OB_SUCC(ret)) { - int64_t access_value = access_ident.is_pl_udf() - ? reinterpret_cast(access_ident.udf_info_.ref_expr_) - : reinterpret_cast(routine_info); - /* - * member function ff(a) return number is - * begin - * ffff(1); - * return 1; - * end; - * - * suppose ffff is a static procedure of a object, it will cause a compile error; - * but : object_type.ffff(1) will not. oracle seems use return self.ffff(1) to resolve - * the procedure without prefix, if not success, just report error, it will not try to - * resolve it as a static procedure. Ob has to follow this rule - * function is also same rule, see the resolve_obj_acess. - * self_var is not null, indicate parent function is a member routine - */ - new(&access_idx)ObObjAccessIdx(proc_pl_data_type, proc_type, proc_name, - proc_pl_data_type, access_value); - if (OB_FAIL(ret)) { - // do nothing - } else if (OB_FAIL(access_idxs.push_back(access_idx))) { - LOG_WARN("push_back error", K(ret)); - } else if (OB_INVALID_ID != udt_type_id && routine_info->is_udt_routine()) { - // 这儿是为udt member procedure的self 参数准备的。 - ObObjAccessIdent &access_ident_udt_p = const_cast(access_ident); - // 借用udf_info的标记位,在resolve_inner call的时候,会使用这个标记位来确认是否需要增加一个self参数 - access_ident_udt_p.udf_info_.is_udt_udf_ = true; - // udt_type_id不为invalid,说明这个调用方式是实例调用,如obj.procedure, - // 其中obj是一个object类型变量,而不是类型调用.如果这个procedure是static,则需要报错 - // 处理类似 obj.routine, cnt > 0的情况 - if (routine_info->is_udt_static_routine()) { - // access_ident_udt_p.udf_info_.set_is_udf_udt_static(); - ret = OB_ERR_INVOKE_STATIC_BY_INSTANCE; - LOG_WARN("invoke static udt function with instance", K(udt_type_id), K(ret)); - LOG_USER_ERROR(OB_ERR_INVOKE_STATIC_BY_INSTANCE); - } - } - } - /* - * 如果有下一level的参数,需要进一步解析 - * */ - if (OB_SUCC(ret) && access_ident.is_pl_udf() - && access_ident.params_.count() > access_ident.udf_info_.param_exprs_.count()) { - OZ (build_return_access(access_ident, access_idxs, func)); - } - } - } - } else { - // 解析udt udf函数中的引用自身变量, 到这儿说明找不到local的,否则在上面的resolve_symbol就解决了。 - bool resolve_self_flag = false; - const ObPLBlockNS *udt_routine_ns = ns.get_udt_routine_ns(); - if (cnt == 0 && OB_NOT_NULL(udt_routine_ns)) { - // 构造的self参数,它是一个record - const ObPLVar *self_var = udt_routine_ns->get_symbol_table()->get_self_param(); - if (OB_NOT_NULL(self_var)) { - type = (udt_routine_ns == &ns) ? ObPLExternalNS::LOCAL_VAR : ObPLExternalNS::SUBPROGRAM_VAR; - var_index = udt_routine_ns->get_symbol_table()->get_self_param_idx(); - pl_data_type = self_var->get_type(); - parent_id = udt_routine_ns->get_package_id(); - ObObjAccessIdx parent_idx; - new(&parent_idx)ObObjAccessIdx(pl_data_type, - static_cast(type), - self_var->get_name(), - pl_data_type, - var_index); - const ObUserDefinedType *user_type = NULL; - if (parent_idx.is_subprogram_var()) { - ObExprResType *result_type = NULL; - CK (OB_NOT_NULL(udt_routine_ns)); - OZ (convert_pltype_to_restype(expr_factory.get_allocator(), pl_data_type, result_type)); - OX (parent_idx.var_ns_ = udt_routine_ns); - OZ (ObRawExprUtils::build_get_subprogram_var(expr_factory, - udt_routine_ns->get_package_id(), - udt_routine_ns->get_routine_id(), - var_index, - result_type, - parent_idx.get_sysfunc_, - session_info), K(ns), K(var_index)); - } - OZ (ns.get_pl_data_type_by_id(pl_data_type.get_user_type_id(), user_type)); - CK (OB_NOT_NULL(user_type)); - OZ (user_type->get_all_depended_user_type(resolve_ctx_, ns)); - OZ (udt_routine_ns->find_sub_attr_by_name(*user_type, - access_ident, - resolve_ctx_.session_info_, - expr_factory_, - func, - access_idx, - pl_data_type, - parent_id, - var_index)); - OZ (access_idxs.push_back(parent_idx)); - OZ (access_idxs.push_back(access_idx)); - OX (resolve_self_flag = true); - if (OB_SUCC(ret)) { - const ObPLDataType &access_type = access_idx.elem_type_; - if (access_type.is_composite_type() && !access_ident.params_.empty()) { //collection type - OZ (build_collection_access(access_ident, access_idxs, func)); - } else if (access_type.is_obj_type() && !access_ident.params_.empty()) { - ret = OB_ERR_NO_FUNCTION_EXIST; - LOG_WARN("PLS-00222: no function with name 'string' exists in this scope", - K(ret), K(access_type), K(access_ident)); - } - } - } - } - if (!resolve_self_flag) { - ret = OB_ERR_SP_UNDECLARED_VAR; - LOG_IN_CHECK_MODE("undeclared var", K(access_ident), K(ret)); - if (lib::is_mysql_mode() || !resolve_ctx_.is_check_mode_) { - LOG_USER_ERROR(OB_ERR_SP_UNDECLARED_VAR, - access_ident.access_name_.length(), access_ident.access_name_.ptr()); - } - } + if (OB_FAIL(ret)) { + } else if ((ObPLExternalNS::LOCAL_TYPE == type && is_routine) + || (ObPLExternalNS::PKG_TYPE == type && is_routine) + || (ObPLExternalNS::UDT_NS == type && is_routine)) { + OZ (resolve_construct(access_ident, ns, access_idxs, var_index, func)); + } else if (ObPLExternalNS::INVALID_VAR == type + || (ObPLExternalNS::LOCAL_VAR == type && is_routine) + || (ObPLExternalNS::TABLE_NS == type && is_routine) + || (ObPLExternalNS::LABEL_NS == type && is_routine) + || (ObPLExternalNS::DB_NS == type && is_routine)) { + if (is_routine) { + OZ (resolve_routine(access_ident, ns, access_idxs, func), + K(access_ident), K(access_idxs)); + } else { // [self.]element, user can access element without self prefix, handle it in here. + OZ (resolve_self_element_access(access_ident, ns, access_idxs, func), + K(access_ident), K(access_idxs)); } - } else { + } else { // current symbol resolve success! + ObObjAccessIdx access_idx; new(&access_idx)ObObjAccessIdx(pl_data_type, - static_cast(type), - access_ident.access_name_, - pl_data_type, - var_index); - if (access_idx.is_pkg() || access_idx.is_subprogram_var()) { - ObExprResType *result_type = NULL; - OZ (convert_pltype_to_restype(expr_factory.get_allocator(), pl_data_type, result_type)); - if (OB_FAIL(ret)) { - } else if (access_idx.is_pkg()) { - OZ (ObRawExprUtils::build_get_package_var(expr_factory, - resolve_ctx_.schema_guard_, - parent_id, - var_index, - result_type, - access_idx.get_sysfunc_, - session_info), parent_id, var_index); - } else if (access_idx.is_subprogram_var()) { - const ObPLBlockNS *ns = reinterpret_cast(parent_id); - CK (OB_NOT_NULL(ns)); - OX (access_idx.var_ns_ = ns); - OZ (ObRawExprUtils::build_get_subprogram_var(expr_factory, - ns->get_package_id(), - ns->get_routine_id(), - var_index, - result_type, - access_idx.get_sysfunc_, - session_info), K(ns), K(var_index)); - } - } else if (access_idx.is_user_var()) { - if (OB_FAIL(ObRawExprUtils::build_get_user_var(expr_factory, access_idx.var_name_, access_idx.get_sysfunc_, session_info))) { - LOG_WARN("Failed to build get user var", K(access_idx), K(ret)); - } - } else if (access_idx.is_session_var()) { - ObSetVar::SetScopeType scope = ObObjAccessIdx::IS_GLOBAL == access_idx.access_type_ ? ObSetVar::SET_SCOPE_GLOBAL : ObSetVar::SET_SCOPE_SESSION; - if (OB_FAIL(ObRawExprUtils::build_get_sys_var(expr_factory, access_idx.var_name_, scope, access_idx.get_sysfunc_, session_info))) { - LOG_WARN("Failed to build get sys var", K(access_idx), K(ret)); - } - } else {} - if (OB_SUCC(ret)) { - if (OB_FAIL(access_idxs.push_back(access_idx))) { - LOG_WARN("push_back error", K(ret)); - } else if (lib::is_oracle_mode()) { - const ObPLDataType &access_type = access_idx.elem_type_; - if (access_type.is_composite_type() && !access_ident.params_.empty()) { //collection type - OZ (build_collection_access(access_ident, access_idxs, func)); - } else if (access_type.is_obj_type() && !access_ident.params_.empty()) { - ret = OB_ERR_NO_FUNCTION_EXIST; - LOG_WARN("PLS-00222: no function with name 'string' exists in this scope", - K(ret), K(access_type), K(access_ident)); - } - } + static_cast(type), + access_ident.access_name_, + pl_data_type, + var_index); + OZ (build_access_idx_sys_func(parent_id, access_idx)); + OZ (access_idxs.push_back(access_idx), K(access_idx)); + if (OB_FAIL(ret)) { + } else if (access_idx.elem_type_.is_composite_type() && !access_ident.params_.empty()) { //collection type + OZ (build_collection_access(access_ident, access_idxs, func)); + } else if (access_idx.elem_type_.is_obj_type() && !access_ident.params_.empty()) { + ret = OB_ERR_NO_FUNCTION_EXIST; + LOG_WARN("PLS-00222: no function with name 'string' exists in this scope", + K(ret), K(access_idx.access_type_), K(access_ident)); } } } else { - const ObPLDataType &parent_type = access_idxs.at(cnt-1).elem_type_; - if (!parent_type.is_composite_type()) { - ret = OB_ERR_OUT_OF_SCOPE; - LOG_WARN("PLS-00225: subprogram or cursor reference is out of scope", - K(ret), K(parent_type)); - } else { - const ObUserDefinedType *user_type = NULL; - if (OB_FAIL(ns.get_pl_data_type_by_id(parent_type.get_user_type_id(), user_type))) { - LOG_WARN("get user type by id failed", K(ret)); - } else if (OB_ISNULL(user_type)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("user type is NULL", K(ret)); - } else if (OB_FAIL(user_type->get_all_depended_user_type(resolve_ctx_, ns))) { - LOG_WARN("get all depended user type failed", K(ret)); - } else { - if (!access_ident.access_name_.empty()) { - if (OB_FAIL(ns.find_sub_attr_by_name( - *user_type, - access_ident, - resolve_ctx_.session_info_, - expr_factory, - func, - access_idx, - pl_data_type, - parent_id, - var_index))) { - LOG_WARN("find sub attr by name failed", K(access_ident.access_name_), K(ret)); - } else if (access_idx.is_pkg()) { - common::ObIAllocator &alloc = expr_factory.get_allocator(); - ObExprResType *result_type = static_cast(alloc.alloc(sizeof(ObExprResType))); - const ObDataType *data_type = pl_data_type.get_data_type(); - if (OB_ISNULL(result_type)) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("allocate memory failed", K(ret)); - } else { - new (result_type) ObExprResType(alloc); - if (OB_ISNULL(data_type)) { - result_type->set_ext(); - } else { - result_type->set_type(data_type->get_obj_type()); - if (ob_is_string_tc(result_type->get_type()) || ob_is_raw_tc(result_type->get_type())) { - result_type->set_length(data_type->get_length()); - result_type->set_length_semantics(data_type->get_length_semantics()); - result_type->set_collation_type(data_type->get_collation_type()); - result_type->set_collation_level(data_type->get_collation_level()); - } else if (ob_is_number_tc(result_type->get_type())) { - result_type->set_precision(data_type->get_precision()); - result_type->set_scale(data_type->get_scale()); - } else {} - } - CK (parent_id != OB_INVALID_ID); - OZ (ObRawExprUtils::build_get_package_var(expr_factory, - resolve_ctx_.schema_guard_, - parent_id, - var_index, - result_type, - access_idx.get_sysfunc_, - session_info), K(parent_id), K(var_index)); - } - } else if (access_idx.is_user_var()) { - if (OB_FAIL(ObRawExprUtils::build_get_user_var(expr_factory, access_idx.var_name_, access_idx.get_sysfunc_, session_info))) { - LOG_WARN("Failed to build get user var", K(access_idx), K(ret)); - } - } else if (access_idx.is_session_var()) { - ObSetVar::SetScopeType scope = ObObjAccessIdx::IS_GLOBAL == access_idx.access_type_ ? ObSetVar::SET_SCOPE_GLOBAL : ObSetVar::SET_SCOPE_SESSION; - if (OB_FAIL(ObRawExprUtils::build_get_sys_var(expr_factory, access_idx.var_name_, scope, access_idx.get_sysfunc_, session_info))) { - LOG_WARN("Failed to build get sys var", K(access_idx), K(ret)); - } - } else { - // prior and next have param, build it - if (0 == access_idx.var_name_.case_compare("next") - || 0 == access_idx.var_name_.case_compare("prior") - || 0 == access_idx.var_name_.case_compare("exists")) { - int64_t param_expr_idx = -1; - CK (1 >= access_idx.type_method_params_.count()); - // associate array 会构造一个额外的表达式。所以调用build函数。例如aa('a'); - if (OB_FAIL(ret)) { - } else if (!access_ident.params_.empty() - && user_type->is_associative_array_type()) { - ObObjAccessIdx tmp_acc_idx; - // 这里使用一个tmp,而不是传access_idx的原因是, - // build会改变它的类型为IS_EXPR,这里预期需要的类型是IS_PROPERTY, - // 否则的话,objaccess表达式获取的就是expr计算结果,没有collection地址了。 - if (OB_FAIL(build_collection_attribute_access(expr_factory, - session_info, - ns, - func, - *user_type, - access_idxs, - OB_INVALID_INDEX, - access_ident.params_.at(0).first, - tmp_acc_idx))) { - LOG_WARN("find sub attr by index failed", K(ret)); - } else { - // 这个PL_ASSOCIATE_INDEX 表达式被放在了get_sysfunc_里面了。 - ObPLAssocIndexRawExpr *pi_expr - = static_cast(tmp_acc_idx.get_sysfunc_); - if (OB_ISNULL(pi_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("got null pl associative index expr", K(ret)); - } else { - pi_expr->set_out_of_range_set_err(false); - int64_t type = -1; - if (0 == access_idx.var_name_.case_compare("prior")) { - type = 0; - } else if (0 == access_idx.var_name_.case_compare("next")) { - type = 1; - } else if (0 == access_idx.var_name_.case_compare("exists")) { - type = 2; - } - pi_expr->set_parent_type(static_cast(type)); - access_idx.get_sysfunc_ = tmp_acc_idx.get_sysfunc_; - } - } - } else { - // 这里暂时不调用build,因为a(1)这种会被build优化掉, - // 没有param,get_attr的时候直接拿这个常量值,不符合next,prior的预期 - for (int64_t i = 0; - OB_SUCC(ret) && i < access_idx.type_method_params_.count(); ++i) { - param_expr_idx = access_idx.type_method_params_.at(i); - if (param_expr_idx >= 0 && param_expr_idx < func.get_exprs().count()) { - // get_sysfunc_在后续的add_access_idx的时候,会将它当作一个param expr加入到计算表达式堆栈中 - access_idx.get_sysfunc_ = func.get_expr(param_expr_idx); - } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to get property param expr", K(param_expr_idx), - K(func.get_exprs().count())); - } - } - } - } - } - if (OB_SUCC(ret)) { - if (OB_FAIL(access_idxs.push_back(access_idx))) { - LOG_WARN("push_back error", K(ret)); - } else if (!access_idx.is_property() - && !access_idx.is_type_method() - && !access_ident.params_.empty()) { - OZ (build_collection_access(access_ident, access_idxs, func)); - } - } - } else { - OV (!access_ident.params_.empty(), - OB_ERR_UNEXPECTED, K(access_ident), K(access_idxs)); - OZ (build_collection_access(access_ident, access_idxs, func)); - } - } - } + // not top node and parent not a namespace, it must be composite access. handle it here. + OZ (resolve_composite_access(access_ident, access_idxs, ns, func)); } CANCLE_LOG_CHECK_MODE(); @@ -15070,6 +15077,27 @@ int ObPLResolver::resolve_do(const ObStmtNodeTree *parse_tree, ObPLDoStmt *stmt, return ret; } +int ObPLResolver::get_udt_names( + ObSchemaGetterGuard &schema_guard, const uint64_t udt_id, ObString &database_name, ObString &udt_name) +{ + int ret = OB_SUCCESS; + if (OB_INVALID_ID != udt_id) { + uint64_t db_id = OB_INVALID_ID; + const ObUDTTypeInfo *udt_info = NULL; + const ObSimpleDatabaseSchema *db_schema = NULL; + const uint64_t tenant_id = get_tenant_id_by_object_id(udt_id); + OZ (schema_guard.get_udt_info(tenant_id, udt_id, udt_info)); + CK (OB_NOT_NULL(udt_info)); + OX (db_id = udt_info->get_database_id()); + CK (OB_INVALID_ID != db_id); + OZ (schema_guard.get_database_schema(tenant_id, db_id, db_schema)); + CK (OB_NOT_NULL(db_schema)); + OX (database_name = db_schema->get_database_name_str()); + OX (udt_name = udt_info->get_type_name()); + } + return ret; +} + int ObPLResolver::get_udt_database_name(ObSchemaGetterGuard &schema_guard, const uint64_t udt_id, ObString &db_name) { int ret = OB_SUCCESS; diff --git a/src/pl/ob_pl_resolver.h b/src/pl/ob_pl_resolver.h index 620c14bb5..67b355051 100644 --- a/src/pl/ob_pl_resolver.h +++ b/src/pl/ob_pl_resolver.h @@ -116,6 +116,26 @@ public: bool is_sync_package_var_; }; +class ObPLMockSelfArg +{ +public: + ObPLMockSelfArg( + const ObIArray &access_idxs, ObSEArray &expr_params, ObRawExprFactory &expr_factory) + : access_idxs_(access_idxs), + expr_params_(expr_params), + expr_factory_(expr_factory), + mark_only_(false), + mocked_(false) {} + int mock(); + ~ObPLMockSelfArg(); +private: + const ObIArray &access_idxs_; + ObSEArray &expr_params_; + ObRawExprFactory &expr_factory_; + bool mark_only_; + bool mocked_; +}; + class ObPLPackageAST; class ObPLResolver { @@ -304,6 +324,10 @@ public: int resolve_sqlcode_or_sqlerrm(sql::ObQualifiedName &q_name, ObPLCompileUnitAST &unit_ast, sql::ObRawExpr *&expr); + int resolve_construct(const ObQualifiedName &q_name, + const ObUDFInfo &udf_info, + const ObUserDefinedType &user_type, + ObRawExpr *&expr); int resolve_construct(const sql::ObQualifiedName &q_name, const sql::ObUDFInfo &udf_info, ObRawExpr *&expr); @@ -506,6 +530,11 @@ public: int check_static_bool_expr(const ObRawExpr *expr, bool &is_static_bool_expr); static int adjust_routine_param_type(ObPLDataType &type); + + int resolve_udf_info( + sql::ObUDFInfo &udf_info, ObIArray &access_idxs, ObPLCompileUnitAST &func); + + int construct_name(ObString &database_name, ObString &package_name, ObString &routine_name, ObSqlString &object_name); private: int resolve_declare_var(const ObStmtNodeTree *parse_tree, ObPLDeclareVarStmt *stmt, ObPLFunctionAST &func_ast); int resolve_declare_var(const ObStmtNodeTree *parse_tree, ObPLPackageAST &package_ast); @@ -624,9 +653,12 @@ private: sql::ObRawExpr *&expr, bool for_write = false); int resolve_udf_without_brackets(sql::ObQualifiedName &q_name, ObPLCompileUnitAST &unit_ast, ObRawExpr *&expr); - int resolve_udf(sql::ObUDFInfo &udf_info, - const ObIArray &access_name, - ObPLCompileUnitAST &func); + int make_self_symbol_expr(ObPLCompileUnitAST &func, ObRawExpr *&expr); + int add_udt_self_argument(const ObIRoutineInfo *routine_info, + ObIArray &expr_params, + ObIArray &access_idxs, + ObUDFInfo &udf_info, + ObPLCompileUnitAST &func); int resolve_qualified_identifier(sql::ObQualifiedName &q_name, ObIArray &columns, ObIArray &real_exprs, @@ -909,12 +941,9 @@ private: ObParamExternType type, uint64_t obj_id, ObPLExternTypeInfo &extern_type_info); - int check_is_udt_routine(const ObObjAccessIdent &access_ident, // 当前正在resolve的ident + int check_is_udt_routine(const ObObjAccessIdent &access_ident, const ObPLBlockNS &ns, ObIArray &access_idxs, - ObObjAccessIdx &access_id, - ObString &udt_type_name, - uint64_t &udt_id, bool &is_routine); static int get_number_literal_value(ObRawExpr *expr, int64_t &result); int check_assign_type(const ObPLDataType &dest_data_type, const ObRawExpr *right_expr); @@ -967,6 +996,10 @@ private: ObPLFunctionAST &func, int64_t &idx); int check_update_column(const ObPLBlockNS &ns, const ObIArray& access_idxs); + static int get_udt_names(ObSchemaGetterGuard &schema_guard, + const uint64_t udt_id, + ObString &database_name, + ObString &udt_name); static int get_udt_database_name(ObSchemaGetterGuard &schema_guard, const uint64_t udt_id, ObString &db_name); static bool check_with_rowid(const ObString &routine_name, @@ -974,6 +1007,71 @@ private: static int recursive_replace_expr(ObRawExpr *expr, ObQualifiedName &qualified_name, ObRawExpr *real_expr); + + int replace_udf_param_expr(ObQualifiedName &q_name, + ObIArray &columns, + ObIArray &real_exprs); + int replace_udf_param_expr(ObObjAccessIdent &access_ident, + ObIArray &columns, + ObIArray &real_exprs); + int get_names_by_access_ident(ObObjAccessIdent &access_ident, + ObIArray &access_idxs, + ObString &database_name, + ObString &package_name, + ObString &routine_name); + int check_routine_callable(const ObPLBlockNS &ns, + ObIArray &access_idxs, + ObIArray &expr_params, + const ObIRoutineInfo &routine_info); + int resolve_routine(ObObjAccessIdent &access_ident, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + ObPLCompileUnitAST &func); + + int resolve_function(ObObjAccessIdent &access_ident, + ObIArray &access_idxs, + const ObIRoutineInfo *routine_info, + ObPLCompileUnitAST &func); + + int resolve_procedure(ObObjAccessIdent &access_ident, + ObIArray &access_idxs, + const ObIRoutineInfo *routine_info, + ObProcType routine_type); + + int resolve_construct(ObObjAccessIdent &access_ident, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + uint64_t user_type_id, + ObPLCompileUnitAST &func); + + int resolve_self_element_access(ObObjAccessIdent &access_ident, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + ObPLCompileUnitAST &func); + + int build_current_access_idx(uint64_t parent_id, + ObObjAccessIdx &access_idx, + ObObjAccessIdent &access_ident, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + ObPLCompileUnitAST &func); + + int build_collection_index_expr(ObObjAccessIdent &access_ident, + ObObjAccessIdx &access_idx, + const ObPLBlockNS &ns, + ObIArray &access_idxs, + const ObUserDefinedType &user_type, + ObPLCompileUnitAST &func); + + int build_access_idx_sys_func(uint64_t parent_id, ObObjAccessIdx &access_idx); + + int resolve_composite_access(ObObjAccessIdent &access_ident, + ObIArray &access_idxs, + const ObPLBlockNS &ns, + ObPLCompileUnitAST &func); + + int init_udf_info_of_accessidents(ObIArray &access_ident); + private: ObPLResolveCtx resolve_ctx_; ObPLExternalNS external_ns_; diff --git a/src/pl/ob_pl_stmt.cpp b/src/pl/ob_pl_stmt.cpp index 26e6e0f0c..8c5fbcf17 100644 --- a/src/pl/ob_pl_stmt.cpp +++ b/src/pl/ob_pl_stmt.cpp @@ -1489,8 +1489,11 @@ int ObPLExternalNS::resolve_external_symbol(const common::ObString &name, uint64_t package_id = OB_INVALID_ID; if (parent_id != OB_INVALID_INDEX) { db_id = parent_id; - } else { - OZ (session_info.get_database_id(db_id)); + } else if (OB_FAIL(session_info.get_database_id(db_id))) { + LOG_WARN("failed to get session database id", K(ret), K(db_id)); + } else if (OB_INVALID_ID == db_id) { + ret = OB_ERR_NO_DB_SELECTED; + LOG_WARN("No database selected", K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(schema_guard.get_package_id( @@ -1669,7 +1672,9 @@ int ObPLExternalNS::resolve_external_symbol(const common::ObString &name, } break; case PKG_VAR: { - if (lib::is_mysql_mode()) { + if (lib::is_mysql_mode() + && get_tenant_id_by_object_id(parent_id) != OB_SYS_TENANT_ID + && session_info.get_effective_tenant_id() != OB_SYS_TENANT_ID) { ret = OB_ERR_UNEXPECTED; LOG_WARN("package is not supported in Mysql mode", K(type), K(ret)); } else { diff --git a/src/pl/ob_pl_stmt.h b/src/pl/ob_pl_stmt.h index b24101cd5..a759687ce 100644 --- a/src/pl/ob_pl_stmt.h +++ b/src/pl/ob_pl_stmt.h @@ -859,6 +859,9 @@ public: || UDT_FUNCTION == type_; } inline uint64_t get_tenant_id() const { return tenant_id_; } inline uint64_t get_db_id() const { return db_id_; } + + virtual uint64_t get_database_id() const { return db_id_; } + virtual uint64_t get_package_id() const { return pkg_id_; } inline uint64_t get_pkg_id() const { return pkg_id_; } inline ObProcType get_type() const { return type_; } int get_idx(int64_t &idx) const; diff --git a/src/pl/ob_pl_type.h b/src/pl/ob_pl_type.h index 2d8c42864..258bbc0e8 100644 --- a/src/pl/ob_pl_type.h +++ b/src/pl/ob_pl_type.h @@ -78,6 +78,20 @@ class ObPLUserTypeTable; class ObUserDefinedType; class ObPLStmt; +enum ObProcType +{ + INVALID_PROC_TYPE = 0, + STANDALONE_PROCEDURE, + STANDALONE_FUNCTION, + PACKAGE_PROCEDURE, /* A subprogram created inside a package is a packaged subprogram */ + PACKAGE_FUNCTION, + NESTED_PROCEDURE, /* A subprogram created inside a PL/SQL block is a nested subprogram */ + NESTED_FUNCTION, + STANDALONE_ANONYMOUS, + UDT_PROCEDURE, + UDT_FUNCTION, +}; + enum ObPLType { PL_INVALID_TYPE = -1, @@ -644,7 +658,7 @@ public: bool is_subprogram_var() const { return IS_SUBPROGRAM_VAR == access_type_; } bool is_user_var() const { return IS_USER == access_type_; } bool is_session_var() const { return IS_SESSION == access_type_ || IS_GLOBAL == access_type_; } - bool is_ns() const { return IS_DB_NS == access_type_ || IS_PKG_NS == access_type_; } + bool is_ns() const { return IS_DB_NS == access_type_ || IS_PKG_NS == access_type_ || IS_UDT_NS == access_type_; } bool is_const() const { return IS_CONST == access_type_; } bool is_property() const { return IS_PROPERTY == access_type_; } bool is_external() const diff --git a/src/rootserver/ob_ddl_service.cpp b/src/rootserver/ob_ddl_service.cpp index ea190d54b..587282691 100644 --- a/src/rootserver/ob_ddl_service.cpp +++ b/src/rootserver/ob_ddl_service.cpp @@ -30303,7 +30303,7 @@ int ObDDLService::drop_user_defined_function(const obrpc::ObDropUserDefinedFunct LOG_WARN("check_udf_exist failed", K(tenant_id), K(name), K(ret)); } else if (!is_exist) { if (if_exist) { - LOG_USER_NOTE(OB_ERR_FUNCTION_UNKNOWN, name.length(), name.ptr()); + LOG_USER_NOTE(OB_ERR_FUNCTION_UNKNOWN, "FUNCTION", name.length(), name.ptr()); LOG_INFO("function not exist, no need to delete it", K(tenant_id), K(name)); } else { ret = OB_ERR_FUNCTION_UNKNOWN; diff --git a/src/share/ob_errno.cpp b/src/share/ob_errno.cpp index cacba9881..c43903e7a 100644 --- a/src/share/ob_errno.cpp +++ b/src/share/ob_errno.cpp @@ -7120,10 +7120,10 @@ static const _error _error_OB_ERR_FUNCTION_UNKNOWN = { .mysql_errno = ER_SP_DOES_NOT_EXIST, .sqlstate = "42000", .str_error = "FUNCTION does not exist", - .str_user_error = "FUNCTION %.*s does not exist", + .str_user_error = "%s %.*s does not exist", .oracle_errno = 600, .oracle_str_error = "ORA-00600: internal error code, arguments: -5055, FUNCTION does not exist", - .oracle_str_user_error = "ORA-00600: internal error code, arguments: -5055, FUNCTION %.*s does not exist" + .oracle_str_user_error = "ORA-00600: internal error code, arguments: -5055, %s %.*s does not exist" }; static const _error _error_OB_ERR_CREAT_MODIFY_TIME_COLUMN = { .error_name = "OB_ERR_CREAT_MODIFY_TIME_COLUMN", diff --git a/src/share/ob_errno.def b/src/share/ob_errno.def index 7d0d8b1bb..600a8c840 100644 --- a/src/share/ob_errno.def +++ b/src/share/ob_errno.def @@ -695,7 +695,7 @@ DEFINE_ERROR(OB_ERR_PASSWORD_EMPTY, -5051, -1, "HY000", "Empty password"); DEFINE_ERROR(OB_ERR_GRANT_PRIVILEGES_TO_CREATE_TABLE, -5052, -1, "42000", "Failed to grant privelege"); DEFINE_ERROR_EXT(OB_ERR_WRONG_DYNAMIC_PARAM, -5053, -1, "HY093", "Wrong dynamic parameters", "Incorrect arguments number to EXECUTE, need %ld arguments but give %ld"); DEFINE_ORACLE_ERROR_EXT(OB_ERR_PARAM_SIZE, -5054, ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, "42000", "Incorrect parameter count", "Incorrect parameter count in the call to native function '%.*s'", 909, "invalid number of arguments", "invalid number of arguments in the call to native function '%.*s'"); -DEFINE_ERROR_EXT(OB_ERR_FUNCTION_UNKNOWN, -5055, ER_SP_DOES_NOT_EXIST, "42000", "FUNCTION does not exist", "FUNCTION %.*s does not exist"); +DEFINE_ERROR_EXT(OB_ERR_FUNCTION_UNKNOWN, -5055, ER_SP_DOES_NOT_EXIST, "42000", "FUNCTION does not exist", "%s %.*s does not exist"); DEFINE_ERROR(OB_ERR_CREAT_MODIFY_TIME_COLUMN, -5056, -1, "23000", "CreateTime or ModifyTime column cannot be modified"); DEFINE_ERROR(OB_ERR_MODIFY_PRIMARY_KEY, -5057, -1, "23000", "Primary key cannot be modified"); DEFINE_ERROR(OB_ERR_PARAM_DUPLICATE, -5058, -1, "42000", "Duplicated parameters"); diff --git a/src/share/ob_errno.h b/src/share/ob_errno.h index a7282e808..25fefe106 100644 --- a/src/share/ob_errno.h +++ b/src/share/ob_errno.h @@ -2302,7 +2302,7 @@ constexpr int OB_ERR_INVALID_DATE_MSG_FMT_V2 = -4219; #define OB_ERR_GRANT_PRIVILEGES_TO_CREATE_TABLE__USER_ERROR_MSG "Failed to grant privelege" #define OB_ERR_WRONG_DYNAMIC_PARAM__USER_ERROR_MSG "Incorrect arguments number to EXECUTE, need %ld arguments but give %ld" #define OB_ERR_PARAM_SIZE__USER_ERROR_MSG "Incorrect parameter count in the call to native function '%.*s'" -#define OB_ERR_FUNCTION_UNKNOWN__USER_ERROR_MSG "FUNCTION %.*s does not exist" +#define OB_ERR_FUNCTION_UNKNOWN__USER_ERROR_MSG "%s %.*s does not exist" #define OB_ERR_CREAT_MODIFY_TIME_COLUMN__USER_ERROR_MSG "CreateTime or ModifyTime column cannot be modified" #define OB_ERR_MODIFY_PRIMARY_KEY__USER_ERROR_MSG "Primary key cannot be modified" #define OB_ERR_PARAM_DUPLICATE__USER_ERROR_MSG "Duplicated parameters" @@ -4346,7 +4346,7 @@ constexpr int OB_ERR_INVALID_DATE_MSG_FMT_V2 = -4219; #define OB_ERR_GRANT_PRIVILEGES_TO_CREATE_TABLE__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5052, Failed to grant privelege" #define OB_ERR_WRONG_DYNAMIC_PARAM__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5053, Incorrect arguments number to EXECUTE, need %ld arguments but give %ld" #define OB_ERR_PARAM_SIZE__ORA_USER_ERROR_MSG "ORA-00909: invalid number of arguments in the call to native function '%.*s'" -#define OB_ERR_FUNCTION_UNKNOWN__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5055, FUNCTION %.*s does not exist" +#define OB_ERR_FUNCTION_UNKNOWN__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5055, %s %.*s does not exist" #define OB_ERR_CREAT_MODIFY_TIME_COLUMN__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5056, CreateTime or ModifyTime column cannot be modified" #define OB_ERR_MODIFY_PRIMARY_KEY__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5057, Primary key cannot be modified" #define OB_ERR_PARAM_DUPLICATE__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -5058, Duplicated parameters" diff --git a/src/share/schema/ob_routine_info.h b/src/share/schema/ob_routine_info.h index 6c9cdd031..3988b6851 100644 --- a/src/share/schema/ob_routine_info.h +++ b/src/share/schema/ob_routine_info.h @@ -125,6 +125,8 @@ public: virtual int find_param_by_name(const common::ObString &name, int64_t &position) const = 0; virtual int get_routine_param(int64_t position, ObIRoutineParam *¶m) const = 0; virtual const ObIRoutineParam* get_ret_info() const = 0; + virtual uint64_t get_database_id() const = 0; + virtual uint64_t get_package_id() const = 0; virtual void set_deterministic() = 0; virtual bool is_deterministic() const = 0; virtual void set_parallel_enable() = 0; diff --git a/src/sql/ob_spi.cpp b/src/sql/ob_spi.cpp index 7510d227d..87840ccb1 100644 --- a/src/sql/ob_spi.cpp +++ b/src/sql/ob_spi.cpp @@ -6759,7 +6759,7 @@ int ObSPIService::resolve_ref_objects(const ParseResult &parse_result, } } if (OB_SUCC(ret)) { - if (OB_FAIL(ObResolverUtils::resolve_udf(udf_node, case_mode, udf_info))) { + if (OB_FAIL(ObResolverUtils::resolve_udf_name_by_parse_node(udf_node, case_mode, udf_info))) { LOG_WARN("fail to resolve udf name", K(ret)); } else if (udf_info.udf_database_.empty()) { udf_info.udf_database_ = session.get_database_name(); diff --git a/src/sql/parser/sql_parser_mysql_mode.y b/src/sql/parser/sql_parser_mysql_mode.y index a51bad5d0..e829b1a33 100755 --- a/src/sql/parser/sql_parser_mysql_mode.y +++ b/src/sql/parser/sql_parser_mysql_mode.y @@ -2675,18 +2675,19 @@ MOD '(' expr ',' expr ')' } | relation_name '.' function_name '(' opt_expr_as_list ')' { + ParseNode *params = NULL; + ParseNode *function = NULL; + ParseNode *sub_obj_access_ref = NULL; + ParseNode *udf_node = NULL; if (NULL != $5) { - ParseNode *params = NULL; merge_nodes(params, result, T_EXPR_LIST, $5); - malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_UDF, 4, $3, params, $1, NULL); - store_pl_ref_object_symbol($$, result, REF_FUNC); - } - else - { - malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_UDF, 4, $3, NULL, $1, NULL); - store_pl_ref_object_symbol($$, result, REF_FUNC); } + malloc_non_terminal_node(function, result->malloc_pool_, T_FUN_SYS, 2, $3, params); + malloc_non_terminal_node(sub_obj_access_ref, result->malloc_pool_, T_OBJ_ACCESS_REF, 2, function, NULL); + malloc_non_terminal_node($$, result->malloc_pool_, T_OBJ_ACCESS_REF, 2, $1, sub_obj_access_ref); + malloc_non_terminal_node(udf_node, result->malloc_pool_, T_FUN_UDF, 4, $3, params, $1, NULL); + store_pl_ref_object_symbol(udf_node, result, REF_FUNC); } | sys_interval_func { diff --git a/src/sql/resolver/cmd/ob_variable_set_resolver.cpp b/src/sql/resolver/cmd/ob_variable_set_resolver.cpp index ef6385922..76542d346 100644 --- a/src/sql/resolver/cmd/ob_variable_set_resolver.cpp +++ b/src/sql/resolver/cmd/ob_variable_set_resolver.cpp @@ -223,11 +223,9 @@ int ObVariableSetResolver::resolve_value_expr(ParseNode &val_node, ObRawExpr *&v sub_query_info, aggr_exprs, win_exprs, udf_info, op_exprs, user_var_exprs))) { LOG_WARN("resolve expr failed", K(ret)); - } else if (udf_info.count() > 0 && - OB_FAIL(ObRawExprUtils::init_udfs_info(params_, udf_info))) { - LOG_WARN("failed to init udf infos", K(ret)); - } else if (OB_FAIL(ObResolverUtils::resolve_columns_for_const_expr(value_expr, columns, params_))) { - LOG_WARN("resolve columns for const expr failed", K(ret)); + } else if (udf_info.count() > 0) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("UDFInfo should not found be here!!!", K(ret)); } else if (value_expr->get_expr_type() == T_SP_CPARAM) { ObCallParamRawExpr *call_expr = static_cast(value_expr); if (OB_ISNULL(call_expr->get_expr())) { @@ -249,6 +247,8 @@ int ObVariableSetResolver::resolve_value_expr(ParseNode &val_node, ObRawExpr *&v LOG_TRACE("set user variable with subquery", K(sub_query_info.count()), K(is_mysql_mode())); } if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObResolverUtils::resolve_columns_for_const_expr(value_expr, columns, params_))) { + LOG_WARN("resolve columns for const expr failed", K(ret)); } else if (OB_FAIL(value_expr->formalize(params_.session_info_))) { LOG_WARN("failed to formalize value expr", K(ret)); } else { diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index 876246d41..a481c11d6 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -1468,34 +1468,8 @@ int ObDMLResolver::resolve_sql_expr(const ParseNode &node, ObRawExpr *&expr, } if (OB_SUCC(ret) && udf_info.count() > 0) { - stmt_->get_query_ctx()->has_pl_udf_ = true; - for (int64_t i = 0; OB_SUCC(ret) && i < udf_info.count(); ++i) { - ObUDFInfo &udf = udf_info.at(i); - if(OB_FAIL(ObRawExprUtils::init_udf_info(params_, udf))) { - LOG_WARN("resolve user defined functions failed", K(ret)); - } else { - ObDMLStmt *stmt = get_stmt(); - ObUDFRawExpr *udf_expr = static_cast(udf_info.at(i).ref_expr_); - share::schema::ObSchemaGetterGuard *schema_guard = NULL; - uint64_t database_id = OB_INVALID_ID; - if (OB_ISNULL(stmt) || OB_ISNULL(udf_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("stmt or expr is null", K(stmt), K(udf_expr), K(ret)); - } else if (OB_ISNULL(schema_guard = params_.schema_checker_->get_schema_guard())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("table schema is null", K(ret), K(schema_guard)); - } else if (OB_FAIL(schema_guard->get_database_id(session_info_->get_effective_tenant_id(), udf_expr->get_database_name(), database_id))) { - LOG_WARN("failed to get database id", K(ret)); - } else if (udf_expr->need_add_dependency()) { - ObSchemaObjVersion udf_version; - uint64_t dep_obj_id = view_ref_id_; - uint64_t dep_db_id = database_id; - OZ (udf_expr->get_schema_object_version(udf_version)); - OZ (stmt->add_global_dependency_table(udf_version)); - OZ (stmt->add_ref_obj_version(dep_obj_id, dep_db_id, ObObjectType::VIEW, udf_version, *allocator_)); - } - } - } + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("UDFInfo should not found be here!!!", K(ret)); } //try to convert ObUDFRawExpr to ObAggRawExpr for pl agg udf if (OB_SUCC(ret)) { @@ -2331,22 +2305,39 @@ int ObDMLResolver::resolve_qualified_identifier(ObQualifiedName &q_name, LOG_WARN("sqlcode or sqlerrm can not use in dml directly", K(ret), KPC(real_ref_expr)); } else { if (q_name.is_access_root() - && is_external - && !params_.is_default_param_ - && T_INTO_SCOPE != current_scope_ - && NULL != params_.secondary_namespace_ //仅PL里的SQL出现了外部变量需要替换成QUESTIONMARK,纯SQL语境的不需要 - && (real_ref_expr->is_const_raw_expr() //local变量 + && is_external + && !params_.is_default_param_ + && T_INTO_SCOPE != current_scope_ + && NULL != params_.secondary_namespace_) { //仅PL里的SQL出现了外部变量需要替换成QUESTIONMARK,纯SQL语境的不需要 + if (real_ref_expr->is_const_raw_expr() //local变量 || real_ref_expr->is_obj_access_expr() //复杂变量 || T_OP_GET_PACKAGE_VAR == real_ref_expr->get_expr_type() //package变量(system/user variable不会走到这里) || real_ref_expr->is_sys_func_expr() - || T_FUN_PL_GET_CURSOR_ATTR == real_ref_expr->get_expr_type())) { //允许CURSOR%ROWID通过 - /* - * 在已有的表达式里寻找是否有相同,如果有相同则使用同一个QuestionMark - * */ - OZ (ObResolverUtils::resolve_external_param_info(params_.external_param_info_, - *params_.expr_factory_, - params_.prepare_param_count_, - real_ref_expr)); + || T_FUN_PL_GET_CURSOR_ATTR == real_ref_expr->get_expr_type()) { //允许CURSOR%ROWID通过 + /* + * 在已有的表达式里寻找是否有相同,如果有相同则使用同一个QuestionMark + * */ + OZ (ObResolverUtils::resolve_external_param_info(params_.external_param_info_, + *params_.expr_factory_, + params_.prepare_param_count_, + real_ref_expr)); + } else if (real_ref_expr->is_udf_expr() + && OB_NOT_NULL(real_ref_expr->get_param_expr(0)) + && real_ref_expr->get_param_expr(0)->has_flag(IS_UDT_UDF_SELF_PARAM)) { + ObRawExpr *self = real_ref_expr->get_param_expr(0); + if (self->is_const_raw_expr() + || self->is_obj_access_expr() + || T_OP_GET_PACKAGE_VAR == self->get_expr_type() + || self->is_sys_func_expr()) { + OZ (ObResolverUtils::resolve_external_param_info(params_.external_param_info_, + *params_.expr_factory_, + params_.prepare_param_count_, + self)); + OZ (ObRawExprUtils::replace_ref_column(real_ref_expr, + real_ref_expr->get_param_expr(0), + self)); + } + } } } } @@ -10160,7 +10151,9 @@ int ObDMLResolver::resolve_external_name(ObQualifiedName &q_name, } else if (OB_ISNULL(schema_guard = params_.schema_checker_->get_schema_guard())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table schema is null", K(ret), K(schema_guard)); - } else if (OB_FAIL(schema_guard->get_database_id(session_info_->get_effective_tenant_id(), udf_expr->get_database_name(), database_id))) { + } else if (OB_FAIL(schema_guard->get_database_id(session_info_->get_effective_tenant_id(), + udf_expr->get_database_name().empty() ? session_info_->get_database_name() : udf_expr->get_database_name(), + database_id))) { LOG_WARN("failed to get database id", K(ret)); } else if (udf_expr->need_add_dependency()) { uint64_t dep_obj_id = view_ref_id_; diff --git a/src/sql/resolver/expr/ob_raw_expr.cpp b/src/sql/resolver/expr/ob_raw_expr.cpp index 1f460f654..e7409262a 100644 --- a/src/sql/resolver/expr/ob_raw_expr.cpp +++ b/src/sql/resolver/expr/ob_raw_expr.cpp @@ -94,7 +94,7 @@ int ObRawExprFactory::create_raw_expr(ObItemType expr_type, ObOpRaw void ObQualifiedName::format_qualified_name(ObNameCaseMode mode) { UNUSED(mode); //TODO: @ryan.ly @yuming.wyc - bool maybe_column = !is_sys_func() && !is_pl_udf() && !is_dll_udf() && !is_pl_var(); + bool maybe_column = !is_sys_func() && !is_pl_udf() && !is_dll_udf() && !is_pl_var() && !is_udf_return_access(); for (int64_t i = 0; maybe_column && i < access_idents_.count(); ++i) { if (access_idents_.at(i).access_name_.empty() || access_idents_.at(i).access_index_ != OB_INVALID_INDEX) { maybe_column = false; @@ -2638,7 +2638,8 @@ int ObObjAccessRawExpr::add_access_indexs(const ObIArray &ac //do nothing } break; - case pl::ObObjAccessIdx::IS_UDF_NS: { + case pl::ObObjAccessIdx::IS_UDF_NS: + case pl::ObObjAccessIdx::IS_UDT_NS: { //do nothing } break; diff --git a/src/sql/resolver/expr/ob_raw_expr.h b/src/sql/resolver/expr/ob_raw_expr.h index cd88aa0a8..92349a77c 100644 --- a/src/sql/resolver/expr/ob_raw_expr.h +++ b/src/sql/resolver/expr/ob_raw_expr.h @@ -949,15 +949,11 @@ struct ObUDFInfo is_contain_self_param_(false), is_udt_udf_inside_pkg_(false), is_new_keyword_used_(false), - flag_(0), - self_arg_(NULL) {} + flag_(0) {} void set_is_udf_udt_static() { flag_ |= UDF_UDT_STATIC; } - bool is_udf_udt_static() const { - return is_udt_udf_ && !!(flag_ & UDF_UDT_STATIC); - } bool is_udf_udt_member() const { return is_udt_udf_ && !(flag_ & UDF_UDT_STATIC); } @@ -1013,7 +1009,6 @@ struct ObUDFInfo bool is_udt_udf_inside_pkg_; bool is_new_keyword_used_; // if in NEW obj(...) form uint64_t flag_; - ObRawExpr *self_arg_; // if this is udt routine, it has self argument }; enum AccessNameType @@ -1082,6 +1077,7 @@ public: inline void set_type_method() { type_ = TYPE_METHOD; } inline void set_cursor_attr() { type_ = CURSOR_ATTR; } inline void set_udt_ns() { type_ = UDT_NS; } + inline bool is_unknown() const { return UNKNOWN == type_; } inline bool is_sys_func() const { return SYS_FUNC == type_; } inline bool is_dll_udf() const { return DLL_UDF == type_; } inline bool is_pl_udf() const { return PL_UDF == type_; } @@ -1150,7 +1146,21 @@ public: } void format_qualified_name(common::ObNameCaseMode mode); - inline bool is_sys_func() const { return 1 == access_idents_.count() && access_idents_.at(0).is_sys_func(); } + inline bool is_unknown() const + { + bool bret = true; + for (int64_t i = 0; bret && i < access_idents_.count(); ++i) { + if (!access_idents_.at(i).is_unknown()) { + bret = false; + break; + } + } + return bret; + } + inline bool is_sys_func() const + { + return 1 == access_idents_.count() && access_idents_.at(0).is_sys_func(); + } inline bool is_pl_udf() const { bool bret = !access_idents_.empty() @@ -3841,6 +3851,7 @@ public: K_(is_aggr_udf_distinct), K_(loc), K_(is_udt_cons), + K_(params_desc_v2), N_CHILDREN, exprs_); private: uint64_t udf_id_; diff --git a/src/sql/resolver/expr/ob_raw_expr_printer.cpp b/src/sql/resolver/expr/ob_raw_expr_printer.cpp index 6e94ba59f..89b5fd1ad 100644 --- a/src/sql/resolver/expr/ob_raw_expr_printer.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_printer.cpp @@ -3131,13 +3131,15 @@ int ObRawExprPrinter::print(ObUDFRawExpr *expr) LOG_WARN("stmt_ is NULL of buf_ is NULL or pos_ is NULL or expr is NULL", K(ret)); } else { if (!print_params_.for_dblink_ && - !expr->get_database_name().empty()) { + !expr->get_database_name().empty() && + expr->get_database_name().case_compare("oceanbase") != 0) { PRINT_QUOT; DATA_PRINTF("%.*s", LEN_AND_PTR(expr->get_database_name())); PRINT_QUOT; DATA_PRINTF("."); } - if (!expr->get_package_name().empty()) { + if (!expr->get_package_name().empty() && + !expr->get_is_udt_cons()) { PRINT_QUOT; DATA_PRINTF("%.*s", LEN_AND_PTR(expr->get_package_name())); PRINT_QUOT; @@ -3156,6 +3158,8 @@ int ObRawExprPrinter::print(ObUDFRawExpr *expr) for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (params_type.at(i).is_null()) { // default parameter, do not print // do nothing ... + } else if (0 == i && expr->get_is_udt_cons()) { + // do not print construnct null self argument } else { if (!params_name.at(i).empty()) { PRINT_QUOT; diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp index eee1949ef..24d3e75c3 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp @@ -958,18 +958,16 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, ObRawExpr if (ret != OB_ERR_FUNCTION_UNKNOWN) { LOG_WARN("fail to process dll user function node", K(ret), K(node)); } else { - ParseNode *udf_node = NULL; - ObString empty_db_name; - ObString empty_pkg_name; - bool record_udf_info = true; - if (OB_FAIL(ObResolverUtils::transform_func_sys_to_udf(&ctx_.expr_factory_.get_allocator(), - node, empty_db_name, empty_pkg_name, udf_node))) { - LOG_WARN("transform func sys to udf node failed", K(ret)); - ret = OB_ERR_FUNCTION_UNKNOWN; - } else if (OB_FAIL(process_udf_node(udf_node, record_udf_info, expr))) { - LOG_WARN("fail to process user defined function node", K(ret), K(node)); - if(get_udf_param_syntax_err()) { - // do nothing + ParseNode *obj_access = NULL; + if (OB_FAIL(ObResolverUtils::transform_sys_func_to_objaccess(&ctx_.expr_factory_.get_allocator(), node, obj_access))) { + LOG_WARN("failed to transform to obj access node", K(ret)); + } else if (OB_ISNULL(obj_access)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("obj access node is null", K(ret)); + } else if (OB_FAIL(process_obj_access_node(*obj_access, expr))) { + LOG_WARN("failed to process obj access node", K(ret)); + if (get_udf_param_syntax_err()) { + // do nothing .... } else { ObString func_name(node->children_[0]->str_len_, node->children_[0]->str_value_); ret = OB_ERR_WRONG_PARAMETERS_TO_NATIVE_FCT; @@ -983,10 +981,8 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, ObRawExpr break; } case T_FUN_UDF: { - bool record_udf_info = true; - if (OB_FAIL(process_udf_node(node, record_udf_info, expr))) { - LOG_WARN("fail to process user defined function node", K(ret), K(node)); - } + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("A BUG, Nerver Be Here!!!", K(ret)); break; } case T_WINDOW_FUNCTION: { @@ -1501,72 +1497,6 @@ int ObRawExprResolverImpl::check_pseudo_column_exist(ObItemType type, ObPseudoCo return ret; } -int ObRawExprResolverImpl::check_name_type(ObQualifiedName &q_name, - ObStmtScope scope, - AccessNameType &type) -{ - int ret = OB_SUCCESS; - SET_LOG_CHECK_MODE(); - type = UNKNOWN; - bool check_success = false; - if (OB_SUCC(ret) && !check_success) { - if (T_PL_SCOPE == scope) { //PL scope里优先解释为var,次优先udf,最后是sys func - if (OB_FAIL(check_pl_variable(q_name, check_success))) { - LOG_WARN("check pl variable failed", K(q_name), K(ret)); - } else if (check_success) { - type = q_name.is_type_method() ? TYPE_METHOD : PL_VAR; - } else if (OB_FAIL(check_pl_udf(q_name, - ctx_.session_info_, - ctx_.schema_checker_, - ctx_.secondary_namespace_, - check_success))) { - LOG_WARN("check pl variable failed", K(q_name), K(ret)); - } else if (check_success) { - type = PL_UDF; - } else if (OB_FAIL(check_sys_func(q_name, check_success))) { - LOG_WARN("check pl variable failed", K(q_name), K(ret)); - } else if (check_success) { - type = SYS_FUNC; - } else { /*do nothing*/ } - } else { //SQL scope里优先解释为sys func,次优先var,最后是udf - if (OB_FAIL(check_sys_func(q_name, check_success))) { - LOG_WARN("check pl variable failed", K(q_name), K(ret)); - } else if (check_success) { - type = SYS_FUNC; - } else if (OB_FAIL(check_pl_variable(q_name, check_success))) { - LOG_WARN("check pl variable failed", K(q_name), K(ret)); - } else if (check_success) { - type = q_name.is_type_method() ? TYPE_METHOD : PL_VAR;; - } else if (OB_FAIL(check_pl_udf(q_name, - ctx_.session_info_, - ctx_.schema_checker_, - ctx_.secondary_namespace_, - check_success))) { - LOG_WARN("check pl variable failed", K(q_name), K(ret)); - } else if (check_success) { - type = PL_UDF; - } else { /*do nothing*/ } - } - } - - if ((OB_SUCC(ret) && !check_success) - || (OB_ERR_INVOKE_STATIC_BY_INSTANCE != ret && OB_FAIL(ret))) { - ret = OB_SUCCESS; - CK (q_name.access_idents_.count() <= 3 && q_name.access_idents_.count() >= 1); - if (3 == q_name.access_idents_.count()) { - OX (q_name.database_name_ = q_name.access_idents_.at(0).access_name_); - OX (q_name.tbl_name_ = q_name.access_idents_.at(1).access_name_); - } else if (2 == q_name.access_idents_.count()) { - OX (q_name.tbl_name_ = q_name.access_idents_.at(0).access_name_); - } - //如果sys func和pl udf都找不到,那么认为可能是还没有创建出来的UDF - OX (type = PL_UDF); - OX (q_name.access_idents_.at(q_name.access_idents_.count() - 1).set_pl_udf()); - } - CANCLE_LOG_CHECK_MODE(); - return ret; -} - int ObRawExprResolverImpl::check_pl_variable(ObQualifiedName &q_name, bool &is_pl_var) { int ret = OB_SUCCESS; @@ -1575,7 +1505,7 @@ int ObRawExprResolverImpl::check_pl_variable(ObQualifiedName &q_name, bool &is_p ObRawExprFactory expr_factory(allocator); ObRawExpr *var = NULL; if (NULL == ctx_.secondary_namespace_) { - //非PL语境,返回false即可(package对象不可在纯sql语境里访问,但是package里的function可以) + // do nothing ... } else { SET_LOG_CHECK_MODE(); CK(OB_NOT_NULL(ctx_.secondary_namespace_->get_external_ns())); @@ -1583,22 +1513,22 @@ int ObRawExprResolverImpl::check_pl_variable(ObQualifiedName &q_name, bool &is_p ObArray fake_columns; ObArray fake_exprs; if (OB_FAIL(ObResolverUtils::resolve_external_symbol(allocator, - expr_factory, - ctx_.secondary_namespace_->get_external_ns()->get_resolve_ctx().session_info_, - ctx_.secondary_namespace_->get_external_ns()->get_resolve_ctx().schema_guard_, - &ctx_.secondary_namespace_->get_external_ns()->get_resolve_ctx().sql_proxy_, - ctx_.external_param_info_, - ctx_.secondary_namespace_, - q_name, - fake_columns, - fake_exprs, - var, - false,/*is_prepare_protocol*/ - true,/*is_check_mode*/ - ctx_.current_scope_ != T_PL_SCOPE /*is_sql_scope*/))) { + expr_factory, + ctx_.secondary_namespace_->get_external_ns()->get_resolve_ctx().session_info_, + ctx_.secondary_namespace_->get_external_ns()->get_resolve_ctx().schema_guard_, + &ctx_.secondary_namespace_->get_external_ns()->get_resolve_ctx().sql_proxy_, + ctx_.external_param_info_, + ctx_.secondary_namespace_, + q_name, + fake_columns, + fake_exprs, + var, + false,/*is_prepare_protocol*/ + true,/*is_check_mode*/ + ctx_.current_scope_ != T_PL_SCOPE /*is_sql_scope*/))) { LOG_INFO("failed to resolve external symbol", K(q_name), K(ret)); if (OB_ERR_INVOKE_STATIC_BY_INSTANCE != ret) { - ret = OB_SUCCESS; //TODO:@ryan.ly 只针对某些错误码 + ret = OB_SUCCESS; } } else if (OB_ISNULL(var)) { ret = OB_ERR_UNEXPECTED; @@ -1628,7 +1558,10 @@ int ObRawExprResolverImpl::check_sys_func(ObQualifiedName &q_name, bool &is_sys_ int ret = OB_SUCCESS; is_sys_func = 1 == q_name.access_idents_.count() && (IS_FUN_SYS_TYPE(ObExprOperatorFactory::get_type_by_name(q_name.access_idents_.at(0).access_name_)) - || 0 == q_name.access_idents_.at(0).access_name_.case_compare("sqlerrm")); + || 0 == q_name.access_idents_.at(0).access_name_.case_compare("sqlerrm")) + && q_name.access_idents_.at(0).access_name_.case_compare("nextval") != 0 + && q_name.access_idents_.at(0).access_name_.case_compare("currval") != 0; + if (is_sys_func) { q_name.access_idents_.at(0).set_sys_func(); } @@ -1641,272 +1574,322 @@ static bool check_is_pl_jsontype(const ObString& name) || (name.length() == 14 && ObString("JSON_ELEMENT_T").compare(name) == 0)); } -int ObRawExprResolverImpl::check_dll_udf(ObQualifiedName &q_name, bool &is_dll_udf) -{ - int ret = OB_SUCCESS; - is_dll_udf = false; - if (!q_name.access_idents_.empty()) { - const share::schema::ObUDF *udf_info = NULL; - ObString &func_name = q_name.access_idents_.at(q_name.access_idents_.count() - 1).access_name_; - if (OB_ISNULL(ctx_.session_info_) || OB_ISNULL(ctx_.schema_checker_)) { - //PL resovler don't have session info and schema checker - } else if (OB_FAIL(ctx_.schema_checker_->get_udf_info(ctx_.session_info_->get_effective_tenant_id(), - func_name, - udf_info, - is_dll_udf))) { - LOG_WARN("failed to get udf info"); - } else if (is_dll_udf) { - q_name.access_idents_.at(0).set_dll_udf(); - } else { /*do nothing*/ } - } - return ret; -} - int ObRawExprResolverImpl::check_pl_udf(ObQualifiedName &q_name, const ObSQLSessionInfo *session_info, ObSchemaChecker *schema_checker, pl::ObPLBlockNS *secondary_namespace, - bool &is_pl_udf) + pl::ObProcType &proc_type) { int ret = OB_SUCCESS; - SET_LOG_CHECK_MODE(); - is_pl_udf = false; - pl::ObProcType proc_type = pl::INVALID_PROC_TYPE; + bool is_pl_udf = false; uint64_t udt_id = OB_INVALID_ID; - if (q_name.access_idents_.empty()) { + proc_type = pl::INVALID_PROC_TYPE; + if (1 == q_name.access_idents_.count()) { + if (OB_FAIL(ObResolverUtils::check_routine_exists(session_info, + schema_checker, + secondary_namespace, + ObString(""), + ObString(""), + q_name.access_idents_.at(0).access_name_, + share::schema::ObRoutineType::ROUTINE_FUNCTION_TYPE, + is_pl_udf, + proc_type, + udt_id))) { + LOG_WARN("failed to check_routine_exists", K(ret), K(q_name)); + } + } else { ret = OB_ERR_UNEXPECTED; - LOG_WARN("Invalid name", K(q_name), K(ret)); - } else if (q_name.access_idents_.count() < 4) { - ObString db_name; - ObString pkg_name; - ObString udt_name; - ObString &func_name = q_name.access_idents_.at(q_name.access_idents_.count() - 1).access_name_; - switch (q_name.access_idents_.count()) { + LOG_WARN("check pl udf only allow q_name.access_idents_ is 1", K(ret), K(q_name)); + } + return ret; +} -#define CKECK_ROUTINE_EXISTS \ -do { \ - if (OB_SUCC(ret)) { \ - if (OB_FAIL(ObResolverUtils::check_routine_exists(session_info, \ - schema_checker, \ - secondary_namespace, \ - db_name, \ - pkg_name, \ - func_name, \ - share::schema::ObRoutineType::ROUTINE_FUNCTION_TYPE, \ - is_pl_udf, \ - proc_type, \ - udt_id))) { \ - LOG_WARN("failed to check_routine_exists", K(q_name), K(db_name), K(pkg_name), K(func_name), K(ret)); \ - } \ - } \ -} while (0) +// PL SCOPE : local udf/local variables > sys function > public function +// SQL SCOPE : sys function > local udf/local variables > public function +// actually we only need recongnise sys function +int ObRawExprResolverImpl::check_name_type( + ObQualifiedName &q_name, ObStmtScope scope, AccessNameType &type) +{ + int ret = OB_SUCCESS; - case 1: { - CKECK_ROUTINE_EXISTS; - if (OB_SUCC(ret) && is_pl_udf) { - //对于一个func,优先级顺序是:package local func > sys func > standalone func - if (pl::STANDALONE_PROCEDURE == proc_type || pl::STANDALONE_FUNCTION == proc_type) { - bool is_sys_func = false; - if (OB_FAIL(check_sys_func(q_name, is_sys_func))) { - LOG_WARN("check sys func failed", K(q_name), K(ret)); - } else if (is_sys_func) { - is_pl_udf = false; - } else { /*do nothing*/ } - } - if (OB_SUCC(ret) && is_pl_udf) { - q_name.access_idents_.at(0).set_pl_udf(); - q_name.col_name_ = func_name; - } + SET_LOG_CHECK_MODE(); + + type = UNKNOWN; + bool check_success = false; + pl::ObProcType proc_type = pl::INVALID_PROC_TYPE; + + if (T_PL_SCOPE == scope) { //PL Scope: Variable > UDF > SysFunction + if (OB_FAIL(check_pl_variable(q_name, check_success))) { + LOG_WARN("check pl variable failed", K(q_name), K(ret)); + } else if (check_success) { + type = q_name.is_type_method() ? TYPE_METHOD : PL_VAR; + } else if (OB_FAIL(check_sys_func(q_name, check_success))) { + LOG_WARN("check system function failed", K(ret), K(q_name)); + } else if (check_success) { + // Variables > System function > Local pl function, so here only need to check local pl function. + if (OB_FAIL(check_pl_udf(q_name, + ctx_.session_info_, + ctx_.schema_checker_, + ctx_.secondary_namespace_, + proc_type))) { + LOG_WARN("check pl udf failed", K(ret), K(q_name)); + } else if (proc_type != pl::INVALID_PROC_TYPE && proc_type != pl::STANDALONE_FUNCTION) { + q_name.access_idents_.at(0).set_pl_udf(); + type = PL_UDF; } else { - // two case: - /* - * object type may have: - * 1. return object_cons; which object_cons is object constructor - * 2. expr(a, object_cons); which object_cons is also object constructor - */ - bool is_udt_exist = false; - if (OB_NOT_NULL(schema_checker) && OB_NOT_NULL(session_info)) { - OZ (schema_checker->check_udt_exist(session_info->get_effective_tenant_id(), - session_info->get_database_id(), - OB_INVALID_ID, - share::schema::ObUDTTypeCode::UDT_TYPE_OBJECT, - func_name, - is_udt_exist)); - if (OB_SUCC(ret) && is_udt_exist) { - OZ (schema_checker->get_udt_id(session_info->get_effective_tenant_id(), - session_info->get_database_name(), - func_name, udt_id)); - } - if (OB_SUCC(ret) && OB_INVALID_ID == udt_id && !is_udt_exist) { - // may system udt - OZ (schema_checker->get_udt_id(OB_SYS_TENANT_ID, - OB_SYS_DATABASE_ID, - OB_INVALID_ID, - func_name, - udt_id), - K(func_name), K(udt_id)); - } - if (OB_SUCC(ret) && OB_INVALID_ID != udt_id) { - int tmp_ret = ret; - ret = OB_SUCCESS; - pkg_name = func_name; - CKECK_ROUTINE_EXISTS; - if (OB_SUCC(ret) && is_pl_udf) { - q_name.access_idents_.at(0).set_pl_udf(); - q_name.tbl_name_ = pkg_name; - q_name.col_name_ = func_name; - } else { - ret = tmp_ret; - } - } - } + type = SYS_FUNC; } + } else { // not variables, not system function, must be udf, do not check it. + q_name.access_idents_.at(q_name.access_idents_.count() - 1).set_pl_udf(); + type = PL_UDF; } - break; - case 2: { - // try pkg.routine() first - db_name = session_info->get_database_name(); - pkg_name = q_name.access_idents_.at(0).access_name_; - CKECK_ROUTINE_EXISTS; - if (OB_SUCC(ret) && is_pl_udf) { - q_name.access_idents_.at(0).set_pkg_ns(); - q_name.access_idents_.at(1).set_pl_udf(); - q_name.database_name_ = db_name; - q_name.tbl_name_ = pkg_name; - q_name.col_name_ = func_name; - } else { - ret = OB_SUCCESS; //TODO:@ryan.ly 特定的错误码才处理 - db_name = q_name.access_idents_.at(0).access_name_; - pkg_name.reset(); - CKECK_ROUTINE_EXISTS; - if (OB_SUCC(ret) && is_pl_udf) { - q_name.access_idents_.at(0).set_db_ns(); - q_name.access_idents_.at(1).set_pl_udf(); - q_name.database_name_ = db_name; - q_name.tbl_name_.reset(); - q_name.col_name_ = func_name; + } else { //SQL Scope: System function > Variable > All pl functions + if (OB_FAIL(check_sys_func(q_name, check_success))) { + LOG_WARN("check pl variable failed", K(q_name), K(ret)); + } else if (check_success) { + type = SYS_FUNC; + } else if (OB_FAIL(check_pl_variable(q_name, check_success))) { + LOG_WARN("check pl variable failed", K(q_name), K(ret)); + } else if (check_success) { + type = q_name.is_type_method() ? TYPE_METHOD : PL_VAR;; + } else { + q_name.access_idents_.at(q_name.access_idents_.count() - 1).set_pl_udf(); + type = PL_UDF; + } + } + + CANCLE_LOG_CHECK_MODE(); + return ret; +} + +int ObRawExprResolverImpl::resolve_func_node_of_obj_access_idents(const ParseNode &left_node, ObQualifiedName &q_name) +{ + int ret = OB_SUCCESS; + const ParseNode &func_node = left_node; + if (OB_ISNULL(func_node.children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node is NULL", K(func_node.num_child_), K(ret)); + } else { + ObString ident_name(static_cast( + func_node.children_[0]->str_len_), func_node.children_[0]->str_value_); + + // first bit in value_ of T_FUN_SYS node is used to mark NEW keyword, + // value_ & 0x1 == 1: not used, + // value_ & 0x1 == 0: used, + // refer to sql_parser_oracle_mode.y + bool is_new_key_word_used = !(func_node.value_ & 0x1); + + if (ident_name.empty() && T_PL_SCOPE == ctx_.current_scope_ && lib::is_oracle_mode()) { + ret = OB_ERR_IDENT_EMPTY; + LOG_WARN("Identifier cannot be an empty string", K(ret), K(ident_name)); + } + OZ (q_name.access_idents_.push_back(ObObjAccessIdent(ident_name, OB_INVALID_INDEX)), K(ident_name)); + + if (OB_SUCC(ret)) { + ObObjAccessIdent &access_ident = q_name.access_idents_.at(q_name.access_idents_.count() - 1); + + AccessNameType name_type = UNKNOWN; + if (!q_name.is_unknown()) { + if (0 == access_ident.access_name_.case_compare("NEXT") + || 0 == access_ident.access_name_.case_compare("PRIOR") + || 0 == access_ident.access_name_.case_compare("EXISTS")) { + name_type = TYPE_METHOD; + access_ident.set_type_method(); } else { - // try system package routine - ret = OB_SUCCESS; - db_name = ObString(OB_SYS_DATABASE_NAME); - pkg_name = q_name.access_idents_.at(0).access_name_; - CKECK_ROUTINE_EXISTS; - if (OB_SUCC(ret) && is_pl_udf) { - q_name.access_idents_.at(0).set_pkg_ns(); - q_name.tbl_name_ = pkg_name; - q_name.access_idents_.at(1).set_pl_udf(); - q_name.database_name_ = db_name; - q_name.col_name_ = func_name; - } else { - } + name_type = PL_UDF; + access_ident.set_pl_udf(); + } + } else { + OZ (check_name_type(q_name, ctx_.current_scope_, name_type), K(q_name), K(name_type)); + if (lib::is_mysql_mode() && PL_VAR == name_type) { + // mysql can not access variable with '()', if found variable, adjust to udf. + name_type = PL_UDF; + access_ident.set_pl_udf(); } } - } - break; - case 3: { - db_name = q_name.access_idents_.at(0).access_name_; - pkg_name = q_name.access_idents_.at(1).access_name_; - CKECK_ROUTINE_EXISTS; - if (OB_SUCC(ret) && is_pl_udf) { - q_name.access_idents_.at(0).set_db_ns(); - q_name.access_idents_.at(1).set_pkg_ns(); - q_name.tbl_name_ = pkg_name; - q_name.access_idents_.at(2).set_pl_udf(); - q_name.database_name_ = db_name; - q_name.col_name_ = func_name; - } else { - ret = OB_SUCCESS; - // db.obj_type.routine, obj_type只能是一个udt type,db.obj.routine不可能, - // 因为obj要么定义在匿名块里面 - // 要么定义在package里面,这种是 db.package.obj.routine,是这个的. db.label.obj.routine有可能吗? - db_name = q_name.access_idents_.at(0).access_name_; - pkg_name = q_name.access_idents_.at(1).access_name_; - udt_name = pkg_name; - uint64_t db_id = OB_INVALID_ID; - if (OB_NOT_NULL(schema_checker)) { - if (OB_FAIL(schema_checker->get_database_id(session_info->get_effective_tenant_id(), - db_name, db_id))) { - LOG_WARN("failed to get db_id", K(db_name), K(pkg_name), K(ret)); - } else if (OB_FAIL(schema_checker->get_udt_id(session_info->get_effective_tenant_id(), - db_id, OB_INVALID_ID, udt_name, udt_id))) { - LOG_WARN("failed to get udt id", K(db_name), K(db_id), K(udt_name), K(ret)); + + if (OB_FAIL(ret)) { + } else if (name_type != PL_UDF + && func_node.num_child_ == 3 + && (func_node.children_[2]->type_ == T_DISTINCT || func_node.children_[2]->type_ == T_ALL)) { + //only pl agg udf allow have distinct/unique/all as common aggr. + ret = OB_DISTINCT_NOT_ALLOWED; + LOG_WARN("distinct/all/unique not allowed here", K(ret)); + } else if (is_new_key_word_used && PL_UDF != name_type) { + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("NEW keyword is only allowed for constructors", K(q_name)); + } + + if (OB_SUCC(ret)) { + switch (name_type) { + case SYS_FUNC: { // system function can not access by prefix, so here, access_idents_ must be 1. + ObRawExpr *func_expr = NULL; + if (0 == q_name.access_idents_.at(0).access_name_.case_compare("SQLERRM")) { + OZ (process_sqlerrm_node(&func_node, func_expr)); + } else if (0 == q_name.access_idents_.at(0).access_name_.case_compare("json_equal")) { + ret = OB_ERR_JSON_EQUAL_OUTSIDE_PREDICATE; + LOG_WARN("JSON_EQUAL used outside predicate", K(ret)); + } else { + OZ (process_fun_sys_node(&func_node, func_expr)); + } + CK (OB_NOT_NULL(func_expr)); + OX (access_ident.sys_func_expr_ = static_cast(func_expr)); + for (int64_t i = 0; OB_SUCC(ret) && i < func_expr->get_param_count(); ++i) { + std::pair param(func_expr->get_param_expr(i), 0); + OZ (access_ident.params_.push_back(param)); } } - if (OB_ERR_BAD_DATABASE == ret) { - ret = OB_SUCCESS; - } - if (OB_SUCC(ret)) { - if (OB_INVALID_ID == udt_id) { - is_pl_udf = false; + break; + case PL_UDF: { + ParseNode *udf_node = NULL; + ObRawExpr *udf_expr = NULL; + // 到这里仅仅知道function node应该是个udf node, 具体是哪个udf是不清楚的, 因此除了udf name,其他的值都填空 + if (OB_FAIL(ObResolverUtils::transform_func_sys_to_udf(&ctx_.expr_factory_.get_allocator(), + &func_node, + ObString(""), + ObString(""), + udf_node))) { + LOG_WARN("transform fun sys to udf node failed", K(ret)); + } else if (OB_FAIL(resolve_udf_node(udf_node, access_ident.udf_info_))) { + LOG_WARN("process udf node failed", K(ret)); + } else if (OB_ISNULL(udf_expr = access_ident.udf_info_.ref_expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid udf expr", K(ret)); } else { - CKECK_ROUTINE_EXISTS; - } - if (OB_SUCC(ret) && is_pl_udf) { - q_name.access_idents_.at(0).set_db_ns(); - q_name.access_idents_.at(1).set_udt_ns(); - q_name.tbl_name_ = udt_name; - q_name.access_idents_.at(2).set_pl_udf(); - q_name.database_name_ = db_name; - q_name.col_name_ = func_name; - } else { - ret = OB_SUCCESS; - // pkg.object.routine, it's possbile, - ObString udt_var_name; - int64_t compatible_mode = lib::is_oracle_mode() ? COMPATIBLE_ORACLE_MODE - : COMPATIBLE_MYSQL_MODE; - uint64_t pkg_id = OB_INVALID_ID; - OX (db_name = session_info->get_database_name()); - OX (pkg_name = q_name.access_idents_.at(0).access_name_); - OX (udt_var_name = q_name.access_idents_.at(1).access_name_); - if (OB_ISNULL(secondary_namespace) || OB_ISNULL(schema_checker)) { - // do nothing; - } else if (OB_FAIL(schema_checker->get_package_id(session_info->get_effective_tenant_id(), - db_name, pkg_name, compatible_mode, pkg_id))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get package unexpected", K(ret), K(pkg_name), K(db_name)); - } else if (OB_INVALID_ID == pkg_id) { - // do nothing - } else if (OB_FAIL(schema_checker->get_udt_id(session_info->get_effective_tenant_id(), - session_info->get_database_id(), - OB_INVALID_ID, udt_var_name, udt_id))) { - LOG_WARN("failed to get udt id", K(ret), K(udt_var_name), K(db_name)); - } else if (OB_INVALID_ID != udt_id) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected, object type defined inside package", K(ret), K(udt_var_name), K(db_name)); - // pkg.object_type.routine - // impossible, because a object type cann't be defined inside a package - } else if (FALSE_IT(secondary_namespace->try_resolve_udt_name(udt_var_name, udt_name, udt_id, pl::ObPLExternalNS::ExternalType::PKG_VAR, pkg_id))) { - } else if (OB_FAIL(schema_checker->get_udt_id(session_info->get_effective_tenant_id(), - session_info->get_database_id(), - OB_INVALID_ID, udt_name, udt_id))) { - LOG_WARN("failed to get udt id", K(db_name), K(db_id), K(udt_name), K(ret)); - } else if (OB_INVALID_ID != udt_id) { - pkg_name = udt_name; - CKECK_ROUTINE_EXISTS; - // pkg.object_instance.routine - if (OB_SUCC(ret) && is_pl_udf) { - q_name.access_idents_.at(0).set_pkg_ns(); - q_name.access_idents_.at(1).set_udt_ns(); - q_name.access_idents_.at(2).set_pl_udf(); - q_name.database_name_ = q_name.access_idents_.at(0).access_name_; - q_name.tbl_name_ = udt_name; - q_name.col_name_ = func_name; + access_ident.udf_info_.is_new_keyword_used_ = is_new_key_word_used; + if (func_node.num_child_ == 3 && func_node.children_[2]->type_ == T_DISTINCT) { + static_cast(udf_expr)->set_is_aggr_udf_distinct(true); + } + for (int64_t i = 0; OB_SUCC(ret) && i < udf_expr->get_param_count(); ++i) { + std::pair param(udf_expr->get_param_expr(i), 0); + if (OB_FAIL(access_ident.params_.push_back(param))) { + LOG_WARN("failed to push access_ident parameters", K(ret), K(access_ident)); } } } } + break; + case TYPE_METHOD: { + if (0 == access_ident.access_name_.case_compare("LIMIT") + || 0 == access_ident.access_name_.case_compare("COUNT")) { + // limit and count has no arguments. + if (func_node.num_child_ > 1 && OB_NOT_NULL(func_node.children_[1])) { + ret = OB_ERR_CALL_WRONG_ARG; + LOG_WARN("wrong number or types of arguments in call to procedure", K(ret), K(access_ident)); + LOG_USER_ERROR(OB_ERR_CALL_WRONG_ARG, access_ident.access_name_.length(), access_ident.access_name_.ptr()); + } + break; + } + } // fall through. continue resolve parameter expression of type method. + case PL_VAR: { + if (func_node.num_child_ != 2 || OB_ISNULL(func_node.children_[1])) { + ret = OB_ERR_NO_FUNCTION_EXIST; + LOG_WARN("PLS-00222: no function with name 'string' exists in this scope", + K(ret), K(func_node.num_child_), K(access_ident)); + } else if (T_EXPR_LIST != func_node.children_[1]->type_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("not expr list node!", K(func_node.children_[1]->type_), K(func_node.children_[1]->num_child_), K(ret)); + } else if (func_node.children_[1]->num_child_ != 1) { + ret = OB_ERR_TABLE_SINGLE_INDEX; + LOG_WARN("PLS-00316: PL/SQL TABLEs must use a single index", K(ret), K(func_node.children_[1]->num_child_)); + } else { + const ParseNode *expr_node = func_node.children_[1]->children_[0]; + ObRawExpr *index_expr = NULL; + if (OB_FAIL(ctx_.parents_expr_info_.add_member(IS_PL_ACCESS_IDX))) { + LOG_WARN("failed to add parents expr info", K(ret)); + } else if (OB_FAIL(SMART_CALL(recursive_resolve(expr_node, index_expr)))) { + LOG_WARN("failed to recursive resolve", K(ret)); + } else { + std::pair param(index_expr, 0); + if (OB_FAIL(access_ident.params_.push_back(param))) { + LOG_WARN("push back error", K(ret)); + } + } + ctx_.parents_expr_info_.del_member(IS_PL_ACCESS_IDX); + } + } + break; + default: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected name type", K(ret), K(name_type), K(ctx_.current_scope_), K(q_name)); + } break; + } } } - break; - default: { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("what happend?", K(q_name), K(ret)); + } + return ret; +} + +int ObRawExprResolverImpl::resolve_left_node_of_obj_access_idents(const ParseNode &left_node, ObQualifiedName &q_name) +{ + int ret = OB_SUCCESS; + if (T_QUESTIONMARK == left_node.type_) { + // quesitonmark in obj access ref muse be top node + CK (q_name.access_idents_.count() <= 0); + OZ (q_name.access_idents_.push_back(ObObjAccessIdent(ObString(""), left_node.value_))); + OX (q_name.access_idents_.at(q_name.access_idents_.count() - 1).set_pl_var()); + } else if (T_IDENT == left_node.type_) { + ObString ident_name(static_cast(left_node.str_len_), left_node.str_value_); + if (ident_name.empty() && T_PL_SCOPE == ctx_.current_scope_ && lib::is_oracle_mode()) { + ret = OB_ERR_IDENT_EMPTY; + LOG_WARN("Identifier cannot be an empty string", K(ret), K(ident_name)); } - break; + OZ (q_name.access_idents_.push_back(ObObjAccessIdent(ident_name, OB_INVALID_INDEX)), K(q_name)); + // TODO: may move this check to pl resovler ? + if (OB_SUCC(ret) + && T_PL_SCOPE == ctx_.current_scope_ + && q_name.access_idents_.count() > 1 + && (0 == ident_name.case_compare("NEXT") + || 0 == ident_name.case_compare("PRIOR") + || 0 == ident_name.case_compare("EXISTS")) + && lib::is_oracle_mode()) { + AccessNameType name_type = UNKNOWN; + OZ (check_name_type(q_name, ctx_.current_scope_, name_type)); + if (OB_SUCC(ret) && name_type == TYPE_METHOD) { + ret = OB_ERR_CALL_WRONG_ARG; + LOG_WARN("wrong number or types of arguments in call to procedure", K(ret), K(q_name)); + LOG_USER_ERROR(OB_ERR_CALL_WRONG_ARG, ident_name.length(), ident_name.ptr()); + } } - } else { /*do nothing*/ } - CANCLE_LOG_CHECK_MODE(); - return ret; + } else if (T_FUN_SYS == left_node.type_) { + OZ (resolve_func_node_of_obj_access_idents(left_node, q_name)); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("left node of obj access ref node not T_IDENT/T_QUESTIONMARK/T_FUN_SYS", K(ret), K(left_node.type_)); + } + return ret; +} + +int ObRawExprResolverImpl::resolve_right_node_of_obj_access_idents(const ParseNode &right_node, ObQualifiedName &q_name) +{ + int ret = OB_SUCCESS; + if (T_OBJ_ACCESS_REF == right_node.type_) { + // example: a(1).b(1), here, we resolve '.b(1)' + OZ (resolve_obj_access_idents(right_node, q_name), K(q_name)); + } else { + // example: a(1)(2) here, we resolve '(2)' + const ParseNode *element_list = &right_node; + CK (OB_LIKELY(!q_name.access_idents_.empty())); + for (int64_t i = 0; OB_SUCC(ret) && i < element_list->num_child_; ++i) { + ObObjAccessIdent &access_ident = q_name.access_idents_.at(q_name.access_idents_.count() - 1); + ObRawExpr *param_expr = NULL; + int64_t param_level = OB_INVALID_INDEX; + CK (OB_NOT_NULL(element_list->children_[i])); + OZ (SMART_CALL(recursive_resolve(element_list->children_[i], param_expr))); + if (OB_FAIL(ret)) { + } else if (access_ident.params_.empty()) { + if (access_ident.is_pl_var() && access_ident.access_name_.empty()) { + param_level = 0; // :a(index) + } else { + param_level = 1; // f()(index) + } + } else { + param_level = access_ident.params_.at(access_ident.params_.count() - 1).second + 1; + } + OZ (access_ident.params_.push_back(std::make_pair(param_expr, param_level)), KPC(param_expr), K(param_level)); + } + } + return ret; } int ObRawExprResolverImpl::resolve_obj_access_idents(const ParseNode &node, ObQualifiedName &q_name) @@ -1914,232 +1897,16 @@ int ObRawExprResolverImpl::resolve_obj_access_idents(const ParseNode &node, ObQu int ret = OB_SUCCESS; if (OB_UNLIKELY(node.type_ != T_OBJ_ACCESS_REF) || OB_UNLIKELY(node.num_child_ != 2)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid node type", K_(node.type), K(node.num_child_), K(ret)); - } else { - //1、首先解T_OBJ_ACCESS_REF的左支,左支只可能是T_IDENT或T_FUN_SYS - if (OB_ISNULL(node.children_[0])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("node is NULL", K(node.num_child_)); - } else if (T_IDENT == node.children_[0]->type_) { - ObString ident_name(static_cast(node.children_[0]->str_len_), node.children_[0]->str_value_); - if (lib::is_oracle_mode() - && T_PL_SCOPE == ctx_.current_scope_ - && ident_name.empty()) { - ret = OB_ERR_IDENT_EMPTY; - LOG_WARN("Identifier cannot be an empty string", K(ret), K(ident_name)); - } - OZ (q_name.access_idents_.push_back(ObObjAccessIdent(ident_name, OB_INVALID_INDEX)), q_name); - if (OB_SUCC(ret) - && T_PL_SCOPE == ctx_.current_scope_ - && q_name.access_idents_.count() > 1 - && (0 == ident_name.case_compare("NEXT") - || 0 == ident_name.case_compare("PRIOR") - || 0 == ident_name.case_compare("EXISTS")) - && lib::is_oracle_mode()) { - AccessNameType name_type = UNKNOWN; - OZ (check_name_type(q_name, ctx_.current_scope_, name_type)); - if (OB_SUCC(ret) && name_type == TYPE_METHOD) { - ret = OB_ERR_CALL_WRONG_ARG; - LOG_WARN("wrong number or types of arguments in call to procedure", K(ret), K(q_name)); - LOG_USER_ERROR(OB_ERR_CALL_WRONG_ARG, ident_name.length(), ident_name.ptr()); - } - } - } else if (T_QUESTIONMARK == node.children_[0]->type_) { - if (q_name.access_idents_.count() > 0) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("quesitonmark in obj access ref muse be top node.", - K(ret), K(q_name.access_idents_)); - } else { - ObObjAccessIdent ident(ObString(""), node.children_[0]->value_); - OX (ident.set_pl_var()); - OZ (q_name.access_idents_.push_back(ident)); - } - } else if (T_FUN_SYS == node.children_[0]->type_) { - const ParseNode &func_node = *(node.children_[0]); - if (OB_ISNULL(func_node.children_[0])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("node is NULL", K(node.num_child_), K(ret)); - } else { - ObString ident_name(static_cast(func_node.children_[0]->str_len_), func_node.children_[0]->str_value_); - - // first bit in value_ of T_FUN_SYS node is used to mark NEW keyword, - // value_ & 0x1 == 1: not used, - // value_ & 0x1 == 0: used, - // refer to sql_parser_oracle_mode.y - bool is_new_key_word_used = !(func_node.value_ & 0x1); - - if (lib::is_oracle_mode() - && T_PL_SCOPE == ctx_.current_scope_ - && ident_name.empty()) { - ret = OB_ERR_IDENT_EMPTY; - LOG_WARN("Identifier cannot be an empty string", K(ret), K(ident_name)); - } - OZ (q_name.access_idents_.push_back( - ObObjAccessIdent(ident_name, OB_INVALID_INDEX)), K(ident_name)); - - if (OB_SUCC(ret)) { - ObObjAccessIdent &access_ident = q_name.access_idents_.at(q_name.access_idents_.count() - 1); - AccessNameType name_type = UNKNOWN; - if (OB_FAIL(check_name_type(q_name, ctx_.current_scope_, name_type))) { - LOG_WARN("check name type failed", K(ret), K(q_name)); - //only pl agg udf allow have distinct/unique/all as common aggr. - } else if (name_type != PL_UDF - && func_node.num_child_ == 3 - && (func_node.children_[2]->type_ == T_DISTINCT - || func_node.children_[2]->type_ == T_ALL)) { - ret = OB_DISTINCT_NOT_ALLOWED; - LOG_WARN("distinct/all/unique not allowed here", K(ret)); - } else if (is_new_key_word_used && PL_UDF != name_type) { - ret = OB_ERR_PARSER_SYNTAX; - LOG_WARN("NEW keyword is only allowed for constructors", K(q_name)); - } else { - switch (name_type) { - case SYS_FUNC: { - ObRawExpr *func_expr = NULL; - if (0 == q_name.access_idents_.at(0).access_name_.case_compare("SQLERRM")) { - OZ (process_sqlerrm_node(&func_node, func_expr)); - } else if (0 == q_name.access_idents_.at(0).access_name_.case_compare("json_equal")) { - ret = OB_ERR_JSON_EQUAL_OUTSIDE_PREDICATE; - } else { - OZ (process_fun_sys_node(&func_node, func_expr)); - } - CK (OB_NOT_NULL(func_expr)); - OX (access_ident.sys_func_expr_ = static_cast(func_expr)); - for (int64_t i = 0; OB_SUCC(ret) && i < func_expr->get_param_count(); ++i) { - std::pair param(func_expr->get_param_expr(i), 0); - OZ (access_ident.params_.push_back(param)); - } - } - break; - case PL_UDF: { - ParseNode *udf_node = NULL; - ObRawExpr *udf_expr = NULL; - bool is_member = false; - int64_t cnt = q_name.access_idents_.count(); - ParseNode *udt_udf_self_param_node = NULL; - ObRawExpr *self_param = NULL; - access_ident.udf_info_.is_new_keyword_used_ = is_new_key_word_used; - if (OB_FAIL(ObResolverUtils::transform_func_sys_to_udf(&ctx_.expr_factory_.get_allocator(), - &func_node, - q_name.database_name_, - q_name.tbl_name_, - udf_node))) { - LOG_WARN("transform fun sys to udf node failed", K(ret)); - } else if (OB_FAIL(resolve_udf_info(udf_node, false, access_ident.udf_info_, - udt_udf_self_param_node, self_param))) { - LOG_WARN("process udf node failed", K(ret)); - } else if (OB_ISNULL(udf_expr = access_ident.udf_info_.ref_expr_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid udf expr", K(ret)); - } else { - if (func_node.num_child_ == 3 && func_node.children_[2]->type_ == T_DISTINCT) { - static_cast(udf_expr)->set_is_aggr_udf_distinct(true); - } - for (int64_t i = 0; OB_SUCC(ret) && i < udf_expr->get_param_count(); ++i) { - std::pair param(udf_expr->get_param_expr(i), 0); - if (OB_FAIL(access_ident.params_.push_back(param))) { - LOG_WARN("push back error", K(ret)); - } - } - if (OB_SUCC(ret) && 3 == cnt) { - bool is_pkg_ns = q_name.access_idents_.at(0).is_pkg_ns(); - bool is_udt_ns = q_name.access_idents_.at(1).is_udt_ns(); - bool is_pl_udf = q_name.access_idents_.at(2).is_pl_udf(); - access_ident.udf_info_.is_udt_udf_inside_pkg_ = is_pkg_ns && is_udt_ns && is_pl_udf; - } - } - } - break; - case TYPE_METHOD: { - if (0 == access_ident.access_name_.case_compare("LIMIT") - || 0 == access_ident.access_name_.case_compare("COUNT")) { - if (func_node.num_child_ > 1 && OB_NOT_NULL(func_node.children_[1])) { - ret = OB_ERR_CALL_WRONG_ARG; - LOG_WARN("wrong number or types of arguments in call to procedure", K(ret), K(access_ident)); - LOG_USER_ERROR(OB_ERR_CALL_WRONG_ARG, - access_ident.access_name_.length(), - access_ident.access_name_.ptr()); - } - break; - } else { - // fall through. - } - } - case PL_VAR: { - if (func_node.num_child_ != 2 || OB_ISNULL(func_node.children_[1])) { - ret = OB_ERR_NO_FUNCTION_EXIST; - LOG_WARN("PLS-00222: no function with name 'string' exists in this scope", - K(ret), K(func_node.num_child_), K(access_ident)); - } else if (T_EXPR_LIST != func_node.children_[1]->type_) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("not expr list node!", K(func_node.children_[1]->type_), K(func_node.children_[1]->num_child_), K(ret)); - } else if (func_node.children_[1]->num_child_ != 1) { - ret = OB_ERR_TABLE_SINGLE_INDEX; - LOG_WARN("PLS-00316: PL/SQL TABLEs must use a single index", K(ret), K(func_node.children_[1]->num_child_)); - } else { - const ParseNode *expr_node = func_node.children_[1]->children_[0]; - ObRawExpr *index_expr = NULL; - if (OB_FAIL(ctx_.parents_expr_info_.add_member(IS_PL_ACCESS_IDX))) { - LOG_WARN("failed to add parents expr info", K(ret)); - } else if (OB_FAIL(SMART_CALL(recursive_resolve(expr_node, index_expr)))) { - LOG_WARN("failed to recursive resolve", K(ret)); - } else { - std::pair param(index_expr, 0); - if (OB_FAIL(access_ident.params_.push_back(param))) { - LOG_WARN("push back error", K(ret)); - } - } - ctx_.parents_expr_info_.del_member(IS_PL_ACCESS_IDX); - } - } - break; - case UNKNOWN: - case DLL_UDF: - case DB_NS: - case PKG_NS: - case REC_ELEM: - default: { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("node is NULL", K(q_name), K(ctx_.current_scope_), K(name_type)); - } break; - } - } - } - } - } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("Invalid node type", K(node.children_[0]->type_), K(ret)); - } - - //2、然后解T_OBJ_ACCESS_REF的右支,右支只可能是T_OBJ_ACCESS_REF('.'的情况)或T_EXPR_LIST('()'的情况) - if (OB_SUCC(ret) && node.children_[1] != NULL) { - if (T_OBJ_ACCESS_REF == node.children_[1]->type_) { - OZ (resolve_obj_access_idents(*(node.children_[1]), q_name), K(q_name)); - } else { - const ParseNode *element_list = node.children_[1]; - CK (OB_LIKELY(!q_name.access_idents_.empty())); - for (int64_t i = 0; OB_SUCC(ret) && i < element_list->num_child_; ++i) { - ObObjAccessIdent &access_ident = q_name.access_idents_.at(q_name.access_idents_.count() - 1); - ObRawExpr *param_expr = NULL; - int64_t param_level = OB_INVALID_INDEX; - CK (OB_NOT_NULL(element_list->children_[i])); - OZ (SMART_CALL(recursive_resolve(element_list->children_[i], param_expr))); - if (OB_FAIL(ret)) { - } else if (access_ident.params_.empty()) { - if (access_ident.is_pl_var() && access_ident.access_name_.empty()) { - // :a(index) - param_level = 0; - } else { - // f()(index) - param_level = 1; - } - } else { - param_level = access_ident.params_.at(access_ident.params_.count() - 1).second + 1; - } - OZ (access_ident.params_.push_back(std::make_pair(param_expr, param_level)), - KPC(param_expr), K(param_level)); - } - } + LOG_WARN("invalid obj access ref node type", K(ret), K(node.type_), K(node.num_child_)); + } else if (OB_ISNULL(node.children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("left node of obj access is null", K(ret), K(node.type_), KP(node.children_)); + } else if (OB_FAIL(resolve_left_node_of_obj_access_idents(*(node.children_[0]), q_name))) { + LOG_WARN("failed to resolve left node of obj access", K(ret), K(q_name)); + } + if (OB_SUCC(ret) && OB_NOT_NULL(node.children_[1])) { + if (OB_FAIL(resolve_right_node_of_obj_access_idents(*(node.children_[1]), q_name))) { + LOG_WARN("failed to resolve right node of obj access", K(ret)); } } return ret; @@ -5735,10 +5502,10 @@ int ObRawExprResolverImpl::process_fun_sys_node(const ParseNode *node, ObRawExpr // deal with exceptions if (0 == name.case_compare("nextval")) { ret = OB_ERR_FUNCTION_UNKNOWN; - LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, name.length(), name.ptr()); + LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, "FUNCTION", name.length(), name.ptr()); } else if (T_FROM_SCOPE != ctx_.current_scope_ && 0 == name.case_compare("generator")) { ret = OB_ERR_FUNCTION_UNKNOWN; - LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, name.length(), name.ptr()); + LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, "FUNCTION", name.length(), name.ptr()); } } @@ -5912,11 +5679,7 @@ int ObRawExprResolverImpl::process_sys_func_params(ObSysFunRawExpr &func_expr, i return ret; } -int ObRawExprResolverImpl::resolve_udf_info(const ParseNode *node, - bool record_udf_info, - ObUDFInfo &udf_info, - ParseNode *extra_param, - ObRawExpr *extra_expr) +int ObRawExprResolverImpl::resolve_udf_node(const ParseNode *node, ObUDFInfo &udf_info) { int ret = OB_SUCCESS; ObUDFRawExpr *func_expr = NULL; @@ -5932,7 +5695,9 @@ int ObRawExprResolverImpl::resolve_udf_info(const ParseNode *node, } else if (OB_ISNULL(node->children_[0])) { ret = OB_ERR_PARSER_SYNTAX; LOG_WARN("invalid function name node", K(ret)); - } else if (OB_FAIL(ObResolverUtils::resolve_udf(node, ctx_.case_mode_, udf_info))) { + } else if (FALSE_IT(new(&udf_info)ObUDFInfo())) { + // reinit ObUDFInfo, resolve_qname may call this function mutli times. + } else if (OB_FAIL(ObResolverUtils::resolve_udf_name_by_parse_node(node, ctx_.case_mode_, udf_info))) { LOG_WARN("fail to result udf", K(ret)); } else if (OB_FAIL(ctx_.expr_factory_.create_raw_expr(T_FUN_UDF, func_expr))) { LOG_WARN("fail to create raw expr", K(ret)); @@ -5944,25 +5709,6 @@ int ObRawExprResolverImpl::resolve_udf_info(const ParseNode *node, ret = OB_ERR_PARSER_SYNTAX; LOG_WARN("invalid paramters node", K(ret), K(node->children_[1])); } else { - // 先处理udt member function的self参数,self参数是第一个参数 - if (OB_SUCC(ret) && OB_NOT_NULL(extra_param)) { - ObRawExpr *param_expr = NULL; - if (OB_FAIL(recursive_resolve(extra_param, param_expr))) { - LOG_WARN("fail to recursive resolve udf parameters", K(ret), K(extra_param)); - } else if (OB_FAIL(func_expr->add_param_expr(param_expr))) { - LOG_WARN("fail to add param expr", K(ret), K(param_expr)); - } else if (OB_FAIL(param_expr->add_flag(IS_UDT_UDF_SELF_PARAM))) { - LOG_WARN("fail to add flag", K(ret)); - } else { - udf_info.udf_param_num_++; - udf_info.is_contain_self_param_ = true; - } - } - if (OB_SUCC(ret) && OB_ISNULL(extra_param) && OB_NOT_NULL(extra_expr)) { - OZ (func_expr->add_param_expr(extra_expr)); - udf_info.udf_param_num_++; - udf_info.is_contain_self_param_ = true; - } ObRawExpr *param_expr = NULL; int32_t num_child = node->children_[1]->num_child_; bool has_assign_expr = false; @@ -6007,61 +5753,14 @@ int ObRawExprResolverImpl::resolve_udf_info(const ParseNode *node, } } } - } else { - // if param is null, such as routine(), we also have to mock a param - if (OB_SUCC(ret) && OB_NOT_NULL(extra_param)) { - ObRawExpr *param_expr = NULL; - if (OB_FAIL(recursive_resolve(extra_param, param_expr))) { - LOG_WARN("fail to recursive resolve udf parameters", K(ret), K(extra_param)); - } else if (OB_FAIL(func_expr->add_param_expr(param_expr))) { - LOG_WARN("fail to add param expr", K(ret), K(param_expr)); - } else if (OB_FAIL(param_expr->add_flag(IS_UDT_UDF_SELF_PARAM))) { - LOG_WARN("fail to add flag", K(ret)); - } else { - udf_info.udf_param_num_++; - udf_info.is_contain_self_param_ = true; - } - } - if (OB_SUCC(ret) && OB_ISNULL(extra_param) && OB_NOT_NULL(extra_expr)) { - OZ (func_expr->add_param_expr(extra_expr)); - udf_info.udf_param_num_++; - udf_info.is_contain_self_param_ = true; - } } if (OB_SUCC(ret)) { func_expr->set_func_name(udf_info.udf_name_); udf_info.ref_expr_ = func_expr; - udf_info.ref_expr_->set_is_udt_udf(udf_info.is_udt_udf_); - if (record_udf_info) { - if (OB_FAIL(ctx_.udf_info_->push_back(udf_info))) { - LOG_WARN("add user defined func failed", K(ret)); - } else if (ctx_.query_ctx_ != NULL) { - ctx_.query_ctx_->has_udf_ = true; - for (int64_t i = 0; OB_SUCC(ret) && i < ctx_.query_ctx_->all_user_variable_.count(); ++i) { - if (OB_ISNULL(ctx_.query_ctx_->all_user_variable_.at(i))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get null user var expr", K(ret)); - } else { - ctx_.query_ctx_->all_user_variable_.at(i)->set_query_has_udf(true); - } - } - } - } } return ret; } -int ObRawExprResolverImpl::process_udf_node(const ParseNode *node, bool record_udf_info, ObRawExpr *&expr) -{ - int ret = OB_SUCCESS; - ObUDFInfo udf_info; - if (OB_FAIL(resolve_udf_info(node, record_udf_info, udf_info))) { - LOG_WARN("resolve udf info failed", K(ret)); - } else { - expr = udf_info.ref_expr_; - } - return ret; -} int ObRawExprResolverImpl::not_int_check(const ObRawExpr *expr) { diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h index 095a9a99b..54d079f06 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h @@ -43,11 +43,14 @@ public: int check_first_node(const ParseNode *node); static int check_sys_func(ObQualifiedName &q_name, bool &is_sys_func); - static int check_pl_udf(ObQualifiedName &q_name, const ObSQLSessionInfo *session_info, + static int check_pl_udf(ObQualifiedName &q_name, + const ObSQLSessionInfo *session_info, ObSchemaChecker *schema_checker, pl::ObPLBlockNS *secondary_namespace, - bool &is_pl_udf); - + pl::ObProcType &proc_type); + int resolve_func_node_of_obj_access_idents(const ParseNode &func_node, ObQualifiedName &q_name); + int check_name_type( + ObQualifiedName &q_name, ObStmtScope scope, AccessNameType &type); // types and constants private: // disallow copy @@ -161,9 +164,7 @@ private: int process_cursor_attr_node(const ParseNode &node, ObRawExpr *&expr); int process_obj_access_node(const ParseNode &node, ObRawExpr *&expr); int resolve_obj_access_idents(const ParseNode &node, ObQualifiedName &q_name); - int check_name_type(ObQualifiedName &q_name, ObStmtScope scope, AccessNameType &type); int check_pl_variable(ObQualifiedName &q_name, bool &is_pl_var); - int check_dll_udf(ObQualifiedName &q_name, bool &is_dll_udf); int is_explict_func_expr(const ParseNode &node, bool &is_func); int check_pseudo_column_exist(ObItemType type, ObPseudoColumnRawExpr *&expr); int process_pseudo_column_node(const ParseNode &node, ObRawExpr *&expr); @@ -177,9 +178,7 @@ private: inline bool is_prior_expr_valid_scope(ObStmtScope scope) const; static bool should_not_contain_window_clause(const ObItemType func_type); static bool should_contain_order_by_clause(const ObItemType func_type); - int process_udf_node(const ParseNode *node, bool record_udf_info, ObRawExpr *&expr); - int resolve_udf_info(const ParseNode *node, bool record_udf_info, ObUDFInfo &udf_info, - ParseNode *extra_param = NULL, ObRawExpr *extar_expr = NULL); + int resolve_udf_node(const ParseNode *node, ObUDFInfo &udf_info); int process_sqlerrm_node(const ParseNode *node, ObRawExpr *&expr); int process_plsql_var_node(const ParseNode *node, ObRawExpr *&expr); int process_call_param_node(const ParseNode *node, ObRawExpr *&expr); @@ -210,6 +209,11 @@ private: int reset_aggr_sort_nulls_first(ObIArray &aggr_sort_item); inline void set_udf_param_syntax_err(const bool val) { is_udf_param_syntax_err_ = val; } inline bool get_udf_param_syntax_err() { return is_udf_param_syntax_err_; } + + int resolve_left_node_of_obj_access_idents(const ParseNode &node, ObQualifiedName &q_name); + int resolve_right_node_of_obj_access_idents(const ParseNode &node, ObQualifiedName &q_name); + +private: // data members ObExprResolveContext &ctx_; bool is_contains_assignment_; diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index d5f794ef2..44043e9ef 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -729,7 +729,6 @@ int ObRawExprUtils::resolve_udf_common_info(const ObString &db_name, OX (udf_raw_expr->set_pkg_body_udf(is_pkg_body_udf)); OX (udf_raw_expr->set_type_id(type_id)); OX (udf_raw_expr->set_is_aggregate_udf(is_pl_agg)); - LOG_DEBUG("resolve_udf_common_info!!!", K(type_id), K(is_pl_agg)); return ret; } @@ -787,11 +786,10 @@ int ObRawExprUtils::resolve_udf_param_types(const ObIRoutineInfo* func_info, OX (udf_raw_expr->set_is_return_sys_cursor(true)); } SET_RES_TYPE_BY_PL_TYPE(result_type, ret_pl_type); - if (lib::is_oracle_mode() - && OB_INVALID_ID != static_cast (func_info)->get_package_id() - && is_sys_tenant( - pl::get_tenant_id_by_object_id( - static_cast(func_info)->get_package_id())) + if (OB_SUCC(ret) + && lib::is_oracle_mode() + && OB_INVALID_ID != func_info->get_package_id() + && is_sys_tenant(pl::get_tenant_id_by_object_id(func_info->get_package_id())) && OB_NOT_NULL(ret_pl_type.get_data_type()) && !(ret_pl_type.get_data_type()->get_meta_type().get_type() == ObLongTextType) && ob_is_string_type(ret_pl_type.get_data_type()->get_meta_type().get_type())) { @@ -803,13 +801,7 @@ int ObRawExprUtils::resolve_udf_param_types(const ObIRoutineInfo* func_info, OX (udf_raw_expr->set_pls_type(ret_pl_type.get_pl_integer_type())); if (OB_FAIL(ret)) { } else if (!ret_pl_type.is_obj_type()) { - // if (ret_pl_type.is_udt_type()) { - OX (result_type.set_udt_id(ret_pl_type.get_user_type_id())); - // } else { - // ret = OB_NOT_SUPPORTED; - // LOG_WARN("not supported other type as function return type", - // K(ret), K(ret_pl_type)); - // } + OX (result_type.set_udt_id(ret_pl_type.get_user_type_id())); } else if (result_type.is_enum_or_set()) { const ObRoutineParam* r_param = static_cast(ret_param); CK (OB_NOT_NULL(r_param)); @@ -989,7 +981,8 @@ int ObRawExprUtils::resolve_udf_param_exprs(ObResolverParams ¶ms, OZ (udf_raw_expr->add_param_expr(param_exprs.at(i))); OZ (udf_raw_expr->add_param_name(param_names.at(i))); } - CK ((udf_info.udf_param_num_ + param_exprs.count()) == udf_raw_expr->get_param_count()); + OV ((udf_info.udf_param_num_ + param_exprs.count()) == udf_raw_expr->get_param_count(), + OB_ERR_UNEXPECTED, K(udf_info.udf_param_num_), K(param_exprs.count()), K(udf_raw_expr->get_param_count())); } if (OB_SUCC(ret) && (func_info->get_param_count() != udf_info.udf_param_num_ + param_exprs.count())) { @@ -1125,7 +1118,7 @@ do { } } OZ (pl::ObPLResolver::resolve_nocopy_params(func_info, udf_info)); - CK (udf_raw_expr->get_params_desc().count() == udf_raw_expr->get_param_count()); + OV (udf_raw_expr->get_params_desc().count() == udf_raw_expr->get_param_count(), OB_ERR_UNEXPECTED, KPC(udf_raw_expr)); return ret; } @@ -1152,135 +1145,29 @@ int ObRawExprUtils::rebuild_expr_params(ObUDFInfo &udf_info, return ret; } -int ObRawExprUtils::init_udf_info(ObResolverParams ¶ms, - ObUDFInfo &udf_info) +int ObRawExprUtils::resolve_udf_info(common::ObIAllocator &allocator, + sql::ObRawExprFactory &expr_factory, + sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + ObUDFInfo &udf_info) { int ret = OB_SUCCESS; - ObString db_name; - ObString package_name; - ObString udf_name; - CK (OB_NOT_NULL(params.schema_checker_)); - CK (OB_NOT_NULL(params.session_info_)); - CK (OB_NOT_NULL(params.allocator_)); - CK (OB_NOT_NULL(GCTX.sql_proxy_)); - OZ (ObResolverUtils::resolve_udf_name(*params.schema_checker_, - *params.session_info_, - udf_info, - db_name, - package_name, - udf_name)); - if (OB_SUCC(ret) && db_name.empty()) { - db_name = params.session_info_->get_database_name(); - } - if (OB_SUCC(ret) && db_name.empty()) { - ret = OB_ERR_NO_DB_SELECTED; - LOG_WARN("no database selected", K(ret), K(db_name)); - } - if(OB_SUCC(ret)) { - const ObPackageInfo *package_info = NULL; - const ObRoutineInfo *func_info = NULL; - ObSEArray expr_params; - if (OB_FAIL(rebuild_expr_params(udf_info, params.expr_factory_, expr_params))) { - LOG_WARN("failed to rebuild expr params", K(ret), K(udf_info)); - } else if (OB_FAIL(ObResolverUtils::get_routine(params, - params.session_info_->get_effective_tenant_id(), - params.session_info_->get_database_name(), - db_name, - package_name, - udf_name, - ROUTINE_FUNCTION_TYPE, - expr_params, - func_info))) { - ret = OB_ERR_SP_DOES_NOT_EXIST == ret ? OB_ERR_FUNCTION_UNKNOWN : ret; - LOG_WARN("failed to get routine info", - K(db_name), K(udf_info.udf_package_), K(udf_info.udf_name_), K(ret)); - } else if (OB_ISNULL(func_info)) { - ret = OB_ERR_FUNCTION_UNKNOWN; - LOG_WARN("stored function not exists", K(ret), K(udf_info.udf_name_), K(db_name)); - LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, udf_info.udf_name_.length(), udf_info.udf_name_.ptr()); - } else if (!func_info->is_function()) { - ret = OB_ERR_FUNCTION_UNKNOWN; - LOG_WARN("user define function must be stored function, but got a procedure", - K(ret), K(db_name), K(package_name), K(udf_name), K(func_info->is_function())); - LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, udf_info.udf_name_.length(), udf_info.udf_name_.ptr()); + pl::ObPLPackageGuard dummy_pkg_guard(session_info.get_effective_tenant_id()); + pl::ObPLResolver pl_resolver(allocator, + session_info, + schema_guard, + dummy_pkg_guard, + *GCTX.sql_proxy_, + expr_factory, + NULL, + false); + HEAP_VAR(pl::ObPLFunctionAST, func_ast, allocator) { + ObSEArray access_idxs; + if (OB_FAIL(pl_resolver.init(func_ast))) { + LOG_WARN("pl resolver init failed", K(ret)); + } else if (OB_FAIL(pl_resolver.resolve_udf_info(udf_info, access_idxs, func_ast))) { + LOG_WARN("failed to resolve udf info", K(ret)); } - if (OB_SUCC(ret) && func_info->is_udt_routine() && !func_info->is_udt_static_routine()) { - ret = OB_ERR_CALL_WRONG_ARG; - LOG_USER_ERROR(OB_ERR_CALL_WRONG_ARG, func_info->get_routine_name().length(), - func_info->get_routine_name().ptr()); - } - if (OB_SUCC(ret) && func_info->is_udt_routine()) { - udf_info.is_udt_udf_ = true; - } - if (OB_SUCC(ret) && OB_INVALID_ID != func_info->get_package_id()) { - CK (OB_NOT_NULL(params.schema_checker_)); - CK (OB_NOT_NULL(params.schema_checker_->get_schema_guard())); - OZ (params.schema_checker_->get_schema_guard() - ->get_package_info(func_info->get_tenant_id(), - func_info->get_package_id(), package_info)); - CK (OB_NOT_NULL(package_info)); - } - OZ (resolve_udf_common_info(db_name, - package_name, - OB_INVALID_ID == func_info->get_package_id() - ? func_info->get_routine_id() - : func_info->get_subprogram_id(), - func_info->get_package_id(), - ObArray(), - OB_INVALID_ID == func_info->get_package_id() - ? func_info->get_schema_version() - : common::OB_INVALID_VERSION, - OB_INVALID_ID == func_info->get_package_id() - ? common::OB_INVALID_VERSION - : package_info->get_schema_version(), - func_info->is_deterministic(), - func_info->is_parallel_enable(), - false, /*is_pkg_body_udf*/ - func_info->is_aggregate(), - func_info->get_type_id(), - udf_info)); - OZ (resolve_udf_param_types(func_info, - *(params.schema_checker_->get_schema_mgr()), - *(params.session_info_), - *(params.allocator_), - *(GCTX.sql_proxy_), - udf_info)); - OZ (resolve_udf_param_exprs(params, func_info, udf_info)); - } - return ret; -} - -int ObRawExprUtils::init_udfs_info(ObResolverParams ¶ms, - ObIArray &udfs_info) -{ - int ret = OB_SUCCESS; - for (int64_t i = 0; OB_SUCC(ret) && i < udfs_info.count(); ++i) { - if (OB_FAIL(init_udf_info(params, udfs_info.at(i)))) { - LOG_WARN("init user define function failed", K(ret)); - } - } - return ret; -} - -int ObRawExprUtils::init_udf_info(pl::ObPLResolveCtx &resolve_ctx, - sql::ObRawExprFactory &expr_factory, - ObUDFInfo &udf_info) -{ - int ret = OB_SUCCESS; - ObResolverParams params; - ObSchemaChecker schema_checker; - if (OB_FAIL(schema_checker.init(resolve_ctx.schema_guard_))) { - LOG_WARN("failed to init schema checker", K(ret)); - } else { - params.schema_checker_ = &(schema_checker); - params.session_info_ = &(resolve_ctx.session_info_); - params.allocator_ = &(resolve_ctx.allocator_); - params.is_prepare_protocol_ = resolve_ctx.is_prepare_protocol_; - params.expr_factory_ = &(expr_factory); - params.sql_proxy_ = &(resolve_ctx.sql_proxy_); - } - if (OB_SUCC(ret) && OB_FAIL(init_udf_info(params, udf_info))) { - LOG_WARN("failed to init udf info", K(ret)); } return ret; } diff --git a/src/sql/resolver/expr/ob_raw_expr_util.h b/src/sql/resolver/expr/ob_raw_expr_util.h index e29066fa2..b67142376 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.h +++ b/src/sql/resolver/expr/ob_raw_expr_util.h @@ -807,9 +807,11 @@ public: static int rebuild_expr_params(ObUDFInfo &udf_info, sql::ObRawExprFactory *expr_factory, common::ObIArray &expr_params); - static int init_udf_info(ObResolverParams ¶ms, ObUDFInfo &udf_info); - static int init_udf_info(pl::ObPLResolveCtx &resolve_ctx, sql::ObRawExprFactory &expr_factory, ObUDFInfo &udf_info); - static int init_udfs_info(ObResolverParams ¶ms, common::ObIArray &udfs_info); + static int resolve_udf_info(common::ObIAllocator &allocator, + sql::ObRawExprFactory &expr_factory, + sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + ObUDFInfo &udf_info); //判断expr里是否包含字符串前缀的表达式 static bool has_prefix_str_expr(const ObRawExpr &expr, const ObColumnRefRawExpr &orig_column_expr, diff --git a/src/sql/resolver/ob_resolver_utils.cpp b/src/sql/resolver/ob_resolver_utils.cpp index e83deb20c..3ae652712 100644 --- a/src/sql/resolver/ob_resolver_utils.cpp +++ b/src/sql/resolver/ob_resolver_utils.cpp @@ -874,71 +874,30 @@ int ObResolverUtils::check_match(const pl::ObPLResolveCtx &resolve_ctx, match_info.match_info_.push_back(ObRoutineMatchInfo::MatchInfo()); } - // first we have to check udt udf's self argument, case study: - /* - * 1. this udf is static, do nothing - * 2. this udf is member, we have to possiblility here - * 1) self argument is mocked, such as obj.routine(a), self argument should be existed - * in expr_params; - * 2) self argument is not mocked, etc: func_name is begin routine(a); end; which func_name - * is a udt member function, and routine is also a member function. in such case, routine's - * self argument is not exist, we should ignore the first param in routine info, if it has - * a self param. - */ int64_t offset = 0; if(OB_SUCC(ret) && 0 < expr_params.count() && OB_NOT_NULL(expr_params.at(0))) { ObRawExpr *first_arg = expr_params.at(0); if (first_arg->has_flag(IS_UDT_UDF_SELF_PARAM)) { // do nothing, may be we can check if routine is static or not - } else if (routine_info->is_udt_routine() && !routine_info->is_udt_static_routine() - && expr_params.count() != routine_info->get_param_count()) { - /* - * what are we doing here? - * suppose a member routine has three params; but the arguments(expr_params) is less than three - * we get three case here: - * case 1 case 2 case 3 - * arg [1][2] [2][3] [2] - * param [1][2][default] [self][2][3] [self][2][default] - * case 1 has default param, but argument is pass default - * case 2 has self, but argument is not passed in - * case 3 is th combine of 2 and 3 - * we have to handle case 2, and case 3, when argument is not having self, - * we just passed this type check test, and suppose it is same - */ - ObIRoutineParam *iparam = NULL; - OZ (routine_info->get_routine_param(0, iparam)); - for (int64_t i = 0; i< routine_info->get_param_count(); ++i) { - ObIRoutineParam *ip = NULL; - routine_info->get_routine_param(i, ip); - } - CK (OB_NOT_NULL(iparam)); - CK (iparam->is_self_param()); - if (OB_SUCC(ret)) { - ObPLDataType dst_pl_type; - if (iparam->is_schema_routine_param()) { - ObRoutineParam *param = static_cast(iparam); - OZ (pl::ObPLDataType::transform_from_iparam(param, - resolve_ctx.schema_guard_, - resolve_ctx.session_info_, - resolve_ctx.allocator_, - resolve_ctx.sql_proxy_, - dst_pl_type)); - } else { - dst_pl_type = iparam->get_pl_data_type(); - } - // to check first is self type or not - ObObjType src_type; - uint64_t src_type_id; + } else if (routine_info->is_udt_routine() + && !routine_info->is_udt_static_routine() + && expr_params.count() != routine_info->get_param_count()) { + uint64_t src_type_id = OB_INVALID_ID; + ObObjType src_type; + if (T_SP_CPARAM == first_arg->get_expr_type()) { + ObCallParamRawExpr *call_expr = static_cast(first_arg); + OZ (call_expr->get_expr()->deduce_type(&resolve_ctx.session_info_)); + OZ (get_type_and_type_id(call_expr->get_expr(), src_type, src_type_id)); + } else { OZ (first_arg->deduce_type(&resolve_ctx.session_info_)); OZ (get_type_and_type_id(first_arg, src_type, src_type_id)); - if (OB_SUCC(ret) && src_type_id != dst_pl_type.get_user_type_id() /*not case 1*/) { - // set first param matched - OX (match_info.match_info_.at(0) = - (ObRoutineMatchInfo::MatchInfo(false, - dst_pl_type.get_obj_type(), - dst_pl_type.get_obj_type()))); - OX (offset = 1); - } + } + if (OB_SUCC(ret) + && (src_type_id != routine_info->get_package_id() + || routine_info->is_udt_cons())) { + // set first param matched + OX (match_info.match_info_.at(0) = (ObRoutineMatchInfo::MatchInfo(false, src_type, src_type))); + OX (offset = 1); } } } @@ -1047,21 +1006,6 @@ int ObResolverUtils::match_vacancy_parameters( } } } - // // 看看是否udt的self 参数 - // if (OB_ERR_SP_WRONG_ARG_NUM == ret) { - // if (routine_info.is_udt_routine() && !routine_info.is_udt_static_routine()) { - // int cnt = 0; - // for (int64_t i = 0; i < match_info.match_info_.count(); ++i) { - // if (ObMaxType == match_info.match_info_.at(i).dest_type_) { - // ++cnt; - // } - // } - // // 只能有一个self参数 - // if (1 == cnt) { - // ret = OB_SUCCESS; - // } - // } - // } CANCLE_LOG_CHECK_MODE(); return ret; } @@ -1320,7 +1264,7 @@ int ObResolverUtils::get_routine(const pl::ObPLResolveCtx &resolve_ctx, OX (routine = static_cast(candidate_routine_infos.at(0))); } else { OZ (pick_routine(resolve_ctx, expr_params, candidate_routine_infos, routine)); - LOG_DEBUG("call ObResolverUtils::get_routine fit routine", + LOG_INFO("call ObResolverUtils::get_routine fit routine", K(db_name), K(package_name), K(routine_name), @@ -1334,7 +1278,7 @@ int ObResolverUtils::get_routine(const pl::ObPLResolveCtx &resolve_ctx, if (ROUTINE_FUNCTION_TYPE == routine_type) { ret = OB_ERR_FUNCTION_UNKNOWN; LOG_WARN("stored function not exists", K(ret), K(routine_name), K(db_name), K(package_name)); - LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, routine_name.length(), routine_name.ptr()); + LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, "FUNCTION", routine_name.length(), routine_name.ptr()); } else { ret = OB_ERR_SP_DOES_NOT_EXIST; LOG_USER_ERROR(OB_ERR_SP_DOES_NOT_EXIST, @@ -2799,9 +2743,9 @@ int ObResolverUtils::resolve_const_expr(ObResolverParams ¶ms, } else if (sub_query_info.count() > 0) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "subqueries or stored function calls here"); - } else if (udf_info.count() > 0 - && OB_FAIL(ObRawExprUtils::init_udfs_info(params, udf_info))) { - LOG_WARN("resolve udf info failed", K(ret), K(udf_info)); + } else if (udf_info.count() > 0) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("UDFInfo should not found be here!!!", K(ret)); } //process oracle compatible implicit conversion @@ -3592,7 +3536,7 @@ int ObResolverUtils::log_err_msg_for_partition_value(const ObQualifiedName &name const ObString &func_name = name.access_idents_.at(name.access_idents_.count() - 1).access_name_; ret = OB_ERR_FUNCTION_UNKNOWN; LOG_WARN("Invalid function name in partition function", K(name.access_idents_.count()), K(ret), K(func_name)); - LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, func_name.length(), func_name.ptr()); + LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, "FUNCTION", func_name.length(), func_name.ptr()); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("name is invalid", K(name), K(ret)); @@ -3890,11 +3834,9 @@ int ObResolverUtils::resolve_partition_range_value_expr(ObResolverParams ¶ms } else if (OB_FAIL(resolve_columns_for_partition_range_value_expr(part_value_expr, columns))) { LOG_WARN("resolve columns failed", K(ret)); } - if (OB_SUCC(ret) && udf_info.count()) { - if (OB_FAIL(ObRawExprUtils::init_udfs_info(params, - udf_info))) { - LOG_WARN("resolve udf info failed", K(ret)); - } + if (OB_SUCC(ret) && udf_info.count() > 0) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("UDFInfo should not found be here!!!", K(ret)); } if (OB_SUCC(ret)) { @@ -3945,7 +3887,7 @@ int ObResolverUtils::resolve_columns_for_partition_expr(ObRawExpr *&expr, OZ (real_sys_exprs.push_back(std::pair(q_name.ref_expr_, real_ref_expr))); } } else if (q_name.is_pl_udf() || q_name.is_pl_var()) { - ret = OB_ERR_UNEXPECTED; + ret = OB_NOT_SUPPORTED; LOG_WARN("pl variable is not invalid for partition", K(ret)); } else if (q_name.database_name_.length() > 0 || q_name.tbl_name_.length() > 0) { ret = OB_ERR_BAD_FIELD_ERROR; @@ -5582,82 +5524,8 @@ int ObResolverUtils::set_sync_ddl_id_str(ObSQLSessionInfo *session_info, ObStrin return ret; } -int ObResolverUtils::resolve_udf_name(ObSchemaChecker &schema_checker, - const ObSQLSessionInfo &session_info, - const ObUDFInfo &udf_info, - ObString &db_name, ObString &pkg_name, ObString &udf_name) -{ - int ret = OB_SUCCESS; - udf_name.assign_ptr(udf_info.udf_name_.ptr(), udf_info.udf_name_.length()); - if (!udf_info.udf_database_.empty() && !udf_info.udf_package_.empty()) { - db_name.assign_ptr(udf_info.udf_database_.ptr(), udf_info.udf_database_.length()); - pkg_name.assign_ptr(udf_info.udf_package_.ptr(), udf_info.udf_package_.length()); - } else if (!udf_info.udf_database_.empty() && udf_info.udf_package_.empty()) { - // need to make sure whether the db name is real db name or package name - // first search db name, then package name - uint64_t database_id = OB_INVALID_ID; - uint64_t package_id = OB_INVALID_ID; - int64_t compatible_mode = lib::is_oracle_mode() ? COMPATIBLE_ORACLE_MODE - : COMPATIBLE_MYSQL_MODE; - if (OB_FAIL(schema_checker.get_database_id(session_info.get_effective_tenant_id(), - udf_info.udf_database_, database_id))) { - if (OB_ERR_BAD_DATABASE != ret) { - LOG_WARN("get database id failed", K(udf_info.udf_database_), K(ret)); - } else { - if (OB_FAIL(schema_checker.get_package_id(session_info.get_effective_tenant_id(), - session_info.get_database_name(), - udf_info.udf_database_, - compatible_mode, - package_id))) { - if (OB_ERR_PACKAGE_DOSE_NOT_EXIST == ret) { - if (OB_FAIL(schema_checker.get_package_id(OB_SYS_TENANT_ID, OB_SYS_DATABASE_NAME, - udf_info.udf_database_, - compatible_mode, - package_id))) { - if (OB_ERR_PACKAGE_DOSE_NOT_EXIST == ret) { - ret = OB_ERR_BAD_DATABASE; - LOG_USER_ERROR(OB_ERR_BAD_DATABASE, udf_info.udf_database_.length(), - udf_info.udf_database_.ptr()); - } else { - LOG_WARN("get package id failed", K(udf_info.udf_database_), K(ret)); - } - } else { - pkg_name.assign_ptr(udf_info.udf_database_.ptr(), udf_info.udf_database_.length()); - db_name.assign_ptr(OB_SYS_DATABASE_NAME, - static_cast(strlen(OB_SYS_DATABASE_NAME))); - } - } else { - LOG_WARN("get package id failed", K(udf_info.udf_database_), K(ret)); - } - } - if (OB_SUCC(ret)) { - pkg_name.assign_ptr(udf_info.udf_database_.ptr(), udf_info.udf_database_.length()); - db_name = session_info.get_database_name(); - if (lib::is_oracle_mode()) { - size_t size = ObCharset::caseup(CS_TYPE_UTF8MB4_GENERAL_CI, db_name.ptr(), db_name.length(), db_name.ptr(), db_name.length()); - db_name.set_length(static_cast(size)); - } - } - } - } else { - db_name.assign_ptr(udf_info.udf_database_.ptr(), udf_info.udf_database_.length()); - if (lib::is_oracle_mode()) { - size_t size = ObCharset::caseup(CS_TYPE_UTF8MB4_GENERAL_CI, db_name.ptr(), db_name.length(), db_name.ptr(), db_name.length()); - db_name.set_length(static_cast(size)); - } - } - } else if (udf_info.udf_database_.empty() && !udf_info.udf_package_.empty()) { - pkg_name = udf_info.udf_package_; - } else { - //do nothing - //in pl context, this call may be a package private procedure, not a schema object - } - return ret; -} - -int ObResolverUtils::resolve_udf(const ParseNode *node, - const common::ObNameCaseMode case_mode, - ObUDFInfo &udf_info) +int ObResolverUtils::resolve_udf_name_by_parse_node( + const ParseNode *node, const common::ObNameCaseMode case_mode, ObUDFInfo &udf_info) { int ret = OB_SUCCESS; ObString udf_name; @@ -6208,6 +6076,21 @@ int ObResolverUtils::check_foreign_key_columns_type(const ObTableSchema &child_t return ret; } +int ObResolverUtils::transform_sys_func_to_objaccess( + ObIAllocator *allocator, const ParseNode *sys_func, ParseNode *&obj_access) +{ + int ret = OB_SUCCESS; + if (allocator == nullptr || sys_func == nullptr || sys_func->type_ != T_FUN_SYS) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("func_sys node is null", K(ret)); + } else if (OB_ISNULL(obj_access + = new_non_terminal_node(allocator, T_OBJ_ACCESS_REF, 2, sys_func, nullptr))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("make T_OBJ_ACCESS node failed", K(ret)); + } + return ret; +} + int ObResolverUtils::transform_func_sys_to_udf(ObIAllocator *allocator, const ParseNode *func_sys, const ObString &db_name, const ObString &pkg_name, ParseNode *&func_udf) @@ -6311,19 +6194,19 @@ int ObResolverUtils::resolve_string(const ParseNode *node, ObString &string) } int ObResolverUtils::resolve_external_symbol(common::ObIAllocator &allocator, - sql::ObRawExprFactory &expr_factory, - sql::ObSQLSessionInfo &session_info, - share::schema::ObSchemaGetterGuard &schema_guard, - common::ObMySQLProxy *sql_proxy, - ExternalParams *extern_param_info, - pl::ObPLBlockNS *ns, - ObQualifiedName &q_name, - ObIArray &columns, - ObIArray &real_exprs, - ObRawExpr *&expr, - bool is_prepare_protocol, - bool is_check_mode, - bool is_sql_scope) + sql::ObRawExprFactory &expr_factory, + sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + common::ObMySQLProxy *sql_proxy, + ExternalParams *extern_param_info, + pl::ObPLBlockNS *ns, + ObQualifiedName &q_name, + ObIArray &columns, + ObIArray &real_exprs, + ObRawExpr *&expr, + bool is_prepare_protocol, + bool is_check_mode, + bool is_sql_scope) { int ret = OB_SUCCESS; pl::ObPLPackageGuard dummy_pkg_guard(session_info.get_effective_tenant_id()); diff --git a/src/sql/resolver/ob_resolver_utils.h b/src/sql/resolver/ob_resolver_utils.h index 656a50e78..5b325ec07 100644 --- a/src/sql/resolver/ob_resolver_utils.h +++ b/src/sql/resolver/ob_resolver_utils.h @@ -534,15 +534,8 @@ public: static bool is_restore_user(ObSQLSessionInfo &session_info); static bool is_drc_user(ObSQLSessionInfo &session_info); static int set_sync_ddl_id_str(ObSQLSessionInfo *session_info, common::ObString &ddl_id_str); - static int resolve_udf_name(ObSchemaChecker &schema_checker, - const ObSQLSessionInfo &session_info, - const ObUDFInfo &udf_info, - common::ObString &db_name, - common::ObString &pkg_name, - common::ObString &udf_name); - static int resolve_udf(const ParseNode *node, - const common::ObNameCaseMode case_mode, - ObUDFInfo& udf_info); + static int resolve_udf_name_by_parse_node( + const ParseNode *node, const common::ObNameCaseMode case_mode, ObUDFInfo& udf_info); // for create table with fk in oracle mode static int check_dup_foreign_keys_exist( const common::ObSArray &fk_args); @@ -596,6 +589,8 @@ public: const share::schema::ObColumnSchemaV2 *column = NULL); static int get_columns_name_from_index_table_schema(const share::schema::ObTableSchema &index_table_schema, ObIArray &index_columns_name); + static int transform_sys_func_to_objaccess( + common::ObIAllocator *allocator, const ParseNode *sys_func, ParseNode *&obj_access); static int transform_func_sys_to_udf(common::ObIAllocator *allocator, const ParseNode *func_sys, const common::ObString &db_name, diff --git a/src/sql/rewrite/ob_transform_pre_process.cpp b/src/sql/rewrite/ob_transform_pre_process.cpp index 3f6787a75..f4322886c 100644 --- a/src/sql/rewrite/ob_transform_pre_process.cpp +++ b/src/sql/rewrite/ob_transform_pre_process.cpp @@ -3460,6 +3460,7 @@ int ObTransformPreProcess::calc_policy_function(ObDMLStmt &stmt, if (OB_ISNULL(ctx_) || OB_ISNULL(session_info = ctx_->session_info_) || OB_ISNULL(schema_checker = ctx_->schema_checker_) + || OB_ISNULL(schema_checker->get_schema_guard()) || OB_ISNULL(expr_factory = ctx_->expr_factory_) || OB_ISNULL(ctx_->exec_ctx_) || OB_ISNULL(ctx_->allocator_)) { @@ -3504,7 +3505,8 @@ int ObTransformPreProcess::calc_policy_function(ObDMLStmt &stmt, } else if (OB_FAIL(udf_expr->add_param_expr(object_name_expr))) { LOG_WARN("failed to add param expr", K(object_name_expr), K(ret)); } else if (FALSE_IT(udf_info.ref_expr_ = udf_expr)) { - } else if (OB_FAIL(ObRawExprUtils::init_udf_info(params, udf_info))) { + } else if (OB_FAIL(ObRawExprUtils::resolve_udf_info( + *params.allocator_, *params.expr_factory_, *params.session_info_, *params.schema_checker_->get_schema_guard(), udf_info))) { LOG_WARN("failed to init udf_info", K(udf_info), K(ret)); } else if (OB_FAIL(udf_expr->formalize(session_info))) { LOG_WARN("failed to formalize", K(ret)); diff --git a/tools/deploy/mysql_test/test_suite/pl/r/mysql/sp_mysql.result b/tools/deploy/mysql_test/test_suite/pl/r/mysql/sp_mysql.result index 9a792b9af..e043ce55b 100644 --- a/tools/deploy/mysql_test/test_suite/pl/r/mysql/sp_mysql.result +++ b/tools/deploy/mysql_test/test_suite/pl/r/mysql/sp_mysql.result @@ -1061,7 +1061,7 @@ a f8() 3 1 drop function f1| select * from v1| -ERROR 42000: FUNCTION f1 does not exist +ERROR 42000: FUNCTION test.f1 does not exist create function f1() returns int return (select sum(data) from t1) + (select sum(data) from v1)| select f1()|