[FEAT MERGE]:develop pl feature of 4.2 version

Co-authored-by: LiuYoung00 <liuyanglo_ol@163.com>
Co-authored-by: 0xacc <heyongyi1998@gmail.com>
Co-authored-by: seuwebber <webber_code@163.com>
This commit is contained in:
obdev
2023-04-27 16:08:10 +08:00
committed by ob-robot
parent 8e9c9d0c5f
commit 57f1c6e7ee
92 changed files with 3534 additions and 1304 deletions

View File

@ -21,6 +21,7 @@
#include "pl/ob_pl_package.h"
#include "observer/ob_req_time_service.h"
#include "pl/ob_pl_compile.h"
#include "pl/pl_cache/ob_pl_cache_mgr.h"
namespace oceanbase
{
@ -50,12 +51,13 @@ int ObCallProcedureResolver::check_param_expr_legal(ObRawExpr *param)
}
int ObCallProcedureResolver::resolve_cparams(const ParseNode *params_node,
const ObRoutineInfo *routine_info,
ObCallProcedureStmt *stmt)
ObCallProcedureInfo *call_proc_info,
ObIArray<ObRawExpr*> &params)
{
int ret = OB_SUCCESS;
CK (OB_NOT_NULL(routine_info));
CK (OB_NOT_NULL(stmt));
ObArray<ObRawExpr*> params;
CK (OB_NOT_NULL(call_proc_info));
// Step 1: 初始化参数列表
for (int64_t i = 0; OB_SUCC(ret) && i < routine_info->get_param_count(); ++i) {
OZ (params.push_back(NULL));
@ -103,8 +105,7 @@ int ObCallProcedureResolver::resolve_cparams(const ParseNode *params_node,
OX (params.at(i) = default_expr);
}
}
// Step 4: 将参数数组设置到stmt中
OZ (stmt->add_params(params));
if (OB_SUCC(ret)) { // 判断所有参数没有复杂表达式参数
bool v = true;
for (int64_t i = 0; v && OB_SUCC(ret) && i < params.count(); i ++) {
@ -120,7 +121,7 @@ int ObCallProcedureResolver::resolve_cparams(const ParseNode *params_node,
v = false;
}
} // for end
stmt->set_can_direct_use_param(v);
call_proc_info->set_can_direct_use_param(v);
}
return ret;
}
@ -252,6 +253,92 @@ int ObCallProcedureResolver::resolve_param_exprs(const ParseNode *params_node,
return ret;
}
int ObCallProcedureResolver::generate_pl_cache_ctx(pl::ObPLCacheCtx &pc_ctx)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(schema_checker_) || OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("argument is NULL", K(schema_checker_), K(session_info_), K(ret));
} else if (OB_ISNULL(schema_checker_->get_schema_mgr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("argument is NULL", K(ret));
} else {
pc_ctx.session_info_ = session_info_;
pc_ctx.schema_guard_ = schema_checker_->get_schema_mgr();
pc_ctx.cache_params_ = const_cast<ParamStore *>(params_.param_list_);
pc_ctx.raw_sql_ = params_.cur_sql_;
pc_ctx.key_.namespace_ = ObLibCacheNameSpace::NS_CALLSTMT;
pc_ctx.key_.db_id_ = session_info_->get_database_id();
pc_ctx.key_.sessid_ = 0;
pc_ctx.key_.key_id_ = OB_INVALID_ID;
pc_ctx.key_.name_ = params_.cur_sql_;
}
return ret;
}
int ObCallProcedureResolver::add_call_proc_info(ObCallProcedureInfo *call_info)
{
int ret = OB_SUCCESS;
ObPlanCache *plan_cache = NULL;
pl::ObPLCacheCtx pc_ctx;
if (OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("argument is NULL", K(ret));
} else if (OB_ISNULL(plan_cache = session_info_->get_plan_cache())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("argument is NULL", K(ret));
} else if (OB_FAIL(generate_pl_cache_ctx(pc_ctx))) {
LOG_WARN("generate pl cache ctx failed", K(ret));
} else if (OB_FAIL(pl::ObPLCacheMgr::add_pl_cache(plan_cache, call_info, pc_ctx))) {
if (OB_SQL_PC_PLAN_DUPLICATE == ret) {
ret = OB_SUCCESS;
LOG_DEBUG("this plan has been added by others, need not add again", KPC(call_info));
} else if (OB_REACH_MEMORY_LIMIT == ret || OB_SQL_PC_PLAN_SIZE_LIMIT == ret) {
if (REACH_TIME_INTERVAL(1000000)) { //1s, 当内存达到上限时, 该日志打印会比较频繁, 所以以1s为间隔打印
LOG_DEBUG("can't add plan to plan cache",
K(ret), K(call_info->get_mem_size()), K(pc_ctx.key_),
K(plan_cache->get_mem_used()));
}
ret = OB_SUCCESS;
} else if (is_not_supported_err(ret)) {
ret = OB_SUCCESS;
LOG_DEBUG("plan cache don't support add this kind of plan now", KPC(call_info));
} else {
if (OB_REACH_MAX_CONCURRENT_NUM != ret) { //如果是达到限流上限, 则将错误码抛出去
ret = OB_SUCCESS; //add plan出错, 覆盖错误码, 确保因plan cache失败不影响正常执行路径
LOG_WARN("Failed to add plan to ObPlanCache", K(ret));
}
}
}
return ret;
}
int ObCallProcedureResolver::find_call_proc_info(ObCallProcedureStmt &stmt)
{
int ret = OB_SUCCESS;
ObPlanCache *plan_cache = NULL;
ObCallProcedureInfo *call_proc_info = NULL;
pl::ObPLCacheCtx pc_ctx;
if (OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("argument is NULL", K(ret));
} else if (OB_ISNULL(plan_cache = session_info_->get_plan_cache())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("argument is NULL", K(ret));
} else if (OB_FAIL(generate_pl_cache_ctx(pc_ctx))) {
LOG_WARN("generate pl cache ctx failed", K(ret));
} else if (OB_FAIL(pl::ObPLCacheMgr::get_pl_cache(plan_cache, stmt.get_cacheobj_guard(), pc_ctx))) {
LOG_INFO("get pl function by sql failed, will ignore this error",
K(ret), K(pc_ctx.key_));
ret = OB_ERR_UNEXPECTED != ret ? OB_SUCCESS : ret;
} else {
call_proc_info = static_cast<ObCallProcedureInfo*>(stmt.get_cacheobj_guard().get_cache_obj());
CK (OB_NOT_NULL(call_proc_info));
OX (stmt.set_call_proc_info(call_proc_info));
}
return ret;
}
int ObCallProcedureResolver::resolve(const ParseNode &parse_tree)
{
int ret = OB_SUCCESS;
@ -261,8 +348,8 @@ int ObCallProcedureResolver::resolve(const ParseNode &parse_tree)
ObString db_name;
ObString package_name;
ObString sp_name;
ObCallProcedureInfo *call_proc_info = NULL;
const ObRoutineInfo *proc_info = NULL;
if (OB_ISNULL(schema_checker_) || OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("argument is NULL", K(schema_checker_), K(session_info_), K(ret));
@ -272,192 +359,222 @@ int ObCallProcedureResolver::resolve(const ParseNode &parse_tree)
} else if (OB_ISNULL(stmt = create_stmt<ObCallProcedureStmt>())) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("create call stmt failed", K(ret));
} else if (FALSE_IT(stmt_ = stmt)) {
} else if (FALSE_IT(stmt->get_cacheobj_guard().init(CALLSTMT_HANDLE))) {
} else if (params_.is_execute_call_stmt_ && 0 != params_.cur_sql_.length() &&
OB_FAIL(find_call_proc_info(*stmt))) {
LOG_WARN("fail to find call stmt", K(ret));
} else if (NULL != stmt->get_call_proc_info()) {
// find call procedure info in pl cache.
} else {
stmt_ = stmt;
}
// 解析过程名称
if (OB_SUCC(ret)) {
if (T_SP_ACCESS_NAME != name_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Invalid procedure name node", K(name_node->type_), K(ret));
} else {
if (OB_FAIL(ObResolverUtils::resolve_sp_access_name(*schema_checker_,
session_info_->get_effective_tenant_id(),
session_info_->get_database_name(),
*name_node,
db_name, package_name, sp_name))) {
LOG_WARN("resolve sp name failed", K(ret));
} else if (db_name.empty() && session_info_->get_database_name().empty()) {
ret = OB_ERR_NO_DB_SELECTED;
LOG_WARN("no database selected", K(ret), K(db_name));
} else {
if (!db_name.empty()) {
OX (stmt->set_db_name(db_name));
} else {
OX (stmt->set_db_name(session_info_->get_database_name()));
}
}
}
}
ObSEArray<ObRawExpr*, 16> expr_params;
// 获取routine schem info
if (OB_SUCC(ret)) {
if (OB_NOT_NULL(params_node)
&& OB_FAIL(resolve_param_exprs(params_node, expr_params))) {
LOG_WARN("failed to resolve param exprs", K(ret));
} else if (OB_FAIL(ObResolverUtils::get_routine(params_,
(*session_info_).get_effective_tenant_id(),
(*session_info_).get_database_name(),
db_name,
package_name,
sp_name,
ROUTINE_PROCEDURE_TYPE,
expr_params,
proc_info))) {
LOG_WARN("failed to get routine info", K(ret), K(db_name), K(package_name), K(sp_name));
} else if (OB_ISNULL(proc_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("proc info is null", K(ret), K(db_name), K(package_name), K(sp_name), K(proc_info));
} else if (proc_info->has_accessible_by_clause()) {
ret = OB_ERR_MISMATCH_SUBPROGRAM;
LOG_WARN("PLS-00263: mismatch between string on a subprogram specification and body",
K(ret), KPC(proc_info));
}
if (OB_SUCC(ret) && proc_info->is_udt_routine() && !proc_info->is_udt_static_routine()) {
ret = OB_ERR_CALL_WRONG_ARG;
LOG_USER_ERROR(OB_ERR_CALL_WRONG_ARG, proc_info->get_routine_name().length(),
proc_info->get_routine_name().ptr());
}
if (OB_SUCC(ret) && proc_info->is_udt_routine()) {
stmt->set_is_udt_routine(true);
}
OZ (ObCacheObjectFactory::alloc(stmt->get_cacheobj_guard(),
ObLibCacheNameSpace::NS_CALLSTMT,
session_info_->get_effective_tenant_id()));
OX (call_proc_info = static_cast<ObCallProcedureInfo*>(stmt->get_cacheobj_guard().get_cache_obj()));
CK (OB_NOT_NULL(call_proc_info));
// 解析过程名称
if (OB_SUCC(ret)) {
ObSchemaObjVersion obj_version;
obj_version.object_id_ = proc_info->get_routine_id();
obj_version.object_type_ = proc_info->is_procedure() ? DEPENDENCY_PROCEDURE : DEPENDENCY_FUNCTION;
obj_version.version_ = proc_info->get_schema_version();
OZ (stmt->add_global_dependency_table(obj_version));
}
}
// 解析参数列表
// if (OB_SUCC(ret) && params_.is_execute_call_stmt_) {
// OZ (stmt->add_params(expr_params));
// OX (stmt->set_can_direct_use_param(true));
// } else {
OZ (resolve_cparams(params_node, proc_info, stmt));
// }
if (OB_SUCC(ret)) {
if (OB_INVALID_ID == proc_info->get_package_id()) {
//standalone procedure
stmt->set_package_id(proc_info->get_package_id());
stmt->set_routine_id(proc_info->get_routine_id());
} else {
//package procedure
stmt->set_package_id(proc_info->get_package_id());
stmt->set_routine_id(proc_info->get_subprogram_id());
}
for (int64_t i = 0; OB_SUCC(ret) && i < proc_info->get_param_count(); ++i) {
const ObRoutineParam *param_info = proc_info->get_routine_params().at(i);
const ObRawExpr *param_expr = stmt->get_params().at(i);
pl::ObPLDataType pl_type;
CK (OB_NOT_NULL(param_info));
CK (OB_NOT_NULL(param_expr));
if (OB_SUCC(ret)) {
CK (OB_NOT_NULL(schema_checker_->get_schema_mgr()));
CK (OB_NOT_NULL(params_.sql_proxy_));
CK (OB_NOT_NULL(params_.allocator_));
CK (OB_NOT_NULL(session_info_));
OZ (pl::ObPLDataType::transform_from_iparam(param_info,
*(schema_checker_->get_schema_mgr()),
*(session_info_),
*(params_.allocator_),
*(params_.sql_proxy_),
pl_type));
if (OB_FAIL(ret)) {
} else if (params_.is_prepare_protocol_
&& params_.is_prepare_stage_
&& param_expr->get_expr_type() != T_QUESTIONMARK) {
// do nothing ...
} else if (!param_info->is_extern_type()) {
if (T_SP_ACCESS_NAME != name_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Invalid procedure name node", K(name_node->type_), K(ret));
} else {
if (OB_FAIL(ObResolverUtils::resolve_sp_access_name(*schema_checker_,
session_info_->get_effective_tenant_id(),
session_info_->get_database_name(),
*name_node,
db_name, package_name, sp_name))) {
LOG_WARN("resolve sp name failed", K(ret));
} else if (db_name.empty() && session_info_->get_database_name().empty()) {
ret = OB_ERR_NO_DB_SELECTED;
LOG_WARN("no database selected", K(ret), K(db_name));
} else {
if (OB_SUCC(ret)) {
//not support complex param not in prepare, except default value
if (pl_type.is_user_type()) {
if (!params_.is_prepare_protocol_
&& !param_expr->has_flag(IS_PL_MOCK_DEFAULT_EXPR)) {
ret = OB_ERR_CALL_WRONG_ARG;
LOG_WARN("PLS-00306: wrong number or types of arguments in call stmt", K(ret));
if (!db_name.empty()) {
OZ (call_proc_info->set_db_name(db_name));
} else {
OZ (call_proc_info->set_db_name(session_info_->get_database_name()));
}
}
}
}
ObSEArray<ObRawExpr*, 16> expr_params;
// 获取routine schem info
if (OB_SUCC(ret)) {
if (OB_NOT_NULL(params_node)
&& OB_FAIL(resolve_param_exprs(params_node, expr_params))) {
LOG_WARN("failed to resolve param exprs", K(ret));
} else if (OB_FAIL(ObResolverUtils::get_routine(params_,
(*session_info_).get_effective_tenant_id(),
(*session_info_).get_database_name(),
db_name,
package_name,
sp_name,
ROUTINE_PROCEDURE_TYPE,
expr_params,
proc_info))) {
LOG_WARN("failed to get routine info", K(ret), K(db_name), K(package_name), K(sp_name));
} else if (OB_ISNULL(proc_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("proc info is null", K(ret), K(db_name), K(package_name), K(sp_name), K(proc_info));
} else if (proc_info->has_accessible_by_clause()) {
ret = OB_ERR_MISMATCH_SUBPROGRAM;
LOG_WARN("PLS-00263: mismatch between string on a subprogram specification and body",
K(ret), KPC(proc_info));
}
if (OB_SUCC(ret) && proc_info->is_udt_routine() && !proc_info->is_udt_static_routine()) {
ret = OB_ERR_CALL_WRONG_ARG;
LOG_USER_ERROR(OB_ERR_CALL_WRONG_ARG, proc_info->get_routine_name().length(),
proc_info->get_routine_name().ptr());
}
if (OB_SUCC(ret) && proc_info->is_udt_routine()) {
call_proc_info->set_is_udt_routine(true);
}
if (OB_SUCC(ret)) {
ObSchemaObjVersion obj_version;
obj_version.object_id_ = proc_info->get_routine_id();
obj_version.object_type_ = proc_info->is_procedure() ? DEPENDENCY_PROCEDURE : DEPENDENCY_FUNCTION;
obj_version.version_ = proc_info->get_schema_version();
int64_t tenant_id = session_info_->get_effective_tenant_id();
int64_t tenant_schema_version = OB_INVALID_VERSION;
int64_t sys_schema_version = OB_INVALID_VERSION;
CK (OB_NOT_NULL(schema_checker_->get_schema_mgr()));
OZ (schema_checker_->get_schema_mgr()->get_schema_version(tenant_id, tenant_schema_version));
OZ (schema_checker_->get_schema_mgr()->get_schema_version(OB_SYS_TENANT_ID, sys_schema_version));
OX (call_proc_info->set_tenant_schema_version(tenant_schema_version));
OX (call_proc_info->set_sys_schema_version(sys_schema_version));
OZ (call_proc_info->init_dependency_table_store(1));
OZ (call_proc_info->get_dependency_table().push_back(obj_version));
}
}
ObArray<ObRawExpr*> params;
OZ (resolve_cparams(params_node, proc_info, call_proc_info, params));
if (OB_SUCC(ret)) {
if (OB_INVALID_ID == proc_info->get_package_id()) {
//standalone procedure
call_proc_info->set_package_id(proc_info->get_package_id());
call_proc_info->set_routine_id(proc_info->get_routine_id());
} else {
//package procedure
call_proc_info->set_package_id(proc_info->get_package_id());
call_proc_info->set_routine_id(proc_info->get_subprogram_id());
}
for (int64_t i = 0; OB_SUCC(ret) && i < proc_info->get_param_count(); ++i) {
const ObRoutineParam *param_info = proc_info->get_routine_params().at(i);
const ObRawExpr *param_expr = params.at(i);
pl::ObPLDataType pl_type;
CK (OB_NOT_NULL(param_info));
CK (OB_NOT_NULL(param_expr));
if (OB_SUCC(ret)) {
CK (OB_NOT_NULL(schema_checker_->get_schema_mgr()));
CK (OB_NOT_NULL(params_.sql_proxy_));
CK (OB_NOT_NULL(session_info_));
OZ (pl::ObPLDataType::transform_from_iparam(param_info,
*(schema_checker_->get_schema_mgr()),
*(session_info_),
*(params_.allocator_),
*(params_.sql_proxy_),
pl_type));
if (OB_FAIL(ret)) {
} else if (params_.is_prepare_protocol_
&& params_.is_prepare_stage_
&& param_expr->get_expr_type() != T_QUESTIONMARK) {
// do nothing ...
} else if (!param_info->is_extern_type()) {
} else {
if (OB_SUCC(ret)) {
//not support complex param not in prepare, except default value
if (pl_type.is_user_type()) {
if (!params_.is_prepare_protocol_
&& !param_expr->has_flag(IS_PL_MOCK_DEFAULT_EXPR)) {
ret = OB_ERR_CALL_WRONG_ARG;
LOG_WARN("PLS-00306: wrong number or types of arguments in call stmt", K(ret));
}
}
}
}
}
}
if (OB_SUCC(ret)) {
if (param_info->is_out_sp_param() || param_info->is_inout_sp_param()) {
const ObRawExpr* param = stmt->get_params().at(i);
if (lib::is_mysql_mode()
&& param->get_expr_type() != T_OP_GET_USER_VAR
&& param->get_expr_type() != T_OP_GET_SYS_VAR) {
ret = OB_ER_SP_NOT_VAR_ARG;
LOG_USER_ERROR(OB_ER_SP_NOT_VAR_ARG, static_cast<int32_t>(i), static_cast<int32_t>(sp_name.length()), sp_name.ptr());
LOG_WARN("OUT or INOUT argument for routine is not a variable", K(param->get_expr_type()), K(ret));
} else if (param_info->is_sys_refcursor_type()
|| (param_info->is_pkg_type() && pl_type.is_cursor_type())) {
OZ (stmt->add_out_param(i,
param_info->get_mode(),
param_info->get_param_name(),
pl_type,
ObString("SYS_REFCURSOR"),
ObString("")));
} else if (param_info->is_complex_type()) { // UDT
if (param_info->get_type_owner() == session_info_->get_database_id()) {
CK (!session_info_->get_database_name().empty());
OZ (stmt->add_out_param(i,
if (OB_SUCC(ret)) {
if (param_info->is_out_sp_param() || param_info->is_inout_sp_param()) {
const ObRawExpr* param = params.at(i);
if (lib::is_mysql_mode()
&& param->get_expr_type() != T_OP_GET_USER_VAR
&& param->get_expr_type() != T_OP_GET_SYS_VAR) {
ret = OB_ER_SP_NOT_VAR_ARG;
LOG_USER_ERROR(OB_ER_SP_NOT_VAR_ARG, static_cast<int32_t>(i), static_cast<int32_t>(sp_name.length()), sp_name.ptr());
LOG_WARN("OUT or INOUT argument for routine is not a variable", K(param->get_expr_type()), K(ret));
} else if (param_info->is_sys_refcursor_type()
|| (param_info->is_pkg_type() && pl_type.is_cursor_type())) {
OZ (call_proc_info->add_out_param(i,
param_info->get_mode(),
param_info->get_param_name(),
pl_type,
param_info->get_type_name(),
session_info_->get_database_name()));
} else {
const ObDatabaseSchema *db_schema = NULL;
CK (OB_NOT_NULL(schema_checker_));
CK (OB_NOT_NULL(schema_checker_->get_schema_mgr()));
OZ (schema_checker_->get_schema_mgr()->get_database_schema(param_info->get_tenant_id(),
param_info->get_type_owner(), db_schema), param_info->get_type_owner());
if (OB_SUCC(ret) && OB_ISNULL(db_schema)) {
ret = OB_ERR_BAD_DATABASE;
LOG_WARN("failed to get type owner", K(param_info->get_type_owner()));
ObString("SYS_REFCURSOR"),
ObString("")));
} else if (param_info->is_complex_type()) { // UDT
if (param_info->get_type_owner() == session_info_->get_database_id()) {
CK (!session_info_->get_database_name().empty());
OZ (call_proc_info->add_out_param(i,
param_info->get_mode(),
param_info->get_param_name(),
pl_type,
param_info->get_type_name(),
session_info_->get_database_name()));
} else {
const ObDatabaseSchema *db_schema = NULL;
CK (OB_NOT_NULL(schema_checker_));
CK (OB_NOT_NULL(schema_checker_->get_schema_mgr()));
OZ (schema_checker_->get_schema_mgr()->get_database_schema(param_info->get_tenant_id(),
param_info->get_type_owner(), db_schema), param_info->get_type_owner());
if (OB_SUCC(ret) && OB_ISNULL(db_schema)) {
ret = OB_ERR_BAD_DATABASE;
LOG_WARN("failed to get type owner", K(param_info->get_type_owner()));
}
OZ (call_proc_info->add_out_param(i,
param_info->get_mode(),
param_info->get_param_name(),
pl_type,
param_info->get_type_name(),
OB_SYS_TENANT_ID == db_schema->get_tenant_id()
? ObString("SYS") : db_schema->get_database_name_str()), i);
}
OZ (stmt->add_out_param(i,
} else if (pl_type.is_user_type()) {
// 通过Call语句执行PL且参数是复杂类型的情况, 仅在PS模式支持, 通过客户端无法构造复杂数据类型;
// PS模式仅支持UDT作为出参, 这里将其他模式的复杂类型出参禁掉;
ret = OB_NOT_SUPPORTED;
LOG_WARN("not supported other type as out parameter except udt", K(ret), K(pl_type.is_user_type()));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "other complex type as out parameter except user define type");
} else {
OZ (call_proc_info->add_out_param(i,
param_info->get_mode(),
param_info->get_param_name(),
pl_type,
param_info->get_type_name(),
OB_SYS_TENANT_ID == db_schema->get_tenant_id()
? ObString("SYS") : db_schema->get_database_name_str()), i);
ObString("")));
}
} else if (pl_type.is_user_type()) {
// 通过Call语句执行PL且参数是复杂类型的情况, 仅在PS模式支持, 通过客户端无法构造复杂数据类型;
// PS模式仅支持UDT作为出参, 这里将其他模式的复杂类型出参禁掉;
ret = OB_NOT_SUPPORTED;
LOG_WARN("not supported other type as out parameter except udt", K(ret), K(pl_type.is_user_type()));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "other complex type as out parameter except user define type");
} else {
OZ (stmt->add_out_param(i,
param_info->get_mode(),
param_info->get_param_name(),
pl_type,
param_info->get_type_name(),
ObString("")));
}
}
}
}
// Step 4: cg raw expr
OX (call_proc_info->set_param_cnt(params.count()));
OZ (call_proc_info->prepare_expression(params));
OZ (call_proc_info->final_expression(params, session_info_, schema_checker_->get_schema_mgr()));
OX (stmt->set_call_proc_info(call_proc_info));
if (params_.is_execute_call_stmt_ && 0 != params_.cur_sql_.length()) {
if (NULL != params_.param_list_) {
OZ (call_proc_info->set_params_info(*params_.param_list_));
}
OZ (add_call_proc_info(call_proc_info));
}
CK (1 == call_proc_info->get_dependency_table().count());
OZ (stmt->add_global_dependency_table(call_proc_info->get_dependency_table().at(0)));
}
return ret;
}

View File

@ -17,6 +17,7 @@
#include "lib/container/ob_se_array.h"
#include "share/ob_rpc_struct.h"
#include "share/schema/ob_schema_struct.h"
#include "pl/pl_cache/ob_pl_cache.h"
namespace oceanbase
{
@ -30,6 +31,7 @@ class ObRoutineInfo;
namespace sql
{
class ObCallProcedureStmt;
class ObCallProcedureInfo;
class ObCallProcedureResolver: public ObCMDResolver
{
public:
@ -40,7 +42,8 @@ public:
private:
int resolve_cparams(const ParseNode* params_node,
const share::schema::ObRoutineInfo *routien_info,
ObCallProcedureStmt *stmt);
ObCallProcedureInfo *call_proc_info,
ObIArray<ObRawExpr*> &params);
int resolve_cparam_without_assign(const ParseNode *param_node,
const int64_t position,
common::ObIArray<ObRawExpr*> &params);
@ -50,6 +53,9 @@ private:
int resolve_param_exprs(const ParseNode *params_node,
ObIArray<ObRawExpr*> &expr_params);
int check_param_expr_legal(ObRawExpr *param);
int find_call_proc_info(ObCallProcedureStmt &stmt);
int add_call_proc_info(ObCallProcedureInfo *call_info);
int generate_pl_cache_ctx(pl::ObPLCacheCtx &pc_ctx);
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObCallProcedureResolver);

View File

@ -21,89 +21,140 @@
#include "ob_call_procedure_stmt.h"
#include "pl/ob_pl_type.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "sql/code_generator/ob_expr_generator_impl.h"
namespace oceanbase
{
namespace sql
{
int ObCallProcedureStmt::deep_copy(ObIAllocator *allocator,
const ObCallProcedureStmt *other)
{
int ret = OB_SUCCESS;
if (this != other) {
CK (OB_NOT_NULL(other));
CK (OB_NOT_NULL(allocator));
OX (can_direct_use_param_ = other->can_direct_use_param_);
OX (package_id_ = other->package_id_);
OX (routine_id_ = other->routine_id_);
OX (param_cnt_ = other->param_cnt_);
OX (out_idx_ = other->out_idx_);
CK (other->out_name_.count() == other->out_type_.count());
CK (other->out_name_.count() == other->out_mode_.count());
CK (other->out_name_.count() == other->out_type_name_.count());
CK (other->out_name_.count() == other->out_type_owner_.count());
for (int64_t i = 0; OB_SUCC(ret) && i < other->out_name_.count(); ++i) {
ObString copy;
pl::ObPLDataType pl_copy_type;
OZ (ob_write_string(*allocator, other->out_name_.at(i), copy));
OZ (out_name_.push_back(copy));
OZ (ob_write_string(*allocator, other->out_type_name_.at(i), copy));
OZ (out_type_name_.push_back(copy));
OZ (ob_write_string(*allocator, other->out_type_owner_.at(i), copy));
OZ (out_type_owner_.push_back(copy));
OZ (pl_copy_type.deep_copy(*allocator, other->out_type_.at(i)));
OZ (out_type_.push_back(pl_copy_type));
OZ (out_mode_.push_back(other->out_mode_.at(i)));
}
for (int64_t i = 0; OB_SUCC(ret) && i < other->in_type_infos_.count(); ++i) {
TypeInfo copy;
OZ (copy.deep_copy(allocator, &(other->in_type_infos_.at(i))));
OZ (in_type_infos_.push_back(copy));
}
OZ (ob_write_string(*allocator, other->db_name_, db_name_));
}
return ret;
}
int ObCallProcedureStmt::add_out_param(
int ObCallProcedureInfo::add_out_param(
int64_t i, int64_t mode, const ObString &name,
const pl::ObPLDataType &type,
const ObString &out_type_name, const ObString &out_type_owner)
{
int ret = OB_SUCCESS;
ObString store_name;
ObString store_out_type_name;
ObString store_out_type_owner;
pl::ObPLDataType pl_data_type;
if (OB_FAIL(out_idx_.add_member(i))) {
LOG_WARN("failed to add out index", K(i), K(name), K(type), K(ret));
} else if (OB_FAIL(out_mode_.push_back(mode))) {
LOG_WARN("failed to push mode", K(ret));
} else if (OB_FAIL(out_name_.push_back(name))) {
} else if (OB_FAIL(ob_write_string(allocator_, name, store_name))) {
LOG_WARN("failed to deep copy name", K(ret), K(name));
} else if (OB_FAIL(out_name_.push_back(store_name))) {
LOG_WARN("push back error", K(i), K(name), K(type), K(ret));
} else if (OB_FAIL(out_type_.push_back(type))) {
} else if (OB_FAIL(pl_data_type.deep_copy(allocator_, type))) {
LOG_WARN("fail to deep copy pl data type", K(type), K(ret));
} else if (OB_FAIL(out_type_.push_back(pl_data_type))) {
LOG_WARN("push back error", K(i), K(name), K(type), K(ret));
} else if (OB_FAIL(out_type_name_.push_back(out_type_name))) {
} else if (OB_FAIL(ob_write_string(allocator_, out_type_name, store_out_type_name))) {
LOG_WARN("failed to deep copy name", K(ret), K(name));
} else if (OB_FAIL(out_type_name_.push_back(store_out_type_name))) {
LOG_WARN("push back error", K(i), K(name), K(type), K(out_type_name), K(ret));
} else if (OB_FAIL(out_type_owner_.push_back(out_type_owner))) {
} else if (OB_FAIL(ob_write_string(allocator_, out_type_owner, store_out_type_owner))) {
LOG_WARN("failed to deep copy name", K(ret), K(name));
} else if (OB_FAIL(out_type_owner_.push_back(store_out_type_owner))) {
LOG_WARN("push back error", K(i), K(name), K(ret), K(out_type_name), K(out_type_owner), K(ret));
} else { /*do nothing*/ }
return ret;
}
int ObCallProcedureStmt::add_params(const common::ObIArray<sql::ObRawExpr*>& params)
int ObCallProcedureInfo::prepare_expression(const common::ObArray<sql::ObRawExpr*> params)
{
int ret = OB_SUCCESS;
ObArray<ObSqlExpression*> array;
for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) {
if (OB_ISNULL(params.at(i))) {
ObSqlExpression *expr = NULL;
if (OB_FAIL(sql_expression_factory_.alloc(expr))) {
LOG_WARN("failed to alloc expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("param at i is null", K(ret), K(i));
} else if (OB_FAIL(params_.push_back(params.at(i)))) {
LOG_WARN("failed to push back", K(ret), K(i));
} else {
param_cnt_++;
}
LOG_WARN("failed to create expr", K(ret));
} else if (OB_FAIL(array.push_back(expr))) {
LOG_WARN("push back error", K(ret));
} else { /*do nothing*/ }
}
OZ (expressions_.assign(array));
return ret;
}
int ObCallProcedureInfo::final_expression(const common::ObArray<sql::ObRawExpr*> params,
ObSQLSessionInfo *session_info,
share::schema::ObSchemaGetterGuard *schema_guard)
{
int ret = OB_SUCCESS;
// generate static engine expressions
sql::ObRawExprUniqueSet raw_exprs(false);
for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); i++) {
OZ(raw_exprs.append(params.at(i)));
}
sql::ObStaticEngineExprCG se_cg(allocator_,
session_info,
schema_guard,
0 /* original param cnt */,
0/* param count*/,
GET_MIN_CLUSTER_VERSION());
se_cg.set_rt_question_mark_eval(true);
OZ(se_cg.generate(raw_exprs, frame_info_));
uint32_t expr_op_size = 0;
RowDesc row_desc;
ObExprGeneratorImpl expr_generator(expr_operator_factory_, 0, 0,
&expr_op_size, row_desc);
for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) {
ObRawExpr *raw_expr = params.at(i);
ObSqlExpression *expression = static_cast<ObSqlExpression*>(expressions_.at(i));
if (OB_ISNULL(raw_expr) || OB_ISNULL(expression)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Invalid arguments", K(i), K(raw_expr), K(expression), K(ret));
} else {
if (OB_FAIL(expr_generator.generate(*raw_expr, *expression))) {
SQL_LOG(WARN, "Generate post_expr error", K(ret), KPC(raw_expr));
} else {
expression->set_expr(raw_expr->rt_expr_);
}
}
}
if (OB_SUCC(ret)) {
expr_op_size_ = std::max(frame_info_.need_ctx_cnt_, static_cast<int64_t>(expr_op_size));
}
return ret;
}
void ObCallProcedureInfo::reset()
{
pl::ObPLCacheObject::reset();
can_direct_use_param_ = false;
package_id_ = common::OB_INVALID_ID;
routine_id_ = common::OB_INVALID_ID;
param_cnt_ = 0;
is_udt_routine_ = false;
}
int ObCallProcedureInfo::check_need_add_cache_obj_stat(ObILibCacheCtx &ctx, bool &need_real_add)
{
int ret = OB_SUCCESS;
//ObPLCacheCtx &pc_ctx = static_cast<ObPLCacheCtx&>(ctx);
//need_real_add = pc_ctx.need_add_obj_stat_;
need_real_add = true;
return ret;
}
void ObCallProcedureInfo::dump_deleted_log_info(const bool is_debug_log /* = true */) const
{
}
}
}

View File

@ -27,57 +27,38 @@
#include "sql/parser/parse_node.h"
#include "sql/resolver/cmd/ob_cmd_stmt.h"
#include "sql/plan_cache/ob_prepare_stmt_struct.h"
#include "pl/pl_cache/ob_pl_cache_object.h"
namespace oceanbase
{
namespace sql
{
class ObCallProcedureStmt : public ObCMDStmt
class ObCallProcedureInfo : public pl::ObPLCacheObject
{
public:
explicit ObCallProcedureStmt(common::ObIAllocator *name_pool)
: ObCMDStmt(name_pool, stmt::T_CALL_PROCEDURE),
explicit ObCallProcedureInfo(lib::MemoryContext &mem_context)
: pl::ObPLCacheObject(ObLibCacheNameSpace::NS_CALLSTMT, mem_context),
can_direct_use_param_(false),
package_id_(common::OB_INVALID_ID),
routine_id_(common::OB_INVALID_ID),
param_cnt_(0),
params_(),
out_idx_(),
out_mode_(),
out_name_(),
out_type_(),
db_name_(),
is_udt_routine_(false),
expr_factory_(NULL) {
is_udt_routine_(false) {
}
ObCallProcedureStmt()
: ObCMDStmt(stmt::T_CALL_PROCEDURE),
can_direct_use_param_(false),
package_id_(common::OB_INVALID_ID),
routine_id_(common::OB_INVALID_ID),
param_cnt_(0),
params_(),
out_idx_(),
out_mode_(),
out_name_(),
out_type_(),
db_name_(),
is_udt_routine_(false),
expr_factory_(NULL) {}
virtual ~ObCallProcedureStmt() {
if (OB_NOT_NULL(expr_factory_)) {
expr_factory_->~ObRawExprFactory();
expr_factory_ = NULL;
}
virtual ~ObCallProcedureInfo() {
}
inline uint64_t get_package_id() const { return package_id_; }
inline void set_package_id(const uint64_t package_id) { package_id_ = package_id; }
inline uint64_t get_routine_id() const { return routine_id_; }
inline void set_routine_id(const uint64_t routine_id) { routine_id_ = routine_id; }
inline const common::ObIArray<sql::ObRawExpr*> &get_params() const { return params_; }
inline common::ObIArray<sql::ObRawExpr*> &get_params() { return params_; }
inline int add_param(sql::ObRawExpr* param) { return params_.push_back(param); }
int add_params(const common::ObIArray<sql::ObRawExpr*>& params);
inline int64_t get_output_count() { return out_idx_.num_members(); }
inline bool is_out_param(int64_t i) { return out_idx_.has_member(i); }
inline ObBitSet<> &get_out_idx() { return out_idx_; }
@ -95,7 +76,10 @@ public:
const ParamTypeInfoArray& get_type_infos() const {
return in_type_infos_;
}
inline void set_db_name(const ObString db_name) { db_name_ = db_name; }
inline int set_db_name(const ObString db_name)
{
return ob_write_string(get_allocator(), db_name, db_name_);
}
const ObString& get_db_name() const { return db_name_; }
//int get_convert_size(int64_t &cv_size) const;
@ -107,13 +91,20 @@ public:
void set_is_udt_routine(bool v) { is_udt_routine_ = v; }
bool is_udt_routine() const { return is_udt_routine_; }
int deep_copy(ObIAllocator *allocator, const ObCallProcedureStmt *other);
int prepare_expression(const common::ObArray<sql::ObRawExpr*> params);
int final_expression(const common::ObArray<sql::ObRawExpr*> params,
ObSQLSessionInfo *session_info,
share::schema::ObSchemaGetterGuard *schema_guard);
virtual void reset();
virtual void dump_deleted_log_info(const bool is_debug_log = true) const;
virtual int check_need_add_cache_obj_stat(ObILibCacheCtx &ctx, bool &need_real_add);
//virtual obrpc::ObDDLArg &get_ddl_arg() { return ddl_arg_; }
TO_STRING_KV(K_(can_direct_use_param),
K_(package_id),
K_(routine_id),
K_(params),
//K_(params),
K_(out_idx),
K_(out_name),
K_(out_type),
@ -125,7 +116,6 @@ private:
uint64_t package_id_;
uint64_t routine_id_;
int64_t param_cnt_;
common::ObArray<sql::ObRawExpr*> params_;
ObBitSet<> out_idx_;
ObSEArray<int64_t, 32> out_mode_;
ObSEArray<ObString, 32> out_name_;
@ -135,11 +125,37 @@ private:
ParamTypeInfoArray in_type_infos_;
ObString db_name_;
bool is_udt_routine_;
ObRawExprFactory *expr_factory_;
DISALLOW_COPY_AND_ASSIGN(ObCallProcedureInfo);
};
class ObCallProcedureStmt : public ObCMDStmt
{
public:
explicit ObCallProcedureStmt()
: ObCMDStmt(NULL, stmt::T_CALL_PROCEDURE),
call_proc_info_(NULL),
cache_call_info_guard_(MAX_HANDLE) {
}
virtual ~ObCallProcedureStmt() {
call_proc_info_ = NULL;
}
void set_call_proc_info(ObCallProcedureInfo *info) {
call_proc_info_ = info;
}
ObCallProcedureInfo *get_call_proc_info() { return call_proc_info_; }
ObCacheObjGuard &get_cacheobj_guard() { return cache_call_info_guard_; }
private:
ObCallProcedureInfo *call_proc_info_;
ObCacheObjGuard cache_call_info_guard_;
DISALLOW_COPY_AND_ASSIGN(ObCallProcedureStmt);
};
}//namespace sql
}//namespace oceanbase