From 57f1c6e7eeb5435ad370f6f1e1e97e5c95cadc4d Mon Sep 17 00:00:00 2001 From: obdev Date: Thu, 27 Apr 2023 16:08:10 +0800 Subject: [PATCH] [FEAT MERGE]:develop pl feature of 4.2 version Co-authored-by: LiuYoung00 Co-authored-by: 0xacc Co-authored-by: seuwebber --- src/pl/CMakeLists.txt | 1 + src/pl/ob_pl.cpp | 130 ++-- src/pl/ob_pl.h | 58 +- src/pl/ob_pl_code_generator.cpp | 150 +++- src/pl/ob_pl_code_generator.h | 2 +- src/pl/ob_pl_interface_pragma.h | 1 + src/pl/ob_pl_package_state.cpp | 22 + src/pl/ob_pl_package_state.h | 2 + src/pl/ob_pl_resolver.cpp | 585 ++++++++------ src/pl/ob_pl_resolver.h | 6 +- src/pl/ob_pl_router.cpp | 28 +- src/pl/ob_pl_router.h | 2 +- src/pl/ob_pl_stmt.cpp | 232 ++++-- src/pl/ob_pl_stmt.h | 160 +++- src/pl/ob_pl_type.h | 8 + src/pl/ob_pl_user_type.cpp | 12 + src/pl/pl_cache/ob_pl_cache.cpp | 17 +- src/pl/pl_cache/ob_pl_cache.h | 9 +- src/pl/pl_cache/ob_pl_cache_mgr.cpp | 9 +- src/pl/pl_cache/ob_pl_cache_mgr.h | 3 +- src/pl/pl_cache/ob_pl_cache_object.cpp | 78 ++ src/pl/pl_cache/ob_pl_cache_object.h | 101 +++ src/pl/sys_package/ob_dbms_session.cpp | 21 + src/pl/sys_package/ob_dbms_session.h | 2 + src/pl/sys_package/ob_dbms_sql.cpp | 62 +- src/pl/sys_package/ob_dbms_sql.h | 13 + src/rootserver/ob_ddl_operator.cpp | 54 +- src/rootserver/ob_ddl_operator.h | 1 - src/rootserver/ob_ddl_service.cpp | 15 +- .../ob_inner_table_schema.12151_12200.cpp | 38 + .../ob_inner_table_schema.15101_15150.cpp | 15 + .../ob_inner_table_schema.15151_15200.cpp | 15 + .../ob_inner_table_schema.251_300.cpp | 38 + .../inner_table/ob_inner_table_schema_def.py | 1 + src/share/ob_rpc_struct.h | 4 +- src/share/schema/ob_routine_info.h | 37 +- src/share/schema/ob_schema_getter_guard.cpp | 101 +++ src/share/schema/ob_schema_getter_guard.h | 8 + src/share/schema/ob_schema_retrieve_utils.ipp | 3 + src/share/schema/ob_table_schema.cpp | 20 + src/share/schema/ob_table_schema.h | 2 + src/share/schema/ob_trigger_info.cpp | 5 +- src/share/schema/ob_trigger_info.h | 41 +- src/share/schema/ob_trigger_sql_service.cpp | 12 + src/sql/code_generator/ob_dml_cg_service.cpp | 26 +- .../code_generator/ob_static_engine_cg.cpp | 2 +- src/sql/engine/cmd/ob_routine_executor.cpp | 90 ++- src/sql/engine/cmd/ob_trigger_executor.cpp | 8 +- src/sql/engine/dml/ob_dml_ctx_define.h | 35 +- src/sql/engine/dml/ob_table_delete_op.cpp | 7 +- src/sql/engine/dml/ob_table_insert_all_op.cpp | 7 +- src/sql/engine/dml/ob_table_insert_op.cpp | 7 +- src/sql/engine/dml/ob_table_insert_up_op.cpp | 14 +- src/sql/engine/dml/ob_table_merge_op.cpp | 21 +- src/sql/engine/dml/ob_table_replace_op.cpp | 18 +- src/sql/engine/dml/ob_table_update_op.cpp | 7 +- src/sql/engine/dml/ob_trigger_handler.cpp | 2 + src/sql/ob_result_set.cpp | 72 +- src/sql/ob_result_set.h | 10 +- src/sql/ob_spi.cpp | 726 +++++++++++++----- src/sql/ob_spi.h | 70 +- src/sql/ob_sql.cpp | 228 +++--- src/sql/ob_sql_context.h | 6 +- src/sql/ob_sql_utils.cpp | 2 +- src/sql/optimizer/ob_optimizer.cpp | 17 +- src/sql/optimizer/ob_optimizer_context.h | 3 + src/sql/plan_cache/ob_lib_cache_register.cpp | 1 + src/sql/plan_cache/ob_lib_cache_register.h | 2 +- src/sql/plan_cache/ob_pc_ref_handle.cpp | 3 +- src/sql/plan_cache/ob_pc_ref_handle.h | 1 + .../privilege_check/ob_privilege_check.cpp | 16 +- .../cmd/ob_call_procedure_resolver.cpp | 461 ++++++----- .../resolver/cmd/ob_call_procedure_resolver.h | 8 +- .../resolver/cmd/ob_call_procedure_stmt.cpp | 153 ++-- src/sql/resolver/cmd/ob_call_procedure_stmt.h | 84 +- .../ddl/ob_create_package_resolver.cpp | 28 +- .../ddl/ob_create_routine_resolver.cpp | 27 +- .../resolver/ddl/ob_create_routine_resolver.h | 1 + src/sql/resolver/ddl/ob_trigger_resolver.cpp | 10 + src/sql/resolver/dml/ob_dml_resolver.cpp | 413 +++++++++- src/sql/resolver/dml/ob_dml_resolver.h | 1 + src/sql/resolver/dml/ob_dml_stmt.cpp | 5 +- src/sql/resolver/dml/ob_dml_stmt.h | 3 + src/sql/resolver/expr/ob_raw_expr.h | 2 + src/sql/resolver/ob_resolver_define.h | 1 + src/sql/resolver/ob_resolver_utils.h | 1 + src/sql/session/ob_basic_session_info.cpp | 22 + src/sql/session/ob_basic_session_info.h | 4 + src/sql/session/ob_sql_session_info.cpp | 59 +- src/sql/session/ob_sql_session_info.h | 1 + .../pl/r/mysql/pl_basic_mysql.result | 10 +- .../test_suite/pl/r/mysql/sp_mysql.result | 19 +- 92 files changed, 3534 insertions(+), 1304 deletions(-) create mode 100644 src/pl/pl_cache/ob_pl_cache_object.cpp create mode 100644 src/pl/pl_cache/ob_pl_cache_object.h diff --git a/src/pl/CMakeLists.txt b/src/pl/CMakeLists.txt index 0da883ab3..dc61e4e1e 100644 --- a/src/pl/CMakeLists.txt +++ b/src/pl/CMakeLists.txt @@ -39,6 +39,7 @@ ob_set_subtarget(ob_pl common ob_set_subtarget(ob_pl common_mixed pl_cache/ob_pl_cache.cpp pl_cache/ob_pl_cache_mgr.cpp + pl_cache/ob_pl_cache_object.cpp ) ob_set_subtarget(ob_pl sys_package diff --git a/src/pl/ob_pl.cpp b/src/pl/ob_pl.cpp index be737a8cc..05bcab3a6 100644 --- a/src/pl/ob_pl.cpp +++ b/src/pl/ob_pl.cpp @@ -966,36 +966,43 @@ int ObPLContext::set_role_id_array(ObPLFunction &routine, if (ObSchemaChecker::is_ora_priv_check() && !routine.is_invoker_right() && routine.get_proc_type() != STANDALONE_ANONYMOUS) { - uint64_t priv_user_id = OB_INVALID_ID; - CK (OB_NOT_NULL(session_info_)); - /* 1. save in definer, just for more information */ - OX (old_in_definer_ = session_info_->get_in_definer_named_proc()); - OX (session_info_->set_in_definer_named_proc(true)); - if (OB_SUCC(ret)) { - if (0 == session_info_->get_database_name().case_compare(OB_SYS_DATABASE_NAME)) { - OX (priv_user_id = OB_ORA_SYS_USER_ID); - } else { - OZ (guard.get_user_id(session_info_->get_effective_tenant_id(), - session_info_->get_database_name(), - ObString(OB_DEFAULT_HOST_NAME), - priv_user_id, - false)); + bool is_special_ir = false; + if (OB_FAIL(routine.is_special_pkg_invoke_right(guard, is_special_ir))){ + LOG_WARN("failed to check special pkg invoke right", K(ret)); + } else if (is_special_ir){ + need_reset_role_id_array_ = false; + } else { + uint64_t priv_user_id = OB_INVALID_ID; + CK (OB_NOT_NULL(session_info_)); + /* 1. save in definer, just for more information */ + OX (old_in_definer_ = session_info_->get_in_definer_named_proc()); + OX (session_info_->set_in_definer_named_proc(true)); + if (OB_SUCC(ret)) { + if (0 == session_info_->get_database_name().case_compare(OB_SYS_DATABASE_NAME)) { + OX (priv_user_id = OB_ORA_SYS_USER_ID); + } else { + OZ (guard.get_user_id(session_info_->get_effective_tenant_id(), + session_info_->get_database_name(), + ObString(OB_DEFAULT_HOST_NAME), + priv_user_id, + false)); + } } + if (OB_SUCC(ret) && OB_INVALID_ID == priv_user_id) { + ret = OB_USER_NOT_EXIST; + LOG_WARN("fail to get procedure owner id", + K(session_info_->get_effective_tenant_id()), + K(session_info_->get_database_name())); + } + /* 2. save priv user id, and set new priv user id, change grantee_id, for priv check */ + OX (old_priv_user_id_ = session_info_->get_priv_user_id()); + OX (session_info_->set_priv_user_id(priv_user_id)); + /* 3. save role id array , remove role id array for priv check */ + OZ (old_role_id_array_.assign(session_info_->get_enable_role_array())); + OX (session_info_->get_enable_role_array().reset()); + OZ (session_info_->get_enable_role_array().push_back(OB_ORA_PUBLIC_ROLE_ID)); + OX (need_reset_role_id_array_ = true); } - if (OB_SUCC(ret) && OB_INVALID_ID == priv_user_id) { - ret = OB_USER_NOT_EXIST; - LOG_WARN("fail to get procedure owner id", - K(session_info_->get_effective_tenant_id()), - K(session_info_->get_database_name())); - } - /* 2. save priv user id, and set new priv user id, change grantee_id, for priv check */ - OX (old_priv_user_id_ = session_info_->get_priv_user_id()); - OX (session_info_->set_priv_user_id(priv_user_id)); - /* 3. save role id array , remove role id array for priv check */ - OZ (old_role_id_array_.assign(session_info_->get_enable_role_array())); - OX (session_info_->get_enable_role_array().reset()); - OZ (session_info_->get_enable_role_array().push_back(OB_ORA_PUBLIC_ROLE_ID)); - OX (need_reset_role_id_array_ = true); } else if (lib::is_mysql_mode() && !routine.is_invoker_right() && 0 != routine.get_priv_user().length() /* 兼容存量存储过程,存量存储过程的priv_user为空。mysql存储过程默认为definer行为, @@ -3451,59 +3458,6 @@ ObPLCompileUnit::~ObPLCompileUnit() } } -void ObPLCompileUnit::reset() -{ - ObILibCacheObject::reset(); - tenant_schema_version_ = OB_INVALID_VERSION; - sys_schema_version_ = OB_INVALID_VERSION; - dependency_tables_.reset(); - params_info_.reset(); -} - -int ObPLCompileUnit::set_params_info(const ParamStore ¶ms) -{ - int ret = OB_SUCCESS; - int64_t N = params.count(); - ObParamInfo param_info; - if (N > 0 && OB_FAIL(params_info_.reserve(N))) { - OB_LOG(WARN, "fail to reserve params info", K(ret)); - } - for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { - param_info.flag_ = params.at(i).get_param_flag(); - param_info.type_ = params.at(i).get_param_meta().get_type(); - param_info.col_type_ = params.at(i).get_collation_type(); - if (ObSQLUtils::is_oracle_empty_string(params.at(i))) { - param_info.is_oracle_empty_string_ = true; - } - if (params.at(i).get_param_meta().get_type() != params.at(i).get_type()) { - LOG_TRACE("differ in set_params_info", - K(params.at(i).get_param_meta().get_type()), - K(params.at(i).get_type()), - K(common::lbt())); - } - //todo:it is for arraybinding check, not pl ext check - if (params.at(i).is_ext()) { - ObDataType data_type; - if (OB_FAIL(ObSQLUtils::get_ext_obj_data_type(params.at(i), data_type))) { - LOG_WARN("fail to get ext obj data type", K(ret)); - } else { - param_info.ext_real_type_ = data_type.get_obj_type(); - param_info.scale_ = data_type.get_meta_type().get_scale(); - } - LOG_DEBUG("ext params info", K(data_type), K(param_info), K(params.at(i))); - } else { - param_info.scale_ = params.at(i).get_scale(); - } - if (OB_SUCC(ret)) { - if (OB_FAIL(params_info_.push_back(param_info))) { - LOG_WARN("failed to push back param info", K(ret)); - } - } - param_info.reset(); - } - return ret; -} - int ObPLCompileUnit::add_routine(ObPLFunction *routine) { int ret = OB_SUCCESS; @@ -3526,6 +3480,14 @@ int ObPLCompileUnit::get_routine(int64_t routine_idx, ObPLFunction *&routine) co return ret; } +void ObPLCompileUnit::reset() +{ + ObPLCacheObject::reset(); + tenant_schema_version_ = OB_INVALID_VERSION; + sys_schema_version_ = OB_INVALID_VERSION; + dependency_tables_.reset(); +} + int ObPLCompileUnit::check_need_add_cache_obj_stat(ObILibCacheCtx &ctx, bool &need_real_add) { @@ -3771,12 +3733,14 @@ int ObPLFunction::is_special_pkg_invoke_right(ObSchemaGetterGuard &guard, bool & static const char *name_pair[] = { "dbms_utility", "name_resolve" }; static const char *name_pair1[] = { "dbms_utility", "ICD_NAME_RES" }; static const char *name_pair2[] = { "dbms_utility", "old_current_schema" }; - static const char *name_pair3[] = { "dbms_describe", "describe_procedure" }; + static const char *name_pair3[] = { "dbms_utility", "exec_ddl_statement" }; + static const char *name_pair4[] = { "dbms_describe", "describe_procedure" }; static name_pair_ptr name_arr[] = { &name_pair, &name_pair1, &name_pair2, - &name_pair3 + &name_pair3, + &name_pair4 // { "dbms_utility", "name_resolve" } }; int ret = OB_SUCCESS; diff --git a/src/pl/ob_pl.h b/src/pl/ob_pl.h index 0ed2e327c..4495b39b2 100644 --- a/src/pl/ob_pl.h +++ b/src/pl/ob_pl.h @@ -34,6 +34,7 @@ #include "pl/ob_pl_interface_pragma.h" #include "sql/plan_cache/ob_cache_object_factory.h" #include "pl/pl_cache/ob_pl_cache.h" +#include "pl/pl_cache/ob_pl_cache_object.h" namespace test { @@ -260,27 +261,17 @@ private: DISALLOW_COPY_AND_ASSIGN(ObPLFunctionBase); }; -class ObPLCompileUnit : public sql::ObILibCacheObject +class ObPLCompileUnit : public ObPLCacheObject { friend class ::test::MockCacheObjectFactory; public: ObPLCompileUnit(sql::ObLibCacheNameSpace ns, lib::MemoryContext &mem_context) - : ObILibCacheObject(ns, mem_context), - tenant_schema_version_(OB_INVALID_VERSION), - sys_schema_version_(OB_INVALID_VERSION), - dependency_tables_(allocator_), - params_info_( (ObWrapperAllocator(allocator_)) ), + : ObPLCacheObject(ns, mem_context), routine_table_(allocator_), type_table_(), - expr_factory_(allocator_), helper_(allocator_), di_helper_(allocator_), - sql_expression_factory_(allocator_), - expr_operator_factory_(allocator_), - expressions_(allocator_), - expr_op_size_(0), - can_cached_(true), - frame_info_(allocator_) + can_cached_(true) { #ifndef USE_MCJIT helper_.init(); @@ -288,20 +279,6 @@ public: } virtual ~ObPLCompileUnit(); - inline int64_t get_dependency_table_size() const { return dependency_tables_.count(); } - inline const DependenyTableStore &get_dependency_table() const { return dependency_tables_; } - inline void set_sys_schema_version(int64_t schema_version) { sys_schema_version_ = schema_version; } - inline void set_tenant_schema_version(int64_t schema_version) { tenant_schema_version_ = schema_version; } - inline int64_t get_tenant_schema_version() const { return tenant_schema_version_; } - inline int64_t get_sys_schema_version() const { return sys_schema_version_; } - int init_dependency_table_store(int64_t dependency_table_cnt) { return dependency_tables_.init(dependency_table_cnt); } - inline DependenyTableStore &get_dependency_table() { return dependency_tables_; } - - int set_params_info(const ParamStore ¶ms); - const common::Ob2DArray &get_params_info() const { return params_info_; } - inline bool get_can_cached() { return can_cached_; } inline void set_can_cached(bool can_cached) { can_cached_ = can_cached; } inline const ObIArray &get_routine_table() const { return routine_table_; } @@ -314,54 +291,29 @@ public: int get_routine(int64_t routine_idx, ObPLFunction *&routine) const; void init_routine_table(int64_t count) { routine_table_.set_capacity(static_cast(count)); } inline const ObIArray &get_type_table() const { return type_table_; } - inline sql::ObRawExprFactory &get_expr_factory() { return expr_factory_; } inline jit::ObLLVMHelper &get_helper() { return helper_; } inline jit::ObLLVMDIHelper &get_di_helper() { return di_helper_; } - inline sql::ObSqlExpressionFactory &get_sql_expression_factory() { return sql_expression_factory_; } - inline sql::ObExprOperatorFactory &get_expr_operator_factory() { return expr_operator_factory_; } - inline const common::ObIArray &get_expressions() const { return expressions_; } - inline common::ObIArray &get_expressions() { return expressions_; } - inline int set_expressions(common::ObIArray &exprs) { return expressions_.assign(exprs); } - inline int64_t get_expr_op_size() const { return expr_op_size_; } - inline void set_expr_op_size(int64_t size) { expr_op_size_ = size; } - inline sql::ObExprFrameInfo &get_frame_info() { return frame_info_; } jit::ObDIRawData get_debug_info() const { return helper_.get_debug_info(); } 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); - TO_STRING_KV(K_(routine_table), K(expr_op_size_), K_(can_cached), + TO_STRING_KV(K_(routine_table), K_(can_cached), K_(tenant_schema_version), K_(sys_schema_version)); protected: - int64_t tenant_schema_version_; - int64_t sys_schema_version_; - DependenyTableStore dependency_tables_; - - //stored args information after paramalization - common::Ob2DArray params_info_; common::ObFixedArray routine_table_; common::ObArray type_table_; - sql::ObRawExprFactory expr_factory_; jit::ObLLVMHelper helper_; jit::ObLLVMDIHelper di_helper_; - sql::ObSqlExpressionFactory sql_expression_factory_; - sql::ObExprOperatorFactory expr_operator_factory_; - common::ObFixedArray expressions_; - int64_t expr_op_size_; - bool can_cached_; - sql::ObExprFrameInfo frame_info_; - DISALLOW_COPY_AND_ASSIGN(ObPLCompileUnit); }; diff --git a/src/pl/ob_pl_code_generator.cpp b/src/pl/ob_pl_code_generator.cpp index 2537c47b1..2cf37c92d 100644 --- a/src/pl/ob_pl_code_generator.cpp +++ b/src/pl/ob_pl_code_generator.cpp @@ -1149,7 +1149,6 @@ int ObPLCodeGenerateVisitor::visit(const ObPLCursorForLoopStmt &s) s.get_index(), static_cast(INT64_MAX), s.get_user_type(), - s.get_expand_user_types(), ret_err)); OZ (generator_.get_helper().create_icmp_eq(ret_err, OB_READ_NOTHING, is_not_found)); OZ (generator_.get_helper().stack_restore(stack)); @@ -1645,7 +1644,7 @@ int ObPLCodeGenerateVisitor::visit(const ObPLExecuteStmt &s) ObLLVMValue exprs_not_null_array_value; ObLLVMValue pl_integer_range_array_value; ObLLVMValue is_bulk; - ObLLVMValue is_returning; + ObLLVMValue is_returning, is_type_record; ObLLVMValue ret_err; OZ (generator_.get_helper().set_insert_point(generator_.get_current())); @@ -1738,6 +1737,8 @@ int ObPLCodeGenerateVisitor::visit(const ObPLExecuteStmt &s) OZ (args.push_back(is_bulk)); OZ (generator_.get_helper().get_int8(s.get_is_returning(), is_returning)); OZ (args.push_back(is_returning)); + OZ (generator_.get_helper().get_int8(s.is_type_record(), is_type_record)); + OZ (args.push_back(is_type_record)); // execution OZ (generator_.get_helper().create_call( @@ -2735,7 +2736,6 @@ int ObPLCodeGenerateVisitor::visit(const ObPLFetchStmt &s) s.get_index(), s.get_limit(), s.get_user_type(), - s.get_expand_user_types(), ret_err))) { LOG_WARN("failed to generate fetch", K(ret)); } else if (lib::is_mysql_mode()) { //Mysql模式直接检查抛出异常 @@ -3048,6 +3048,100 @@ int ObPLCodeGenerateVisitor::visit(const ObPLDoStmt &s) return ret; } +int ObPLCodeGenerateVisitor::visit(const ObPLCaseStmt &s) +{ + int ret = OB_SUCCESS; + if (NULL == generator_.get_current().get_v()) { + //控制流已断,后面的语句不再处理 + } else if (OB_FAIL(generator_.get_helper().set_insert_point(generator_.get_current()))) { + LOG_WARN("failed to set insert point", K(ret)); + } else if (OB_FAIL(generator_.set_debug_location(s))) { + LOG_WARN("failed to set debug location", K(ret)); + } else if (OB_FAIL(generator_.generate_goto_label(s))) { + LOG_WARN("failed to generate goto label", K(ret)); + } else { + // generate case expr, if any + if (s.get_case_expr() != OB_INVALID_ID) { + int64_t case_expr_idx = s.get_case_expr(); + int64_t case_var_idx = s.get_case_var(); + ObLLVMValue p_result_obj; + if (OB_FAIL(generator_.generate_expr(case_expr_idx, s, case_var_idx, p_result_obj))) { + LOG_WARN("failed to generate calc_expr func", K(ret)); + } + } + + // generate when clause + ObLLVMBasicBlock continue_branch; + if (OB_SUCC(ret)) { + if (OB_FAIL(generator_.get_helper().create_block( + ObString("continue"), generator_.get_func(), continue_branch))) { + LOG_WARN("faild to create continue branch for case stmt", K(ret)); + } else { + const ObPLCaseStmt::WhenClauses &when = s.get_when_clauses(); + for (int64_t i = 0; OB_SUCC(ret) && i < when.count(); ++i) { + const ObPLCaseStmt::WhenClause ¤t_when = when.at(i); + const sql::ObRawExpr *expr = s.get_expr(current_when.expr_); + ObLLVMBasicBlock current_then; + ObLLVMBasicBlock current_else; + ObLLVMValue p_cond; + ObLLVMValue cond; + ObLLVMValue is_false; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected nullptr to when expr", K(i), K(current_when)); + } else if (OB_FAIL(generator_.get_helper().create_block( + ObString("then"), generator_.get_func(), current_then))) { + LOG_WARN("failed to create then branch for case stmt", K(ret)); + } else if (OB_FAIL(generator_.get_helper().create_block( + ObString("else"), generator_.get_func(), current_else))) { + LOG_WARN("failed to create else branch for case stmt", K(ret)); + } else if (OB_FAIL(generator_.generate_expr( + current_when.expr_, s, OB_INVALID_INDEX, p_cond))) { + LOG_WARN("failed to generate calc_expr func", K(ret)); + } else if (OB_FAIL(generator_.extract_value_from_objparam( + p_cond, expr->get_data_type(), cond))) { + LOG_WARN("failed to extract_value_from_objparam", K(ret)); + } else if (OB_FAIL(generator_.get_helper().create_icmp_eq( + cond, FALSE, is_false))) { + LOG_WARN("failed to create_icmp_eq", K(ret)); + } else if (OB_FAIL(generator_.get_helper().create_cond_br( + is_false, current_else, current_then))) { + LOG_WARN("failed to create_cond_br", K(ret)); + } else if (OB_FAIL(generator_.set_current(current_then))) { + LOG_WARN("failed to set current to current_then branch", K(ret)); + } else if (OB_FAIL(visit(*current_when.body_))) { + LOG_WARN("failed to visit then clause for case stmt", K(ret)); + } else if (OB_FAIL(generator_.finish_current(continue_branch))) { + LOG_WARN("failed to finish current", K(ret)); + } else if (OB_FAIL(generator_.set_current(current_else))) { + LOG_WARN("failed to set current to current_else branch", K(ret)); + } else { + // do nothing + } + } + } + } + + // generate else + if (OB_SUCC(ret)) { + const ObPLStmtBlock *else_clause = s.get_else_clause(); + if (OB_ISNULL(else_clause)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("else in CASE stmt is NULL in CG", K(s), K(ret)); + } else if (OB_FAIL(visit(*else_clause))) { + LOG_WARN("failed to visit else clause for case stmt", K(ret)); + } else if (OB_FAIL(generator_.finish_current(continue_branch))) { + LOG_WARN("failed to finish current", K(ret)); + } else if (OB_FAIL(generator_.set_current(continue_branch))) { + LOG_WARN("failed to set current", K(ret)); + } else { + // do nohting + } + } + } + return ret; +} + int ObPLCodeGenerateVisitor::find_next_procedence_condition(common::ObIArray> &conditions, common::ObIArray &position_map, int64_t &idx) { @@ -3394,6 +3488,8 @@ int ObPLCodeGenerator::init_spi_service() LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(arg_types.push_back(bool_type))) { LOG_WARN("push_back error", K(ret)); + } else if (OB_FAIL(arg_types.push_back(bool_type))) { + LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(ObLLVMFunctionType::get(int32_type, arg_types, ft))) { LOG_WARN("failed to get function type", K(ret)); } else if (OB_FAIL(helper_.create_function(ObString("spi_set_variable"), ft, spi_service_.spi_set_variable_))) { @@ -3425,6 +3521,8 @@ int ObPLCodeGenerator::init_spi_service() LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(arg_types.push_back(bool_type))) { LOG_WARN("push_back error", K(ret)); + } else if (OB_FAIL(arg_types.push_back(bool_type))) { + LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(ObLLVMFunctionType::get(int32_type, arg_types, ft))) { LOG_WARN("failed to get function type", K(ret)); } else if (OB_FAIL(helper_.create_function(ObString("spi_query"), ft, spi_service_.spi_query_))) { @@ -3471,6 +3569,8 @@ int ObPLCodeGenerator::init_spi_service() LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(arg_types.push_back(bool_type))) { LOG_WARN("push_back error", K(ret)); + } else if (OB_FAIL(arg_types.push_back(bool_type))) { + LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(ObLLVMFunctionType::get(int32_type, arg_types, ft))) { LOG_WARN("failed to get function type", K(ret)); } else if (OB_FAIL(helper_.create_function(ObString("spi_execute"), ft, spi_service_.spi_execute_))) { @@ -3506,6 +3606,8 @@ int ObPLCodeGenerator::init_spi_service() LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(arg_types.push_back(bool_type))) { LOG_WARN("push_back error", K(ret)); + } else if (OB_FAIL(arg_types.push_back(bool_type))) { + LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(ObLLVMFunctionType::get(int32_type, arg_types, ft))) { LOG_WARN("failed to get function type", K(ret)); } else if (OB_FAIL(helper_.create_function(ObString("spi_execute_immediate"), ft, spi_service_.spi_execute_immediate_))) { @@ -3661,6 +3763,7 @@ int ObPLCodeGenerator::init_spi_service() OZ (arg_types.push_back(int64_type));//limit OZ (arg_types.push_back(data_type_pointer_type));//return_type OZ (arg_types.push_back(int64_type));//return_type_count + OZ (arg_types.push_back(bool_type));//is_type_record OZ (ObLLVMFunctionType::get(int32_type, arg_types, ft)); OZ (helper_.create_function(ObString("spi_cursor_fetch"), ft, spi_service_.spi_cursor_fetch_)); } @@ -4621,7 +4724,6 @@ int ObPLCodeGenerator::generate_fetch(const ObPLStmt &s, const int64_t &cursor_index, const int64_t &limit, const ObUserDefinedType *user_defined_type, - const ObIArray &user_types, jit::ObLLVMValue &ret_err) { int ret = OB_SUCCESS; @@ -4651,7 +4753,7 @@ int ObPLCodeGenerator::generate_fetch(const ObPLStmt &s, ObLLVMValue type_count_value; ObLLVMValue exprs_not_null_array_value; ObLLVMValue pl_integer_array_value; - ObLLVMValue is_bulk; + ObLLVMValue is_bulk, is_type_record; OZ (generate_into(into, into_array_value, into_count_value, type_array_value, type_count_value, exprs_not_null_array_value, @@ -4709,31 +4811,46 @@ int ObPLCodeGenerator::generate_fetch(const ObPLStmt &s, OZ (ObLLVMHelper::get_null_const(data_type_pointer, return_type_array_value)); OZ (helper_.get_int64(0, return_type_count_value)); } else { + const ObRecordType *return_type = static_cast(user_defined_type); + const ObPLDataType *pl_data_type = nullptr; + CK (OB_NOT_NULL(return_type)); OZ (adt_service_.get_data_type(data_type)); OZ (data_type.get_pointer_to(data_type_pointer)); OZ (ObLLVMHelper::get_array_type(data_type, - user_types.count(), + return_type->get_record_member_count(), array_type)); OZ (helper_.create_alloca(ObString("datatype_array"), array_type, return_type_array_value)); - for (int64_t i = 0; OB_SUCC(ret) && i < user_types.count(); ++i) { + for (int64_t i = 0; OB_SUCC(ret) && i < return_type->get_record_member_count(); ++i) { type_value.reset(); OZ (helper_.create_gep(ObString("extract_datatype"), return_type_array_value, i, type_value)); - OZ (store_data_type(user_types.at(i), type_value)); + pl_data_type = return_type->get_record_member_type(i); + CK (OB_NOT_NULL(pl_data_type)); + if (OB_SUCC(ret)) { + if (pl_data_type->is_obj_type()) { + OZ (store_data_type(*(pl_data_type->get_data_type()), type_value)); + } else { // 构造函数场景 + ObDataType ext_type; + ext_type.set_obj_type(ObExtendType); + OZ (store_data_type(ext_type, type_value)); + } + } } OZ (helper_.create_bit_cast(ObString("datatype_array_to_pointer"), return_type_array_value, data_type_pointer, return_type_array_value)); - OZ (helper_.get_int64(static_cast(user_types.count()), + OZ (helper_.get_int64(static_cast(return_type->get_record_member_count()), return_type_count_value)); } OZ (args.push_back(return_type_array_value)); OZ (args.push_back(return_type_count_value)); + OZ (helper_.get_int8(static_cast(into.is_type_record()), is_type_record)); + OZ (args.push_back(is_type_record)); OZ (get_helper().create_call(ObString("spi_cursor_fetch"), get_spi_service().spi_cursor_fetch_, @@ -5157,7 +5274,7 @@ int ObPLCodeGenerator::generate_sql(const ObPLSqlStmt &s, ObLLVMValue &ret_err) ObLLVMValue for_update; ObLLVMValue hidden_rowid; ObLLVMValue params; - ObLLVMValue count; + ObLLVMValue count, is_type_record; OZ (args.push_back(get_vars().at(CTX_IDX))); OZ (generate_sql(s, str, len, ps_sql, type, for_update, hidden_rowid, params, count)); if (OB_SUCC(ret)) { @@ -5194,12 +5311,16 @@ int ObPLCodeGenerator::generate_sql(const ObPLSqlStmt &s, ObLLVMValue &ret_err) } if (OB_SUCC(ret)) { if (s.get_params().empty()) { + OZ (get_helper().get_int8(static_cast(s.is_type_record()), is_type_record)); + OZ (args.push_back(is_type_record)); OZ (args.push_back(for_update)); OZ (get_helper().create_call(ObString("spi_query"), get_spi_service().spi_query_, args, ret_err)); } else { //有外部变量,走prepare/execute接口 ObLLVMValue is_forall; OZ (get_helper().get_int8(static_cast(s.is_forall_sql()), is_forall)); OZ (args.push_back(is_forall)); + OZ (get_helper().get_int8(static_cast(s.is_type_record()), is_type_record)); + OZ (args.push_back(is_type_record)); OZ (args.push_back(for_update)); OZ (get_helper().create_call(ObString("spi_execute"), get_spi_service().spi_execute_, args, ret_err)); } @@ -6425,6 +6546,9 @@ int ObPLCodeGenerator::generate_into(const ObPLInto &into, K(into.get_data_type()), K(into.get_not_null_flags()), K(into.get_pl_integer_ranges())); + } else if (into.is_type_record() && 1 != into.get_into_data_type().count()) { + ret = OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("coercion into multiple record targets not supported", K(ret)); } else { ObLLVMType data_type; ObLLVMType data_type_pointer; @@ -6562,7 +6686,7 @@ int ObPLCodeGenerator::generate_set_variable(int64_t expr, int ret = OB_SUCCESS; ObSEArray args; ObLLVMValue expr_addr; - ObLLVMValue is_default_value; + ObLLVMValue is_default_value, need_copy; ObLLVMValue result; if (OB_FAIL(args.push_back(get_vars().at(CTX_IDX)))) { //PL的执行环境 LOG_WARN("push_back error", K(ret)); @@ -6576,6 +6700,10 @@ int ObPLCodeGenerator::generate_set_variable(int64_t expr, LOG_WARN("failed tio get int8", K(is_default), K(ret)); } else if (OB_FAIL(args.push_back(is_default_value))) { //is_default LOG_WARN("push_back error", K(ret)); + } else if (OB_FAIL(helper_.get_int8(false, need_copy))) { + LOG_WARN("failed tio get int8", K(ret)); + } else if (OB_FAIL(args.push_back(need_copy))) { + LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(get_helper().create_call(ObString("spi_set_variable"), get_spi_service().spi_set_variable_, args, result))) { LOG_WARN("failed to create call", K(ret)); } else if (OB_FAIL(check_success(result, stmt_id, in_notfound, in_warning))) { diff --git a/src/pl/ob_pl_code_generator.h b/src/pl/ob_pl_code_generator.h index 2aac45dd9..fcd160ea9 100644 --- a/src/pl/ob_pl_code_generator.h +++ b/src/pl/ob_pl_code_generator.h @@ -268,7 +268,6 @@ public: const int64_t &cursor_index, const int64_t &limit, const ObUserDefinedType *user_defined_type, - const ObIArray &user_types, jit::ObLLVMValue &ret_err); int generate_close(const ObPLStmt &s, const uint64_t &package_id, @@ -786,6 +785,7 @@ public: virtual int visit(const ObPLTrimStmt &s); virtual int visit(const ObPLInterfaceStmt &s); virtual int visit(const ObPLDoStmt &s); + virtual int visit(const ObPLCaseStmt &s); private: int find_next_procedence_condition(common::ObIArray> &conditions, diff --git a/src/pl/ob_pl_interface_pragma.h b/src/pl/ob_pl_interface_pragma.h index ba74e0067..b2eeb5f97 100644 --- a/src/pl/ob_pl_interface_pragma.h +++ b/src/pl/ob_pl_interface_pragma.h @@ -116,6 +116,7 @@ INTERFACE_DEF(INTERFACE_DBMS_SESSION_CLEAR_IDENTIFIER, "CLEAR_IDENTIFIER", (ObDBMSSession::clear_identifier)) INTERFACE_DEF(INTERFACE_DBMS_SESSION_SET_CONTEXT, "SET_CONTEXT", (ObDBMSSession::set_context)) INTERFACE_DEF(INTERFACE_DBMS_SESSION_SET_IDENTIFIER, "SET_IDENTIFIER", (ObDBMSSession::set_identifier)) + INTERFACE_DEF(INTERFACE_DBMS_SESSION_RESET_PACKAGE, "RESET_PACKAGE", (ObDBMSSession::reset_package)) // end of dbms_session // start of dbms_udr diff --git a/src/pl/ob_pl_package_state.cpp b/src/pl/ob_pl_package_state.cpp index 736ee4558..b432b7bbd 100644 --- a/src/pl/ob_pl_package_state.cpp +++ b/src/pl/ob_pl_package_state.cpp @@ -353,5 +353,27 @@ int ObPLPackageState::convert_changed_info_to_string_kvs(ObPLExecCtx &pl_ctx, Ob return ret; } +int ObPLPackageState::remove_user_variables_for_package_state(ObSQLSessionInfo &session) +{ + int ret = OB_SUCCESS; + int64_t var_count = vars_.count(); + ObArenaAllocator allocator(ObModIds::OB_PL_TEMP); + ObString key; + for (int64_t var_idx = 0; var_idx < var_count; var_idx++) { + // ignore error code, reset all variables + key.reset(); + if (OB_FAIL(make_pkg_var_kv_key(allocator, var_idx, VARIABLE, key))) { + LOG_WARN("make package var name failed", K(ret), K(package_id_), K(var_idx)); + } else if (session.user_variable_exists(key)) { + if (OB_FAIL(session.remove_user_variable(key))) { + LOG_WARN("fail to remove user var", K(ret), K(key), K(package_id_), K(var_idx)); + } else if (OB_FAIL(session.remove_changed_user_var(key))) { + LOG_WARN("fail to remove change user var", K(ret), K(key), K(package_id_), K(var_idx)); + } + } + } + return ret; +} + } // end namespace pl } // end namespace oceanbase diff --git a/src/pl/ob_pl_package_state.h b/src/pl/ob_pl_package_state.h index d334cd426..9829bedf8 100644 --- a/src/pl/ob_pl_package_state.h +++ b/src/pl/ob_pl_package_state.h @@ -166,6 +166,8 @@ public: common::ObString &key, common::ObObj &value); inline bool get_serially_reusable() const { return serially_reusable_; } + int remove_user_variables_for_package_state(ObSQLSessionInfo &session); + uint64_t get_package_id() { return package_id_; } ObIArray &get_vars() { return vars_; } diff --git a/src/pl/ob_pl_resolver.cpp b/src/pl/ob_pl_resolver.cpp index bb16af2dc..aa04a2452 100644 --- a/src/pl/ob_pl_resolver.cpp +++ b/src/pl/ob_pl_resolver.cpp @@ -342,7 +342,7 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun } break; case T_SP_CASE: { - RESOLVE_STMT(PL_IF, resolve_case, ObPLIfStmt); + RESOLVE_STMT(PL_CASE, resolve_case, ObPLCaseStmt); } break; case T_SP_ITERATE: { @@ -363,10 +363,14 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun break; case T_SP_CURSOR_FOR_LOOP: { RESOLVE_STMT(PL_CURSOR_FOR_LOOP, resolve_cursor_for_loop, ObPLCursorForLoopStmt); + if (!func.is_modifies_sql_data()) { + func.set_reads_sql_data(); + } } break; case T_SP_FORALL: { RESOLVE_STMT(PL_FORALL, resolve_forall, ObPLForAllStmt); + func.set_modifies_sql_data(); } break; case T_SP_REPEAT: { @@ -396,10 +400,16 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun break; case T_SP_EXECUTE_IMMEDIATE: { RESOLVE_STMT(PL_EXECUTE, resolve_execute_immediate, ObPLExecuteStmt); + func.set_modifies_sql_data(); } break; case T_SP_DO: { - RESOLVE_STMT(PL_DO, resolve_do, ObPLDoStmt); + RESOLVE_STMT(PL_DO, resolve_do, ObPLDoStmt); + if (lib::is_mysql_mode()) { + if (!func.is_reads_sql_data() && !func.is_modifies_sql_data()) { + func.set_contains_sql(); + } + } } break; case T_SP_EXTEND: { @@ -440,14 +450,21 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun break; case T_SP_RESIGNAL: { RESOLVE_STMT(PL_SIGNAL, resolve_resignal, ObPLSignalStmt); + if (lib::is_mysql_mode() && !func.is_reads_sql_data() && !func.is_modifies_sql_data()) { + func.set_contains_sql(); + } } break; case T_SP_SIGNAL: { RESOLVE_STMT(PL_SIGNAL, resolve_signal, ObPLSignalStmt); + if (lib::is_mysql_mode() && !func.is_reads_sql_data() && !func.is_modifies_sql_data()) { + func.set_contains_sql(); + } } break; case T_SP_CALL_STMT: { RESOLVE_STMT(PL_CALL, resolve_call, ObPLCallStmt); + OX (func.set_external_state()); } break; case T_SP_INNER_CALL_STMT: { @@ -455,6 +472,7 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun LOG_WARN("failed to resolve inner call", K(parse_tree), K(ret)); } else { func.set_is_all_sql_stmt(false); + func.set_external_state(); } } break; @@ -463,6 +481,9 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun LOG_WARN("fail to check decalre order", K(ret)); } else { RESOLVE_STMT(PL_CURSOR, resolve_declare_cursor, ObPLDeclareCursorStmt); + if (!func.is_modifies_sql_data()) { + func.set_reads_sql_data(); + } } } break; @@ -664,6 +685,9 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun signal_stmt->set_str_len(STRLEN(ob_sqlstate(save_ret))); func.set_can_cached(false); func.set_is_all_sql_stmt(false); + if (lib::is_mysql_mode() && !func.is_reads_sql_data() && !func.is_modifies_sql_data()) { + func.set_contains_sql(); + } } } @@ -976,6 +1000,10 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLPackageAST &pack case T_SP_DECL_CURSOR: { if (OB_FAIL(resolve_declare_cursor(parse_tree, package_ast))) { LOG_WARN("resovle package cursor declare failed", K(ret), K(parse_tree), K(package_ast)); + } else { + if (!package_ast.is_modifies_sql_data()) { + package_ast.set_reads_sql_data(); + } } } break; @@ -2923,6 +2951,7 @@ int ObPLResolver::resolve_assign(const ObStmtNodeTree *parse_tree, ObPLAssignStm OZ (current_block_->get_namespace().get_package_var(resolve_ctx_, package_id, var_idx, var)); CK (OB_NOT_NULL(var)); OX (expected_type = &(var->get_type())); + OX (func.set_wps()); } else if (T_OP_GET_SUBPROGRAM_VAR == into_expr->get_expr_type()) { CK (into_expr->get_param_count() >= 3); OX (subprogram_id = static_cast(into_expr->get_param_expr(1))->get_value().get_uint64()); @@ -3043,9 +3072,11 @@ int ObPLResolver::resolve_if(const ObStmtNodeTree *parse_tree, ObPLIfStmt *stmt, return ret; } -int ObPLResolver::resolve_case(const ObStmtNodeTree *parse_tree, ObPLIfStmt *stmt, ObPLFunctionAST &func) +int ObPLResolver::resolve_case(const ObStmtNodeTree *parse_tree, ObPLCaseStmt *stmt, ObPLFunctionAST &func) { int ret = OB_SUCCESS; + + ObConstRawExpr *case_var = nullptr; if (OB_ISNULL(parse_tree) || OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("parse_tree is NULL", K(parse_tree), K(stmt), K(ret)); @@ -3054,64 +3085,39 @@ int ObPLResolver::resolve_case(const ObStmtNodeTree *parse_tree, ObPLIfStmt *stm ObRawExpr *case_expr = NULL; const ObStmtNodeTree *expr_node = parse_tree->children_[0]; set_item_type(T_SP_CASE); - if (NULL == expr_node) { - //没有case表达式 - } else if (OB_FAIL(resolve_expr(expr_node, func, case_expr, - combine_line_and_col(expr_node->stmt_loc_), false))) { - LOG_WARN("failed to resolve expr", K(expr_node), K(ret)); - } else { /*do nothing*/ } - - //解析when子句 - ObPLIfStmt *current_if = stmt; ObPLStmtBlock *current_block = current_block_; - if (OB_SUCC(ret)) { - const ObStmtNodeTree *when_list = parse_tree->children_[1]; - if (NULL == when_list) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("then node is NULL", K(when_list), K(parse_tree->children_), K(ret)); - } else if (T_WHEN_LIST != when_list->type_) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("Failed to resolve when", K(ret)); - } else if (0 >= when_list->num_child_) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected when list number", K(ret)); - } else { - if (OB_FAIL(resolve_when(when_list->children_[0], case_expr, stmt, func))) { - LOG_WARN("Failed to resolve when", K(ret)); - } else { - int64_t idx = 1; - while (OB_SUCC(ret) && idx < when_list->num_child_) { - const ObStmtNodeTree *when_node = when_list->children_[idx]; - CK (OB_NOT_NULL(when_node)); - if (OB_SUCC(ret)) { - ObPLStmtBlock *parent = NULL; - parent = current_block_; - if (OB_FAIL(make_block(func, parent, current_block_))) { - LOG_WARN("failed to make block", K(ret)); - } else { - ObPLStmt *stmt = NULL; - current_if->set_else(current_block_); - if (OB_FAIL(stmt_factory_.allocate(PL_IF, current_block_, stmt))) { - LOG_WARN("failed to alloc stmt", K(ret)); - } else if (OB_ISNULL(current_if = static_cast(stmt))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to static cast", K(ret)); - } else if (OB_FAIL(resolve_when(when_node, case_expr, current_if, func))) { - LOG_WARN("Failed to resolve when", K(ret)); - } else if (OB_FAIL(current_block_->add_stmt(current_if))) { - LOG_WARN("failed to add stmt", K(stmt), K(ret)); - } else { - current_if->set_location(when_node->stmt_loc_.first_line_, - when_node->stmt_loc_.first_column_); - } - } - } - idx++; - } - } + if (OB_FAIL(make_block(func, current_block, current_block_))) { + LOG_WARN("failed to make block", K(ret)); + } else if (NULL == expr_node) { + //没有case表达式 + } else if (OB_FAIL(resolve_expr(expr_node, + func, + case_expr, + combine_line_and_col(expr_node->stmt_loc_)))) { + LOG_WARN("failed to resolve expr", K(expr_node), K(ret)); + } else if (OB_FAIL(current_block_->get_namespace().add_symbol( + ObString(""), // anonymous variable for holding case expr value + case_expr->get_data_type()))) { + LOG_WARN("failed to add CASE expr var to symbol table"); + } else { + stmt->set_case_expr(func.get_expr_count() - 1); + stmt->set_case_var(func.get_symbol_table().get_count() - 1); + OZ(expr_factory_.create_raw_expr(T_QUESTIONMARK, case_var)); + CK(OB_NOT_NULL(case_var)); + if (OB_SUCC(ret)) { + ObObjParam val; + val.set_unknown(stmt->get_case_var()); + val.set_param_meta(); + case_var->set_value(val); + case_var->set_result_type(case_expr->get_result_type()); + OZ (case_var->extract_info()); } } + //解析when子句 + const ObStmtNodeTree *when_list = parse_tree->children_[1]; + OZ (resolve_when(when_list, case_var, stmt, func)); + //解析else子句 if (OB_SUCC(ret)) { const ObStmtNodeTree *else_node = parse_tree->children_[2]; @@ -3161,7 +3167,7 @@ int ObPLResolver::resolve_case(const ObStmtNodeTree *parse_tree, ObPLIfStmt *stm } if (OB_SUCC(ret)) { - current_if->set_else(else_block); + stmt->set_else_clause(else_block); } } @@ -3173,56 +3179,53 @@ int ObPLResolver::resolve_case(const ObStmtNodeTree *parse_tree, ObPLIfStmt *stm return ret; } -int ObPLResolver::resolve_when(const ObStmtNodeTree *parse_tree, const ObRawExpr *case_expr, ObPLIfStmt *stmt, ObPLFunctionAST &func) +int ObPLResolver::resolve_when(const ObStmtNodeTree *parse_tree, ObRawExpr *case_expr_var, ObPLCaseStmt *stmt, ObPLFunctionAST &func) { int ret = OB_SUCCESS; if (OB_ISNULL(parse_tree) || OB_ISNULL(stmt)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("parse_tree is NULL", K(parse_tree), K(stmt), K(ret)); - } else if (T_SP_WHEN != parse_tree->type_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("parse_tree of when list is NULL", K(parse_tree), K(stmt), K(ret)); + } else if (T_WHEN_LIST != parse_tree->type_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid when node type", K(parse_tree->type_), K(ret)); + } else if (0 >= parse_tree->num_child_) { // one when clause at least + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected when list number", K(ret)); } else { - //解析expr then结构 - ObRawExpr *expr = NULL; - ObPLStmtBlock *then_block = NULL; - ObPLDataType data_type(ObTinyIntType); - bool is_bool_stmt = false; - if (OB_ISNULL(case_expr) && lib::is_mysql_mode()) { - is_bool_stmt = true; - } - set_item_type(T_SP_WHEN); - if (OB_FAIL(resolve_then(parse_tree, - func, - OB_ISNULL(case_expr) ? &data_type : NULL, - expr, - then_block, - is_bool_stmt))) { - LOG_WARN("failed to resolve then", K(ret)); - } else { - stmt->set_then(then_block); - } - - if (OB_SUCC(ret)) { - if (NULL == case_expr) { - if (OB_FAIL(func.add_expr(expr))) { - LOG_WARN("failed to add expr", K(*expr), K(ret)); - } else { - stmt->set_cond(func.get_expr_count() - 1); - } - } else { - ObRawExpr *cond_expr = NULL; - if (OB_FAIL(ObRawExprUtils::create_equal_expr(expr_factory_, &resolve_ctx_.session_info_, case_expr, expr, cond_expr))) { - LOG_WARN("failed to create_equal_expr", K(ret)); - } else { - if (OB_FAIL(func.add_expr(cond_expr))) { - LOG_WARN("failed to add expr", K(*cond_expr), K(ret)); - } else { - OZ (cond_expr->formalize(&resolve_ctx_.session_info_)); - OX (stmt->set_cond(func.get_expr_count() - 1)); - } - } + for (int64_t i = 0; OB_SUCC(ret) && i < parse_tree->num_child_; ++i) { + ObRawExpr *expr = nullptr; + ObPLStmtBlock *body = nullptr; + ObPLDataType data_type(ObTinyIntType); + bool is_bool_stmt = false; + if (!case_expr_var && lib::is_mysql_mode()) { + is_bool_stmt = true; } + set_item_type(T_SP_WHEN); + if (OB_FAIL(make_block(func, current_block_, body))) { + LOG_WARN("failed to make block"); + } else if (OB_FAIL(resolve_then(parse_tree->children_[i], + func, + case_expr_var ? nullptr : &data_type, + expr, + body, + is_bool_stmt))) { + LOG_WARN("failed to resolve then", K(ret)); + } + + if (OB_SUCC(ret) && case_expr_var) { + ObRawExpr *cmp_expr = nullptr; + + OZ (ObRawExprUtils::create_equal_expr(expr_factory_, + &resolve_ctx_.session_info_, + case_expr_var, + expr, + cmp_expr)); + OX (expr = cmp_expr); + } + + OZ (func.add_expr(expr)); + OZ (expr->formalize(&resolve_ctx_.session_info_)); + OZ (stmt->add_when_clause(func.get_expr_count() - 1, body)); } } return ret; @@ -3556,20 +3559,9 @@ int ObPLResolver::resolve_cursor_for_loop( ret = OB_ERR_UNEXPECTED; LOG_WARN("user type is null", K(ret)); } else { - // cursor nested complex type, report not support - for (int64_t i = 0; OB_SUCC(ret) && i < user_type->get_member_count(); ++i) { - if (!user_type->get_member(i)->is_obj_type()) { - ret = OB_NOT_SUPPORTED; - LOG_WARN("cursor nested complex type", K(ret)); - LOG_USER_ERROR(OB_NOT_SUPPORTED, "cursor nested complex type"); - } - } if (OB_SUCC(ret)) { stmt->set_user_type(user_type); stmt->set_index_index(func.get_symbol_table().get_count() - 1); - if (OB_FAIL(body_block->get_namespace().expand_data_type(user_type, stmt->get_expand_user_types()))) { - LOG_WARN("fail to expand data type", K(ret)); - } } } } @@ -4599,6 +4591,17 @@ int ObPLResolver::resolve_static_sql(const ObStmtNodeTree *parse_tree, ObPLSql & K(ret), K(prepare_result.type_), K(func.get_compile_flag())); } } + if (OB_SUCC(ret)) { + if (stmt::T_SELECT == prepare_result.type_) { + if (!func.is_modifies_sql_data()) { + func.set_reads_sql_data(); + } + } else if (ObStmt::is_dml_write_stmt(prepare_result.type_)) { + func.set_modifies_sql_data(); + } else if (!func.is_reads_sql_data() && !func.is_modifies_sql_data()) { + func.set_contains_sql(); + } + } if (OB_SUCC(ret)) { ObArray idxs; @@ -4640,6 +4643,9 @@ int ObPLResolver::resolve_static_sql(const ObStmtNodeTree *parse_tree, ObPLSql & } } if (OB_SUCC(ret)) { + if (prepare_result.is_bulk_) { + static_into.set_bulk(); + } if (OB_FAIL(static_into.set_into(idxs, current_block_->get_namespace(), prepare_result.into_exprs_))) { LOG_WARN("failed to set into exprs", K(prepare_result.into_exprs_), K(idxs), K(ret)); } @@ -4662,9 +4668,9 @@ int ObPLResolver::resolve_static_sql(const ObStmtNodeTree *parse_tree, ObPLSql & ObPLDataType type; OZ (access_expr->get_final_type(type)); OZ (static_into.check_into( - func, current_block_->get_namespace(), type.is_collection_type())); + func, current_block_->get_namespace(), prepare_result.is_bulk_)); } else { - OZ (static_into.check_into(func, current_block_->get_namespace(), false)); + OZ (static_into.check_into(func, current_block_->get_namespace(), prepare_result.is_bulk_)); } } @@ -4816,6 +4822,33 @@ int ObPLResolver::resolve_execute_immediate( const ObStmtNodeTree *using_node = parse_tree->children_[2]; if (NULL != using_node) { OZ (resolve_using(using_node, stmt->get_using(), func)); + if (OB_FAIL(ret)) { + } else if (stmt->has_out() && (parse_tree->children_[3] || parse_tree->children_[1])) { + ret = OB_ERR_INOUT_PARAM_PLACEMENT_NOT_PROPERLY; + LOG_WARN("PLS-00254: OUT and IN/OUT modes cannot be used in this context Cause: \ + actual parameter mode (OUT, or IN/OUT) is not used properly in USING clause.\ + For USING clause in an OPEN statement, only IN mode is allowed.", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_using().count(); ++i) { + const ObRawExpr *expr = func.get_expr(stmt->get_using_index(i)); + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr is NULL", K(ret)); + } else if (expr->is_obj_access_expr()) { + pl::ObPLDataType final_type; + const ObObjAccessRawExpr *access_expr = static_cast(expr); + OZ(access_expr->get_final_type(final_type)); + if (OB_SUCC(ret) && final_type.is_type_record() && stmt->is_out(i)) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(ret)); + } + } + + if (OB_SUCC(ret) && stmt->is_out(i)) { + OZ (stmt->generate_into_variable_info(current_block_->get_namespace(), *expr)); + } + } + } } } } @@ -6325,6 +6358,13 @@ int ObPLResolver::resolve_cursor_def(const ObString &cursor_name, } } } + if (OB_SUCC(ret)) { + if (prepare_result.for_update_) { + func.set_modifies_sql_data(); + } else if (!func.is_modifies_sql_data()) { + func.set_reads_sql_data(); + } + } if (OB_SUCC(ret)) { if (OB_FAIL(func.add_dependency_objects(prepare_result.ref_objects_))) { LOG_WARN("failed to set ref object", K(prepare_result.ref_objects_), K(ret)); @@ -6726,10 +6766,14 @@ int ObPLResolver::resolve_open( ObPLCursor *cursor = NULL; cursor = current_block_->get_namespace().get_cursor_table()->get_cursor(index); if (OB_SUCC(ret) && OB_NOT_NULL(cursor)) { + if (cursor->is_for_update()) { + func.set_modifies_sql_data(); + } if (PL_REF_CURSOR_TYPE == cursor->get_cursor_type().get_type()) { if (cursor->get_package_id() != current_block_->get_namespace().get_package_id() || cursor->get_routine_id() != current_block_->get_namespace().get_routine_id()) { func.set_open_external_ref_cursor(); + func.set_external_state(); } } else { if (!var->get_pl_data_type().is_ref_cursor_type() @@ -6926,6 +6970,7 @@ int ObPLResolver::resolve_open_for( LOG_USER_ERROR(OB_NOT_SUPPORTED, "non-string type dynamic sql"); } else { stmt->set_dynamic_sql(func.get_expr_count() - 1); + func.set_modifies_sql_data(); } } } @@ -6964,6 +7009,13 @@ int ObPLResolver::resolve_fetch( CK (OB_NOT_NULL( cursor = current_block_->get_namespace().get_cursor_table()->get_cursor(index))); OX (stmt->set_index(cursor->get_package_id(), cursor->get_routine_id(), cursor->get_index())); + if (OB_SUCC(ret)) { + if (cursor->is_for_update()) { + func.set_modifies_sql_data(); + } else if (!func.is_modifies_sql_data()) { + func.set_reads_sql_data(); + } + } //解析into if (OB_SUCC(ret)) { @@ -6990,130 +7042,94 @@ int ObPLResolver::resolve_fetch( bool is_compatible = true; const ObRecordType *return_type = static_cast(cursor_type); stmt->set_user_type(cursor_type); - if (OB_FAIL(current_block_->get_namespace().expand_data_type(cursor_type, stmt->get_expand_user_types()))) { - LOG_WARN("fail to expand data type", K(ret)); - } else if (return_type->get_record_member_count() != stmt->get_data_type().count() + if (return_type->get_record_member_count() != stmt->get_data_type().count() && return_type->get_record_member_count() != stmt->get_into().count()) { ret = OB_ERR_WRONG_FETCH_INTO_NUM; LOG_WARN("wrong number of values in the INTO list of a FETCH statement", K(ret)); } else { - // cursor nested complex type, report not support - for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_into().count(); ++i) { - const ObRawExpr *raw_expr = NULL; - CK (OB_NOT_NULL(raw_expr = func.get_expr(stmt->get_into(i)))); - if (OB_FAIL(ret)) { - } else if (raw_expr->get_result_type().is_ext()) { - int64_t udt_id = raw_expr->get_result_type().get_accuracy().accuracy_; - if (T_OBJ_ACCESS_REF == raw_expr->get_expr_type() && OB_INVALID_ID == udt_id) { - //objaccess expr udt id is invalid if final type is basic data type. - const ObObjAccessRawExpr *obj_access_expr = static_cast(raw_expr); - ObExprResType result_type; - pl::ObPLDataType final_type; - if (OB_FAIL(obj_access_expr->get_final_type(final_type))) { - LOG_WARN("failed to get final type", K(ret)); - } else if (!final_type.is_obj_type()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("fetch into var type is unexpected", K(ret)); - } - } else { - const ObUserDefinedType *into_var_type = NULL; - OZ (current_block_->get_namespace().get_user_type(udt_id, into_var_type)); - CK (OB_NOT_NULL(into_var_type)); - if (OB_FAIL(ret)) { - } else if (into_var_type->is_record_type()) { - for (int64_t j = 0; OB_SUCC(ret) && j < into_var_type->get_member_count(); ++j) { - if (!into_var_type->get_member(j)->is_obj_type()) { - ret = OB_NOT_SUPPORTED; - LOG_WARN("cursor nested complex type", K(ret)); - LOG_USER_ERROR(OB_NOT_SUPPORTED, "cursor nested complex type"); - } - } - } else if (into_var_type->is_collection_type()) { - const ObCollectionType *coll_type = static_cast(into_var_type); - CK (OB_NOT_NULL(coll_type)); - if (coll_type->get_element_type().is_obj_type()) { - // do nothing - } else if (coll_type->get_element_type().is_record_type()) { - const ObUserDefinedType *element_type = NULL; - OZ (current_block_->get_namespace().get_user_type(coll_type->get_element_type().get_user_type_id(), element_type)); - CK (OB_NOT_NULL(element_type)); - for (int64_t j = 0; OB_SUCC(ret) && j < element_type->get_member_count(); ++j) { - if (!element_type->get_member(j)->is_obj_type()) { - ret = OB_NOT_SUPPORTED; - LOG_WARN("cursor nested complex type", K(ret)); - LOG_USER_ERROR(OB_NOT_SUPPORTED, "cursor nested complex type"); - } - } - } else { - ret = OB_NOT_SUPPORTED; - LOG_WARN("cursor nested complex type", K(ret)); - LOG_USER_ERROR(OB_NOT_SUPPORTED, "cursor nested complex type"); - } - } - } + //如果into后面只有一个变量且为record类型, + bool has_type_record_type = false; + const ObPLDataType *into_var_type = NULL; + for (int64_t i = 0; OB_SUCC(ret) && !has_type_record_type && i < stmt->get_into_data_type().count(); ++i) { + into_var_type = &stmt->get_into_data_type(i); + //type定义的record + if (into_var_type->is_type_record()) { + has_type_record_type = true; } } - bool has_record_type = false; - for (int64_t i = 0; - OB_SUCC(ret) && is_compatible && i < return_type->get_record_member_count(); - ++i) { - const ObPLDataType *left = return_type->get_record_member_type(i); - ObDataType right; - CK (OB_NOT_NULL(left)); - if (OB_SUCC(ret)) { - if (!left->is_obj_type()) { - has_record_type = true; - } - if (!has_record_type) { - right = stmt->get_data_type(i); + if (OB_SUCC(ret) && has_type_record_type && stmt->get_into_data_type().count() != 1) { + //后续新增494的错误码 + ret = OB_ERR_MULTI_RECORD; + LOG_WARN("coercion into multiple record targets not supported", K(ret)); + } + /* 走到这里如果没报错,有两种可能: + 1.into变量只有唯一一个type record. + 2.into变量无type record */ + + if (OB_SUCC(ret)) { + const ObUserDefinedType *into_user_type = NULL; + const ObRecordType *into_record_type = NULL; + int64_t into_data_type_count = 0; + if (has_type_record_type) { + CK (1 == stmt->get_into_data_type().count()); + OZ (current_block_->get_namespace().get_user_type(stmt->get_into_data_type(0).get_user_type_id(), into_user_type)); + CK (OB_NOT_NULL(into_user_type)); + CK (into_user_type->is_record_type()); + OX (into_record_type = static_cast(into_user_type)); + OX (into_data_type_count = into_record_type->get_record_member_count()); + } else { + into_data_type_count = stmt->get_into_data_type().count(); + } + // 依次比较cursor member和所有into变量 + const ObPLDataType *left = NULL; + const ObPLDataType *right = NULL; + CK (return_type->get_record_member_count() == into_data_type_count); + for (int64_t i = 0; OB_SUCC(ret) && is_compatible && i < into_data_type_count; ++i) { + left = return_type->get_record_member_type(i); + if (has_type_record_type) { + right = into_record_type->get_record_member_type(i); } else { - const ObRawExpr *raw_expr = NULL; - if (return_type->get_record_member_count() != stmt->get_into().count()) { - ret = OB_ERR_TYPE_MISMATCH_IN_FETCH; - LOG_WARN("type not compatible", - K(return_type->get_record_member_count()), - K(stmt->get_into().count()), - K(ret)); + right = &stmt->get_into_data_type(i); + } + CK (OB_NOT_NULL(left)); + if (OB_FAIL(ret)) { + } else if (left->is_obj_type() && + right->is_obj_type() && + NULL != right->get_data_type() && + !right->get_data_type()->get_meta_type().is_ext()) { + if (right->get_data_type()->get_meta_type().is_null() && + stmt->get_into().count() > i && + is_question_mark_value(func.get_expr(stmt->get_into(i)))) { + OZ (set_question_mark_type(func.get_expr(stmt->get_into(i)), left)); } else { - CK (OB_NOT_NULL(raw_expr = func.get_expr(stmt->get_into(i)))); - OV (raw_expr->get_result_type().is_ext(), OB_ERR_UNEXPECTED, KPC(raw_expr)); - OX (right.set_meta_type(raw_expr->get_result_type())); - OX (right.set_accuracy(raw_expr->get_result_type().get_accuracy())); + CK (OB_NOT_NULL(left->get_data_type())); + OX (is_compatible = cast_supported(left->get_data_type()->get_obj_type(), + left->get_data_type()->get_collation_type(), + right->get_data_type()->get_obj_type(), + right->get_data_type()->get_collation_type())); } + } else if ((!left->is_obj_type() || + (left->get_data_type() != NULL && left->get_data_type()->get_meta_type().is_ext())) + && + (!right->is_obj_type() || + (right->get_data_type() != NULL && right->get_data_type()->get_meta_type().is_ext()))) { + uint64_t left_udt_id = (NULL == left->get_data_type()) ? left->get_user_type_id() + : left->get_data_type()->get_udt_id(); + uint64_t right_udt_id = (NULL == right->get_data_type()) ? right->get_user_type_id() + : right->get_data_type()->get_udt_id(); + if (left_udt_id != right_udt_id) { + is_compatible = false; + } else { + // same composite type, compatible is true, do nothing. + } + } else { + is_compatible = false; } } - if (OB_FAIL(ret)) { - } else if (left->is_obj_type() && !right.get_meta_type().is_ext()) { - if (right.get_meta_type().is_null() - && stmt->get_into().count() > i - && is_question_mark_value(func.get_expr(stmt->get_into(i)))) { - OZ (set_question_mark_type(func.get_expr(stmt->get_into(i)), left)); - } else { - CK (OB_NOT_NULL(left->get_data_type())); - OX (is_compatible = cast_supported(left->get_data_type()->get_obj_type(), - left->get_data_type()->get_collation_type(), - right.get_obj_type(), - right.get_collation_type())); - } - } else if ((!left->is_obj_type() - || (left->get_data_type() != NULL - && left->get_data_type()->get_meta_type().is_ext())) - && right.get_meta_type().is_ext()) { - uint64_t left_udt_id = - (NULL == left->get_data_type()) - ? left->get_user_type_id() : left->get_data_type()->get_udt_id(); - if (left_udt_id != right.get_udt_id()) { - // left and right both composite. - OZ (check_composite_compatible(current_block_->get_namespace(), - left->get_user_type_id(), - right.get_udt_id(), - is_compatible), KPC(left), K(right)); - } else { - // same composite type, compatible is true, do nothing. - } - } else { - is_compatible = false; + if (OB_SUCC(ret) && !is_compatible) { + ret = OB_ERR_TYPE_MISMATCH_IN_FETCH; + LOG_WARN("type not compatible", K(ret)); } } } @@ -7179,6 +7195,13 @@ int ObPLResolver::resolve_close( cursor = current_block_->get_namespace().get_cursor_table()->get_cursor(index))); OX (stmt->set_index( cursor->get_package_id(), cursor->get_routine_id(), cursor->get_index())); + if (OB_SUCC(ret)) { + if (cursor->is_for_update()) { + func.set_modifies_sql_data(); + } else if (!func.is_modifies_sql_data()) { + func.set_reads_sql_data(); + } + } } return ret; } @@ -8228,6 +8251,28 @@ int ObPLResolver::set_cm_warn_on_fail(ObRawExpr *&expr) return ret; } +int ObPLResolver::analyze_expr_type(ObRawExpr *&expr, + ObPLCompileUnitAST &unit_ast) +{ + int ret = OB_SUCCESS; + CK (OB_NOT_NULL(expr)); + if (OB_FAIL(ret)) { + } else if (T_OP_GET_PACKAGE_VAR == expr->get_expr_type()) { + OX (unit_ast.set_rps()); + } else if (T_FUN_UDF == expr->get_expr_type()) { + OX (unit_ast.set_external_state()); + } else { + for (int64_t i = 0; + OB_SUCC(ret) && + (!unit_ast.is_rps() || !unit_ast.is_external_state()) && + i < expr->get_param_count(); + ++i) { + OZ (analyze_expr_type(expr->get_param_expr(i), unit_ast)); + } + } + return ret; +} + int ObPLResolver::resolve_expr(const ParseNode *node, ObPLCompileUnitAST &unit_ast, ObRawExpr *&expr, @@ -8243,7 +8288,7 @@ int ObPLResolver::resolve_expr(const ParseNode *node, CK (OB_NOT_NULL(expr)); bool is_order = false; OZ (replace_object_compare_expr(expr, unit_ast, is_order)); - + OZ (analyze_expr_type(expr, unit_ast)); // check op illegal if (OB_SUCC(ret) && !OB_ISNULL(expr) && (T_OP_EQ == expr->get_expr_type() || T_OP_NE == expr->get_expr_type())) { @@ -8561,6 +8606,10 @@ int ObPLResolver::transform_subquery_expr(const ParseNode *node, LOG_WARN("failed to set precalc exprs", K(prepare_result.exec_params_), K(ret)); } else if (OB_FAIL(func.add_dependency_objects(prepare_result.ref_objects_))) { LOG_WARN("failed to add dependency objects", K(prepare_result.ref_objects_), K(ret)); + } else { + if (!func.is_modifies_sql_data()) { + func.set_reads_sql_data(); + } } if (OB_SUCC(ret)) { @@ -10016,6 +10065,7 @@ int ObPLResolver::resolve_udf_info( CK (OB_NOT_NULL(udf_info.ref_expr_)); CK (OB_NOT_NULL(current_block_)); + OX (func.set_external_state()); OZ (schema_checker.init(resolve_ctx_.schema_guard_)); OZ (ObRawExprUtils::rebuild_expr_params(udf_info, &expr_factory_, expr_params), K(udf_info), K(access_idxs)); { @@ -10269,6 +10319,23 @@ int ObPLResolver::resolve_udf_info( 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)) { + bool enable_parallel = true; + if (udf_raw_expr->is_parallel_enable()) { + //do nothing + } else { + if (routine_info->is_modifies_sql_data() || + routine_info->is_wps() || + routine_info->is_rps() || + routine_info->is_has_sequence() || + routine_info->is_external_state()) { + enable_parallel = false; + } else if (routine_info->is_reads_sql_data()) { + enable_parallel = true; + } + OX (udf_raw_expr->set_parallel_enable(enable_parallel)); + } + } if (OB_SUCC(ret) && udf_info.is_udf_udt_cons() && OB_NOT_NULL(udf_raw_expr->get_param_expr(0))) { @@ -11109,6 +11176,18 @@ int ObPLResolver::resolve_var(ObQualifiedName &q_name, ObPLBlockNS &ns, &resolve_ctx_.schema_guard_, ns, expr, for_write))) { LOG_WARN("failed to make var from access", K(ret), K(q_name), K(access_idxs)); } else { /*do nothing*/ } + + if (OB_SUCC(ret)) { + if (ObObjAccessIdx::is_package_variable(access_idxs)) { + if (for_write) { + OX (func.set_wps()); + } else { + OX (func.set_rps()); + } + } else if (ObObjAccessIdx::is_get_variable(access_idxs)) { + OX (func.set_external_state()); + } + } return ret; } @@ -12238,11 +12317,17 @@ int ObPLResolver::resolve_into(const ParseNode *into_node, ObPLInto &into, ObPLF static_cast(into_list->children_[i]->str_len_), into_list->children_[i]->str_value_); } + if (OB_SUCC(ret) && 1 == into_node->value_) { + into.set_bulk(); + } CK (OB_NOT_NULL(expr)); OZ (func.add_expr(expr)); OZ (into.add_into(func.get_expr_count() - 1, current_block_->get_namespace(), *expr)); - if (OB_SUCC(ret) && expr->is_obj_access_expr()) { + if (OB_FAIL(ret)) { + } else if (expr->is_obj_access_expr()) { OZ (func.add_obj_access_expr(expr)); + } else if (T_OP_GET_PACKAGE_VAR == expr->get_expr_type()) { + OX (func.set_wps()); } } @@ -12395,6 +12480,7 @@ int ObPLResolver::resolve_condition(const ObStmtNodeTree *parse_tree, obj_version.object_type_ = DEPENDENCY_PACKAGE; obj_version.version_ = package_info->get_schema_version(); OZ (func.add_dependency_object(obj_version)); + OX (func.set_rps()); } OX (*value = &(condition->get_value())); } @@ -12710,6 +12796,9 @@ int ObPLResolver::resolve_sequence_object(const ObQualifiedName &q_name, OX (obj_version.version_ = schema_version); OZ (unit_ast.add_dependency_object(obj_version)); } + if (OB_SUCC(ret)) { + unit_ast.set_has_sequence(); + } } } else { ret = OB_ERR_SP_UNDECLARED_VAR; @@ -12996,6 +13085,7 @@ int ObPLResolver::resolve_cursor(ObPLCompileUnitAST &func, obj_version.object_type_ = DEPENDENCY_PACKAGE; obj_version.version_ = package_info->get_schema_version(); OZ (func.add_dependency_object(obj_version)); + OX (func.set_rps()); } return ret; } @@ -13622,9 +13712,15 @@ int ObPLResolver::resolve_routine_decl_param_list(const ParseNode *param_list, break; case MODE_OUT: param_mode = PL_PARAM_OUT; + if (!unit_ast.is_package()) { + unit_ast.set_has_out_param(); + } break; case MODE_INOUT: param_mode = PL_PARAM_INOUT; + if (!unit_ast.is_package()) { + unit_ast.set_has_out_param(); + } break; default: ret = OB_ERR_UNEXPECTED; @@ -14203,6 +14299,39 @@ int ObPLResolver::resolve_routine_def(const ObStmtNodeTree *parse_tree, OZ (routine_table.set_routine_ast(idx, routine_ast)); OX (unit_ast.add_dependency_objects(routine_ast->get_dependency_table())); OX (unit_ast.set_can_cached(routine_ast->get_can_cached())); + if (OB_SUCC(ret)) { + if (unit_ast.is_modifies_sql_data()) { + // do nothing + } else if (routine_ast->is_modifies_sql_data()) { + unit_ast.set_modifies_sql_data(); + } else if (unit_ast.is_reads_sql_data()) { + // do nothing + } else if (routine_ast->is_reads_sql_data()) { + unit_ast.set_reads_sql_data(); + } else if (unit_ast.is_contains_sql()) { + // do nothing + } else if (routine_ast->is_contains_sql()) { + unit_ast.set_contains_sql(); + } else if (routine_ast->is_no_sql()) { + unit_ast.set_no_sql(); + } + if (routine_ast->is_wps()) { + unit_ast.set_wps(); + } + if (routine_ast->is_rps()) { + unit_ast.set_rps(); + } + if (routine_ast->is_has_sequence()) { + unit_ast.set_has_sequence(); + } + /*if (routine_ast->is_has_out_param()) { + unit_ast.set_has_out_param(); + }*/ + if (routine_ast->is_external_state()) { + unit_ast.set_external_state(); + } + } + OX (routine_info->set_analyze_flag(routine_ast->get_analyze_flag())); // 将routine param中的外部类型加入到当前namespace的type table中。 for (int64_t i = 0; OB_SUCC(ret) && i < routine_info->get_param_count(); ++i) { ObPLRoutineParam *param = routine_info->get_params().at(i); diff --git a/src/pl/ob_pl_resolver.h b/src/pl/ob_pl_resolver.h index 67b355051..fa7e28863 100644 --- a/src/pl/ob_pl_resolver.h +++ b/src/pl/ob_pl_resolver.h @@ -566,7 +566,7 @@ private: bool is_for_param_type = false); int resolve_assign(const ObStmtNodeTree *parse_tree, ObPLAssignStmt *stmt, ObPLFunctionAST &func); int resolve_if(const ObStmtNodeTree *parse_tree, ObPLIfStmt *stmt, ObPLFunctionAST &func); - int resolve_case(const ObStmtNodeTree *parse_tree, ObPLIfStmt *stmt, ObPLFunctionAST &func); + int resolve_case(const ObStmtNodeTree *parse_tree, ObPLCaseStmt *stmt, ObPLFunctionAST &func); int resolve_iterate(const ObStmtNodeTree *parse_tree, ObPLIterateStmt *stmt, ObPLFunctionAST &func); int resolve_leave(const ObStmtNodeTree *parse_tree, ObPLLeaveStmt *stmt, ObPLFunctionAST &func); int resolve_while(const ObStmtNodeTree *parse_tree, ObPLWhileStmt *stmt, ObPLFunctionAST &func); @@ -641,6 +641,8 @@ private: const ObPLDataType *expected_type = NULL); int get_actually_pl_type(const ObPLDataType *&type); int set_cm_warn_on_fail(ObRawExpr *&expr); + int analyze_expr_type(ObRawExpr *&expr, + ObPLCompileUnitAST &unit_ast); int resolve_expr(const ParseNode *node, ObPLCompileUnitAST &unit_ast, sql::ObRawExpr *&expr, uint64_t line_number = 0, /* where this expr called */ bool need_add = true, const ObPLDataType *expected_type = NULL, @@ -683,7 +685,7 @@ private: int resolve_package_stmt_list(const ObStmtNodeTree *node, ObPLStmtBlock *&block, ObPLPackageAST &package); int resolve_stmt_list(const ObStmtNodeTree *parse_tree, ObPLStmtBlock *&stmt, ObPLFunctionAST &func, bool stop_search_label = false, bool in_handler_scope = false); - int resolve_when(const ObStmtNodeTree *parse_tree, const ObRawExpr *case_expr, ObPLIfStmt *stmt, ObPLFunctionAST &func); + int resolve_when(const ObStmtNodeTree *parse_tree, ObRawExpr *case_expr_var, ObPLCaseStmt *stmt, ObPLFunctionAST &func); int resolve_then(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &func, ObPLDataType *data_type, diff --git a/src/pl/ob_pl_router.cpp b/src/pl/ob_pl_router.cpp index 1993494a1..a4c75d98c 100644 --- a/src/pl/ob_pl_router.cpp +++ b/src/pl/ob_pl_router.cpp @@ -105,7 +105,7 @@ int ObPLRouter::check_error_in_resolve(int code) return ret; } -int ObPLRouter::analyze(ObString &route_sql, ObIArray &dep_info) +int ObPLRouter::analyze(ObString &route_sql, ObIArray &dep_info, ObRoutineInfo &routine_info) { int ret = OB_SUCCESS; HEAP_VAR(ObPLFunctionAST, func_ast, inner_allocator_) { @@ -128,6 +128,32 @@ int ObPLRouter::analyze(ObString &route_sql, ObIArray &dep_inf routine_info_.get_object_type(), 0, dep_attr, dep_attr)); } + if (OB_SUCC(ret)) { + if (func_ast.is_modifies_sql_data()) { + routine_info.set_modifies_sql_data(); + } else if (func_ast.is_reads_sql_data()) { + routine_info.set_reads_sql_data(); + } else if (func_ast.is_contains_sql()) { + routine_info.set_contains_sql(); + } else if (func_ast.is_no_sql()) { + routine_info.set_no_sql(); + } + if (func_ast.is_wps()) { + routine_info.set_wps(); + } + if (func_ast.is_rps()) { + routine_info.set_rps(); + } + if (func_ast.is_has_sequence()) { + routine_info.set_has_sequence(); + } + if (func_ast.is_has_out_param()) { + routine_info.set_has_out_param(); + } + if (func_ast.is_external_state()) { + routine_info.set_external_state(); + } + } } return ret; } diff --git a/src/pl/ob_pl_router.h b/src/pl/ob_pl_router.h index 561903b6e..3bd3b78dc 100644 --- a/src/pl/ob_pl_router.h +++ b/src/pl/ob_pl_router.h @@ -33,7 +33,7 @@ public: expr_factory_(inner_allocator_) {} virtual ~ObPLRouter() {} - int analyze(ObString &route_sql, common::ObIArray &dep_infos); + int analyze(ObString &route_sql, common::ObIArray &dep_infos, ObRoutineInfo &routine_info); int simple_resolve(ObPLFunctionAST &func_ast); static int analyze_stmt(const ObPLStmt *stmt, ObString &route_sql); diff --git a/src/pl/ob_pl_stmt.cpp b/src/pl/ob_pl_stmt.cpp index 18e5bb15c..dc0ede8cd 100644 --- a/src/pl/ob_pl_stmt.cpp +++ b/src/pl/ob_pl_stmt.cpp @@ -3136,6 +3136,43 @@ int ObPLBlockNS::get_cursor_by_name(const ObExprResolveContext &ctx, return ret; } +int ObPLBlockNS::expand_data_type_once(const ObUserDefinedType *user_type, + ObIArray &types, + ObIArray *not_null_flags, + ObIArray *pls_ranges) const +{ + int ret = OB_SUCCESS; + CK (OB_NOT_NULL(user_type)); + for (int64_t i = 0; OB_SUCC(ret) && i < user_type->get_member_count(); ++i) { + const ObPLDataType *member = user_type->get_member(i); + CK (OB_NOT_NULL(member)); + if (OB_FAIL(ret)) { + } else if (member->is_obj_type()) { + CK (OB_NOT_NULL(member->get_data_type())); + OZ (types.push_back(*member->get_data_type()), i); + if (OB_NOT_NULL(not_null_flags)) { + OZ (not_null_flags->push_back(member->get_not_null())); + } + if (OB_NOT_NULL(pls_ranges)) { + ObPLIntegerRange range; + OZ (pls_ranges->push_back(member->is_pl_integer_type() ? member->get_range() : range.range_)); + } + } else { + ObDataType ext_type; + ext_type.set_obj_type(ObExtendType); + OZ (types.push_back(ext_type), i); + if (OB_NOT_NULL(not_null_flags)) { + OZ (not_null_flags->push_back(false)); + } + if (OB_NOT_NULL(pls_ranges)) { + ObPLIntegerRange range; + OZ (pls_ranges->push_back(range.range_)); + } + } + } + return ret; +} + int ObPLBlockNS::expand_data_type(const ObUserDefinedType *user_type, ObIArray &types, ObIArray *not_null_flags, @@ -3389,82 +3426,122 @@ int64_t ObPLBlockNS::to_string(char* buf, const int64_t buf_len) const return pos; } +int ObPLInto::generate_into_variable_info(ObPLBlockNS &ns, const ObRawExpr &expr) +{ + int ret = OB_SUCCESS; + + pl::ObPLDataType final_type; + pl::ObPLDataType pl_data_type; + // T_OBJ_ACCESS_REF expr, access obj type (not user defined type) + bool access_obj_type = false; + if (expr.is_obj_access_expr()) { + // case: + // type num_table is table of number; + // ... + // num_table nums; + // ... + // fetch c_cursor into nums(1); + // + // We got `num(1)` by T_OBJ_ACCESS_REF expression for write. T_OBJ_ACCESS_REF return + // the address of ObObj by extend value in execution, so %expr's result type is set to + // ObExtendType. We get the obj type from final type of T_OBJ_ACCESS_REF here. + const auto &access_expr = static_cast(expr); + OZ(access_expr.get_final_type(final_type)); + OX(access_obj_type = !final_type.is_user_type()); + if (bulk_ && !access_obj_type && final_type.is_collection_type()) { + const pl::ObUserDefinedType *user_type = NULL; + OZ (ns.get_pl_data_type_by_id(final_type.get_user_type_id(), user_type)); + CK (OB_NOT_NULL(user_type)); + if (OB_SUCC(ret)) { + const ObCollectionType *coll_type = static_cast(user_type); + CK (OB_NOT_NULL(coll_type)); + OX (final_type = coll_type->get_element_type()); + OX(access_obj_type = !final_type.is_user_type()); + } + } + } + if (OB_FAIL(ret)) { + } else if (expr.get_result_type().is_ext() && !access_obj_type) { + const pl::ObUserDefinedType *user_type = NULL; + if (expr.is_obj_access_expr()) { + // do nothing, %final_type already fetched + } else if (T_QUESTIONMARK == expr.get_expr_type()) { + CK (OB_NOT_NULL(ns.get_symbol_table())); + int64_t var_index = static_cast(expr).get_value().get_int(); + const ObPLVar *var = ns.get_symbol_table()->get_symbol(var_index); + CK (OB_NOT_NULL(var)); + OX (final_type = var->get_pl_data_type()); + } else { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid expr type used in INTO clause", K(expr), K(ret)); + } + + if (OB_SUCC(ret)) { + if (final_type.is_cursor_type() || final_type.is_opaque_type()) { + ObDataType ext_type; + ext_type.set_obj_type(ObExtendType); + OZ (data_type_.push_back(ext_type)); + OZ (not_null_flags_.push_back(false)); + ObPLIntegerRange range; + OZ (pl_integer_ranges_.push_back(range.range_)); + OX (pl_data_type.set_data_type(ext_type)); + OX (pl_data_type.set_type(PL_OBJ_TYPE)); + OZ (into_data_type_.push_back(pl_data_type)); + } else { + if (final_type.is_type_record()) { + ObArray basic_types; + ObArray not_null_flags; + ObArray pls_ranges; + is_type_record_ = true; + OZ (ns.get_pl_data_type_by_id(final_type.get_user_type_id(), user_type)); + CK (OB_NOT_NULL(user_type)); + // 只能展一层 + OZ (ns.expand_data_type_once(user_type, basic_types, ¬_null_flags, &pls_ranges)); + OZ (append(data_type_, basic_types)); + OZ (append(not_null_flags_, not_null_flags)); + OZ (append(pl_integer_ranges_, pls_ranges)); + } else { + ObDataType ext_type; + ObDataType type; + ObPLIntegerRange range; + ext_type.set_obj_type(ObExtendType); + OZ (data_type_.push_back(ext_type)); + OZ (not_null_flags_.push_back(false)); + OZ (pl_integer_ranges_.push_back(range.range_)); + } + OZ (into_data_type_.push_back(final_type)); + } + } + } else { + ObDataType type; + ObPLIntegerRange range; + bool flag = false; + if (access_obj_type) { + type.set_meta_type(final_type.get_data_type()->get_meta_type()); + type.set_accuracy(final_type.get_data_type()->get_accuracy()); + } else { + type.set_meta_type(expr.get_result_type().get_obj_meta()); + type.set_accuracy(expr.get_result_type().get_accuracy()); + } + OZ (calc_type_constraint(expr, ns, flag, range), expr); + OZ (data_type_.push_back(type), type); + OZ (not_null_flags_.push_back(flag), type, flag); + OZ (pl_integer_ranges_.push_back(range.range_)); + OX (pl_data_type.set_data_type(type)); + OX (pl_data_type.set_type(PL_OBJ_TYPE)); + OZ (into_data_type_.push_back(pl_data_type)); + } + + return ret; +} + int ObPLInto::add_into(int64_t idx, ObPLBlockNS &ns, const ObRawExpr &expr) { int ret = OB_SUCCESS; if (OB_FAIL(into_.push_back(idx))) { LOG_WARN("Failed to add into", K(idx), K(ret)); } else { - pl::ObPLDataType final_type; - // T_OBJ_ACCESS_REF expr, access obj type (not user defined type) - bool access_obj_type = false; - if (expr.is_obj_access_expr()) { - // case: - // type num_table is table of number; - // ... - // num_table nums; - // ... - // fetch c_cursor into nums(1); - // - // We got `num(1)` by T_OBJ_ACCESS_REF expression for write. T_OBJ_ACCESS_REF return - // the address of ObObj by extend value in execution, so %expr's result type is set to - // ObExtendType. We get the obj type from final type of T_OBJ_ACCESS_REF here. - const auto &access_expr = static_cast(expr); - OZ(access_expr.get_final_type(final_type)); - OX(access_obj_type = !final_type.is_user_type()); - } - if (OB_FAIL(ret)) { - } else if (expr.get_result_type().is_ext() && !access_obj_type) { - const pl::ObUserDefinedType *user_type = NULL; - if (expr.is_obj_access_expr()) { - // do nothing, %final_type already fetched - } else if (T_QUESTIONMARK == expr.get_expr_type()) { - CK (OB_NOT_NULL(ns.get_symbol_table())); - int64_t var_index = static_cast(expr).get_value().get_int(); - const ObPLVar *var = ns.get_symbol_table()->get_symbol(var_index); - CK (OB_NOT_NULL(var)); - OX (final_type = var->get_pl_data_type()); - } else { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("Invalid expr type used in INTO clause", K(idx), K(expr), K(ret)); - } - - if (OB_SUCC(ret)) { - if (final_type.is_cursor_type() || final_type.is_opaque_type()) { - ObDataType ext_type; - ext_type.set_obj_type(ObExtendType); - OZ (data_type_.push_back(ext_type)); - OZ (not_null_flags_.push_back(false)); - ObPLIntegerRange range; - OZ (pl_integer_ranges_.push_back(range.range_)); - } else { - ObArray basic_types; - ObArray not_null_flags; - ObArray pls_ranges; - OZ (ns.get_pl_data_type_by_id(final_type.get_user_type_id(), user_type)); - CK (OB_NOT_NULL(user_type)); - OZ (ns.expand_data_type(user_type, basic_types, ¬_null_flags, &pls_ranges)); - OZ (append(data_type_, basic_types)); - OZ (append(not_null_flags_, not_null_flags)); - OZ (append(pl_integer_ranges_, pls_ranges)); - } - } - } else { - ObDataType type; - ObPLIntegerRange range; - bool flag = false; - if (access_obj_type) { - type.set_meta_type(final_type.get_data_type()->get_meta_type()); - type.set_accuracy(final_type.get_data_type()->get_accuracy()); - } else { - type.set_meta_type(expr.get_result_type().get_obj_meta()); - type.set_accuracy(expr.get_result_type().get_accuracy()); - } - OZ (calc_type_constraint(expr, ns, flag, range), expr); - OZ (data_type_.push_back(type), type); - OZ (not_null_flags_.push_back(flag), type, flag); - OZ (pl_integer_ranges_.push_back(range.range_)); - } + OZ (generate_into_variable_info(ns, expr)); } return ret; } @@ -3596,9 +3673,7 @@ int ObPLInto::check_into(ObPLFunctionAST &func, ObPLBlockNS &ns, bool is_bulk) } } } - if (OB_SUCC(ret) && is_bulk) { - set_bulk(); - } + return ret; } @@ -4358,6 +4433,13 @@ int ObPLStmtFactory::allocate(ObPLStmtType type, const ObPLStmtBlock *block, ObP } } break; + case PL_CASE: { + stmt = static_cast(allocator_.alloc(sizeof(ObPLCaseStmt))); + if (NULL != stmt) { + stmt = new(stmt)ObPLCaseStmt(allocator_); + } + } + break; default:{ ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected stmt type", K(ret), K(type)); @@ -4521,6 +4603,10 @@ int ObPLDoStmt::accept(ObPLStmtVisitor &visitor) const { return visitor.visit(*this); } +int ObPLCaseStmt::accept(ObPLStmtVisitor &visitor) const +{ + return visitor.visit(*this); +} } } diff --git a/src/pl/ob_pl_stmt.h b/src/pl/ob_pl_stmt.h index 71c94049a..15740614b 100644 --- a/src/pl/ob_pl_stmt.h +++ b/src/pl/ob_pl_stmt.h @@ -834,10 +834,7 @@ public: accessors_(allocator), priv_user_(), loc_(0), - is_no_sql_(false), - is_reads_sql_data_(false), - is_modifies_sql_data_(false), - is_contains_sql_(true){} + analyze_flag_(0) {} virtual ~ObPLRoutineInfo(); int make_routine_param(common::ObIAllocator &allocator, @@ -942,6 +939,20 @@ public: virtual bool is_invoker_right() const { return compile_flag_.compile_with_invoker_right(); } + inline void set_analyze_flag(uint64_t flag) { analyze_flag_ = flag; } + inline uint64_t get_analyze_flag() const { return analyze_flag_; } + + virtual void set_wps() { is_wps_ = true; } + virtual bool is_wps() const { return is_wps_; } + virtual void set_rps() { is_rps_ = true; } + virtual bool is_rps() const { return is_rps_; } + virtual void set_has_sequence() { is_has_sequence_ = true; } + virtual bool is_has_sequence() const { return is_has_sequence_; } + virtual void set_has_out_param() { is_has_out_param_ = true; } + virtual bool is_has_out_param() const { return is_has_out_param_; } + virtual void set_external_state() { is_external_state_ = true; } + virtual bool is_external_state() const { return is_external_state_; } + virtual void set_result_cache() { is_result_cache_ = true; } virtual bool is_result_cache() const { return is_result_cache_; } @@ -983,7 +994,8 @@ public: K_(is_parallel_enable), K_(is_udt_routine), K_(accessors), - K_(loc)); + K_(loc), + K_(analyze_flag)); private: common::ObIAllocator &allocator_; uint64_t tenant_id_; @@ -1011,10 +1023,21 @@ private: ObPLSEArray accessors_; common::ObString priv_user_; uint64_t loc_; - bool is_no_sql_; - bool is_reads_sql_data_; - bool is_modifies_sql_data_; - bool is_contains_sql_; + union { + uint64_t analyze_flag_; + struct { + uint64_t is_no_sql_ : 1; + uint64_t is_reads_sql_data_ : 1; + uint64_t is_modifies_sql_data_ : 1; + uint64_t is_contains_sql_ : 1; + uint64_t is_wps_ : 1; + uint64_t is_rps_ : 1; + uint64_t is_has_sequence_ : 1; + uint64_t is_has_out_param_ : 1; + uint64_t is_external_state_ : 1; + uint64_t reserved_:54; + }; + }; }; class ObPLFunctionAST; @@ -1411,6 +1434,10 @@ public: ObIArray &types, ObIArray *not_null_flags = NULL, ObIArray *pls_ranges = NULL) const; + int expand_data_type_once(const ObUserDefinedType *user_type, + ObIArray &types, + ObIArray *not_null_flags = NULL, + ObIArray *pls_ranges = NULL) const; inline bool is_procedure(ObProcType routine_type) const { return STANDALONE_PROCEDURE == routine_type @@ -1503,7 +1530,8 @@ public: dependency_table_(), compile_flag_(), can_cached_(true), - priv_user_() + priv_user_(), + analyze_flag_(0) {} virtual ~ObPLCompileUnitAST() {} @@ -1586,6 +1614,28 @@ public: virtual int64_t get_version() const = 0; virtual uint64_t get_database_id() const = 0; + virtual uint64_t get_analyze_flag() const { return analyze_flag_; } + + virtual void set_no_sql() { is_no_sql_ = true; is_reads_sql_data_ = false; is_modifies_sql_data_ = false; is_contains_sql_ = false; } + virtual bool is_no_sql() const { return is_no_sql_; } + virtual void set_reads_sql_data() { is_no_sql_ = false; is_reads_sql_data_ = true; is_modifies_sql_data_ = false; is_contains_sql_ = false; } + virtual bool is_reads_sql_data() const { return is_reads_sql_data_; } + virtual void set_modifies_sql_data() { is_no_sql_ = false; is_reads_sql_data_ = false; is_modifies_sql_data_ = true; is_contains_sql_ = false; } + virtual bool is_modifies_sql_data() const { return is_modifies_sql_data_; } + virtual void set_contains_sql() { is_no_sql_ = false; is_reads_sql_data_ = false; is_modifies_sql_data_ = false; is_contains_sql_ = true; } + virtual bool is_contains_sql() const { return is_contains_sql_; } + + virtual void set_wps() { is_wps_ = true; } + virtual bool is_wps() const { return is_wps_; } + virtual void set_rps() { is_rps_ = true; } + virtual bool is_rps() const { return is_rps_; } + virtual void set_has_sequence() { is_has_sequence_ = true; } + virtual bool is_has_sequence() const { return is_has_sequence_; } + virtual void set_has_out_param() { is_has_out_param_ = true; } + virtual bool is_has_out_param() const { return is_has_out_param_; } + virtual void set_external_state() { is_external_state_ = true; } + virtual bool is_external_state() const { return is_external_state_; } + ObPLSymbolDebugInfoTable &get_symbol_debuginfo_table() { return symbol_debuginfo_table_; @@ -1618,6 +1668,21 @@ protected: ObPLCompileFlag compile_flag_; bool can_cached_; ObString priv_user_; + union { + uint64_t analyze_flag_; + struct { + uint64_t is_no_sql_ : 1; + uint64_t is_reads_sql_data_ : 1; + uint64_t is_modifies_sql_data_ : 1; + uint64_t is_contains_sql_ : 1; + uint64_t is_wps_ : 1; + uint64_t is_rps_ : 1; + uint64_t is_has_sequence_ : 1; + uint64_t is_has_out_param_ : 1; + uint64_t is_external_state_ : 1; + uint64_t reserved_:54; + }; + }; private: DISALLOW_COPY_AND_ASSIGN(ObPLCompileUnitAST); }; @@ -1723,6 +1788,7 @@ enum ObPLStmtType PL_TRIM, PL_INTERFACE, PL_DO, + PL_CASE, MAX_PL_STMT }; @@ -1974,6 +2040,56 @@ private: ObPLStmtBlock *else_; }; +class ObPLCaseStmt : public ObPLStmt { +public: + ObPLCaseStmt(common::ObIAllocator &allocator) + : ObPLStmt(PL_CASE), + case_expr_idx_(OB_INVALID_INDEX), case_var_idx_(OB_INVALID_INDEX), + when_(allocator), else_(nullptr) {} + virtual ~ObPLCaseStmt() {} + + virtual int64_t get_child_size() const override { return when_.count() + 1; } + virtual const ObPLStmt *get_child_stmt(int64_t i) const override { + ObPLStmt *ret = nullptr; + int64_t when_count = when_.count(); + if (OB_LIKELY(0 <= i && i <= when_count)) { + if (OB_LIKELY(i < when_count)) { + ret = when_[i].body_; + } else { + ret = else_; + } + } + return ret; + } + + virtual int accept(ObPLStmtVisitor &visitor) const override; + + struct WhenClause { + int64_t expr_; + ObPLStmtBlock *body_; + + TO_STRING_KV(K_(expr), K_(body)); + }; + using WhenClauses = ObPLSEArray; + + void set_case_expr(int64_t case_expr_idx) { case_expr_idx_ = case_expr_idx; } + int64_t get_case_expr() const { return case_expr_idx_; } + void set_case_var(int64_t case_var_idx) { case_var_idx_ = case_var_idx; } + int64_t get_case_var() const { return case_var_idx_; } + int add_when_clause(int64_t expr, ObPLStmtBlock *body) { + return when_.push_back(WhenClause{expr, body}); + } + const WhenClauses &get_when_clauses() const { return when_; } + void set_else_clause(ObPLStmtBlock *stmts) { else_ = stmts; } + const ObPLStmtBlock *get_else_clause() const { return else_; } + +private: + int64_t case_expr_idx_; + int64_t case_var_idx_; + WhenClauses when_; + ObPLStmtBlock *else_; +}; + typedef common::ObSEArray ObObjAccessIndexs; typedef common::ObSEArray ObObjAccessArray; @@ -1985,7 +2101,9 @@ public: not_null_flags_(allocator), pl_integer_ranges_(allocator), data_type_(allocator), - bulk_(false) {} + into_data_type_(allocator), + bulk_(false), + is_type_record_(false) {} virtual ~ObPLInto() {} inline const common::ObIArray &get_into() const { return into_; } @@ -1995,11 +2113,16 @@ public: int set_into(const common::ObIArray &idxs, ObPLBlockNS &ns, const common::ObIArray &exprs); inline int add_into(int64_t idx) { return into_.push_back(idx); } int add_into(int64_t idx, ObPLBlockNS &ns, const sql::ObRawExpr &expr); + int generate_into_variable_info(ObPLBlockNS &ns, const ObRawExpr &expr); inline const common::ObIArray &get_data_type() const { return data_type_; } inline common::ObIArray &get_data_type() { return data_type_; } inline const ObDataType &get_data_type(int64_t i) const { return data_type_.at(i); } inline int set_data_type(const common::ObIArray &types) { return append(data_type_, types); } inline int add_data_type(ObDataType &type) { return data_type_.push_back(type); } + inline const common::ObIArray &get_into_data_type() const { return into_data_type_; } + inline common::ObIArray &get_into_data_type() { return into_data_type_; } + inline const ObPLDataType &get_into_data_type(int64_t i) const { return into_data_type_.at(i); } + inline bool is_type_record() const { return is_type_record_; } inline bool is_bulk() const { return bulk_; } inline void set_bulk() { bulk_ = true; } int check_into(ObPLFunctionAST &func, ObPLBlockNS &ns, bool is_bulk); @@ -2022,7 +2145,9 @@ protected: ObPLSEArray not_null_flags_; ObPLSEArray pl_integer_ranges_; ObPLSEArray data_type_; + ObPLSEArray into_data_type_; bool bulk_; + bool is_type_record_; // 表示into后面是否只有一个type定义的record类型(非object定义) }; class ObPLLoopControl : public ObPLStmt @@ -2218,8 +2343,7 @@ public: cursor_idx_(OB_INVALID_INDEX), params_(allocator), need_declare_(false), - user_type_(NULL), - expand_user_types_() {} + user_type_(NULL) {} virtual ~ObPLCursorForLoopStmt() {} @@ -2288,8 +2412,6 @@ public: user_type_ = user_type; } - ObIArray &get_expand_user_types() { return expand_user_types_; } - const ObIArray &get_expand_user_types() const { return expand_user_types_; } inline void set_need_declare(bool need) { need_declare_ = need; } inline bool get_need_declare() const { return need_declare_; } @@ -2303,7 +2425,6 @@ private: ObPLSEArray params_; //cursor的实参 bool need_declare_; // 是否是SQL语句, 需要在codegen时声明 const ObUserDefinedType *user_type_; // CURSOR返回值类型 - ObSEArray expand_user_types_; //expand return type }; class ObPLSqlStmt; @@ -2939,8 +3060,7 @@ public: routine_id_(OB_INVALID_ID), idx_(common::OB_INVALID_INDEX), limit_(INT64_MAX), - user_type_(NULL), - expand_user_types_() {} + user_type_(NULL) {} virtual ~ObPLFetchStmt() {} int accept(ObPLStmtVisitor &visitor) const; @@ -2963,8 +3083,6 @@ public: { user_type_ = user_type; } - ObIArray &get_expand_user_types() { return expand_user_types_; } - const ObIArray &get_expand_user_types() const { return expand_user_types_; } inline int64_t get_limit() const { return limit_; } inline void set_limit(int64_t limit) { limit_ = limit; } @@ -2976,7 +3094,6 @@ private: int64_t idx_; //symbol表里的下标 int64_t limit_; //INT64_MAX:是bulk fetch但是没有limit子句 const ObUserDefinedType *user_type_; // CURSOR返回值类型 - ObSEArray expand_user_types_; //expand return type }; class ObPLCloseStmt : public ObPLStmt @@ -3210,6 +3327,7 @@ public: virtual int visit(const ObPLTrimStmt &s) = 0; virtual int visit(const ObPLInterfaceStmt &s) = 0; virtual int visit(const ObPLDoStmt &s) = 0; + virtual int visit(const ObPLCaseStmt &s) = 0; }; } diff --git a/src/pl/ob_pl_type.h b/src/pl/ob_pl_type.h index 258bbc0e8..af11508ee 100644 --- a/src/pl/ob_pl_type.h +++ b/src/pl/ob_pl_type.h @@ -404,6 +404,10 @@ public: inline bool is_object_type() const { return (is_record_type() || is_opaque_type()) && is_udt_type(); } + //存储过程内部通过type定义的record + inline bool is_type_record() const { + return is_record_type() && !is_udt_type(); + } inline bool is_lob_type() const { return PL_OBJ_TYPE == type_ && obj_type_.get_meta_type().is_lob_locator(); } @@ -739,6 +743,7 @@ enum ObPLCursorFlag { SESSION_CURSOR = 2, // this cursor is alloc in session memory TRANSFERING_RESOURCE = 4, // this cursor is returned by a udf SYNC_CURSOR = 8, // this cursor from package cursor sync, can not used by this server. + INVALID_CURSOR = 16, // this cursor is convert to a dbms cursor, invalid for dynamic cursor op. }; class ObPLCursorInfo { @@ -954,6 +959,9 @@ public: inline void set_sync_cursor() { set_flag_bit(SYNC_CURSOR); } inline bool is_sync_cursor() { return test_flag_bit(SYNC_CURSOR); } + inline void set_invalid_cursor() { set_flag_bit(INVALID_CURSOR); } + inline bool is_invalid_cursor() { return test_flag_bit(INVALID_CURSOR); } + static int prepare_entity(sql::ObSQLSessionInfo &session, lib::MemoryContext &entity); int prepare_spi_result(ObPLExecCtx *ctx, sql::ObSPIResultSet *&spi_result); diff --git a/src/pl/ob_pl_user_type.cpp b/src/pl/ob_pl_user_type.cpp index 5364ced86..0684edf97 100644 --- a/src/pl/ob_pl_user_type.cpp +++ b/src/pl/ob_pl_user_type.cpp @@ -734,6 +734,18 @@ int ObRecordType::is_compatble(const ObRecordType &other, bool &is_comp) const left->get_data_type()->get_collation_type(), right->get_data_type()->get_obj_type(), right->get_data_type()->get_collation_type())); + } else if ((!left->is_obj_type() || + (left->get_data_type() != NULL && left->get_data_type()->get_meta_type().is_ext())) + && + (!right->is_obj_type() || + (right->get_data_type() != NULL && right->get_data_type()->get_meta_type().is_ext()))) { + uint64_t left_udt_id = (NULL == left->get_data_type()) ? left->get_user_type_id() + : left->get_data_type()->get_udt_id(); + uint64_t right_udt_id = (NULL == right->get_data_type()) ? right->get_user_type_id() + : right->get_data_type()->get_udt_id(); + if (left_udt_id != right_udt_id) { + is_comp = false; + } } else { is_comp = false; } diff --git a/src/pl/pl_cache/ob_pl_cache.cpp b/src/pl/pl_cache/ob_pl_cache.cpp index 233c07d14..a531235f0 100644 --- a/src/pl/pl_cache/ob_pl_cache.cpp +++ b/src/pl/pl_cache/ob_pl_cache.cpp @@ -173,7 +173,7 @@ bool ObPLObjectKey::is_equal(const ObILibCacheKey &other) const int ObPLObjectValue::init(const ObILibCacheObject &cache_obj, ObPLCacheCtx &pc_ctx) { int ret = OB_SUCCESS; - const pl::ObPLCompileUnit &pl_object = static_cast(cache_obj); + const pl::ObPLCacheObject &pl_object = static_cast(cache_obj); if (OB_FAIL(add_match_info(pc_ctx, &pc_ctx.key_, cache_obj))) { LOG_WARN("failed to add_match_info", K(ret)); } else { @@ -497,8 +497,12 @@ int ObPLObjectValue::add_match_info(ObILibCacheCtx &ctx, int ret = OB_SUCCESS; ObPLCacheCtx& pc_ctx = static_cast(ctx); - const pl::ObPLCompileUnit &cache_object = static_cast(cache_obj); - if (OB_UNLIKELY(!cache_object.is_prcr() && !cache_object.is_sfc() && !cache_object.is_pkg() && !cache_object.is_anon())) { + const pl::ObPLCacheObject &cache_object = static_cast(cache_obj); + if (OB_UNLIKELY(!cache_object.is_prcr() && + !cache_object.is_sfc() && + !cache_object.is_pkg() && + !cache_object.is_anon() && + !cache_object.is_call_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("cache object is invalid", K(cache_object)); } else if (OB_UNLIKELY(pl_routine_obj_ != nullptr)) { @@ -888,7 +892,7 @@ int ObPLObjectSet::inner_add_cache_obj(ObILibCacheCtx &ctx, int ret = OB_SUCCESS; ObPLCacheCtx& pc_ctx = static_cast(ctx); - pl::ObPLCompileUnit *cache_object = static_cast(cache_obj); + pl::ObPLCacheObject *cache_object = static_cast(cache_obj); ObSEArray schema_array; if (OB_ISNULL(cache_object)) { @@ -897,14 +901,15 @@ int ObPLObjectSet::inner_add_cache_obj(ObILibCacheCtx &ctx, } else if (OB_UNLIKELY(!cache_object->is_prcr() && !cache_object->is_sfc() && !cache_object->is_pkg() && - !cache_object->is_anon())) { + !cache_object->is_anon() && + !cache_object->is_call_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("cache object is invalid", K(cache_object)); } else if (OB_FAIL(ObPLObjectValue::get_all_dep_schema(*pc_ctx.schema_guard_, cache_object->get_dependency_table(), schema_array))) { LOG_WARN("failed to get all dep schema", K(ret)); - } else { + } else { DLIST_FOREACH(pl_object_value, object_value_sets_) { bool is_same = true; bool is_old_version = false; diff --git a/src/pl/pl_cache/ob_pl_cache.h b/src/pl/pl_cache/ob_pl_cache.h index 111e0a4d4..8510d2f65 100644 --- a/src/pl/pl_cache/ob_pl_cache.h +++ b/src/pl/pl_cache/ob_pl_cache.h @@ -21,16 +21,12 @@ #include "sql/plan_cache/ob_cache_object_factory.h" #include "sql/plan_cache/ob_lib_cache_register.h" #include "pl/ob_pl.h" +#include "pl/pl_cache/ob_pl_cache_object.h" namespace oceanbase { -namespace pl -{ - class ObPLCompileUnit; -} - namespace pl { @@ -156,6 +152,7 @@ struct ObPLObjectKey : public ObILibCacheKey common::ObString name_; }; + class ObPLObjectValue : public common::ObDLinkBase { public: @@ -241,7 +238,7 @@ public: common::ObFixedArray stored_schema_objs_; common::Ob2DArray params_info_; - pl::ObPLCompileUnit *pl_routine_obj_; + pl::ObPLCacheObject *pl_routine_obj_; private: DISALLOW_COPY_AND_ASSIGN(ObPLObjectValue); }; diff --git a/src/pl/pl_cache/ob_pl_cache_mgr.cpp b/src/pl/pl_cache/ob_pl_cache_mgr.cpp index 1e1c7f675..a61a26672 100644 --- a/src/pl/pl_cache/ob_pl_cache_mgr.cpp +++ b/src/pl/pl_cache/ob_pl_cache_mgr.cpp @@ -54,7 +54,8 @@ int ObPLCacheMgr::get_pl_object(ObPlanCache *lib_cache, ObILibCacheCtx &ctx, ObC (!guard.get_cache_obj()->is_prcr() && !guard.get_cache_obj()->is_sfc() && !guard.get_cache_obj()->is_pkg() && - !guard.get_cache_obj()->is_anon())) { + !guard.get_cache_obj()->is_anon() && + guard.get_cache_obj()->get_ns() != ObLibCacheNameSpace::NS_CALLSTMT)) { ret = OB_ERR_UNEXPECTED; PL_CACHE_LOG(WARN, "cache obj is invalid", KPC(guard.get_cache_obj())); } @@ -89,7 +90,8 @@ int ObPLCacheMgr::get_pl_cache(ObPlanCache *lib_cache, ObCacheObjGuard& guard, O // update pl func/package stat pl::PLCacheObjStat *stat = NULL; int64_t current_time = ObTimeUtility::current_time(); - if (ObLibCacheNameSpace::NS_PKG != guard.get_cache_obj()->get_ns()) { + if (ObLibCacheNameSpace::NS_PKG != guard.get_cache_obj()->get_ns() && + ObLibCacheNameSpace::NS_CALLSTMT != guard.get_cache_obj()->get_ns()) { pl::ObPLFunction* pl_func = static_cast(guard.get_cache_obj()); stat = &pl_func->get_stat_for_update(); ATOMIC_INC(&(stat->hit_count_)); @@ -156,7 +158,8 @@ int ObPLCacheMgr::add_pl_cache(ObPlanCache *lib_cache, ObILibCacheObject *pl_obj } break; case NS_PKG: - case NS_ANON: { + case NS_ANON: + case NS_CALLSTMT: { ns = pl_object->get_ns(); } break; diff --git a/src/pl/pl_cache/ob_pl_cache_mgr.h b/src/pl/pl_cache/ob_pl_cache_mgr.h index 4260ade4d..b919624bb 100644 --- a/src/pl/pl_cache/ob_pl_cache_mgr.h +++ b/src/pl/pl_cache/ob_pl_cache_mgr.h @@ -45,7 +45,8 @@ struct ObGetPLKVEntryOp : public sql::ObKVEntryTraverseOp if (ObLibCacheNameSpace::NS_PRCR == entry.first->namespace_ || ObLibCacheNameSpace::NS_SFC == entry.first->namespace_ || ObLibCacheNameSpace::NS_ANON == entry.first->namespace_ || - ObLibCacheNameSpace::NS_PKG == entry.first->namespace_) { + ObLibCacheNameSpace::NS_PKG == entry.first->namespace_ || + ObLibCacheNameSpace::NS_CALLSTMT == entry.first->namespace_) { is_match = true; } return ret; diff --git a/src/pl/pl_cache/ob_pl_cache_object.cpp b/src/pl/pl_cache/ob_pl_cache_object.cpp new file mode 100644 index 000000000..89c1db83e --- /dev/null +++ b/src/pl/pl_cache/ob_pl_cache_object.cpp @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2022 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX PL_CACHE +#include "ob_pl_cache_object.h" +#include "lib/oblog/ob_log_module.h" + +namespace oceanbase +{ +namespace pl +{ + +void ObPLCacheObject::reset() +{ + ObILibCacheObject::reset(); + tenant_schema_version_ = OB_INVALID_VERSION; + sys_schema_version_ = OB_INVALID_VERSION; + params_info_.reset(); + sql_expression_factory_.destroy(); + expr_operator_factory_.destroy(); + expressions_.reset(); +} + +int ObPLCacheObject::set_params_info(const ParamStore ¶ms) +{ + int ret = OB_SUCCESS; + int64_t N = params.count(); + sql::ObParamInfo param_info; + if (N > 0 && OB_FAIL(params_info_.reserve(N))) { + OB_LOG(WARN, "fail to reserve params info", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { + param_info.flag_ = params.at(i).get_param_flag(); + param_info.type_ = params.at(i).get_param_meta().get_type(); + param_info.col_type_ = params.at(i).get_collation_type(); + if (sql::ObSQLUtils::is_oracle_empty_string(params.at(i))) { + param_info.is_oracle_empty_string_ = true; + } + if (params.at(i).get_param_meta().get_type() != params.at(i).get_type()) { + LOG_TRACE("differ in set_params_info", + K(params.at(i).get_param_meta().get_type()), + K(params.at(i).get_type()), + K(common::lbt())); + } + //todo:it is for arraybinding check, not pl ext check + if (params.at(i).is_ext()) { + ObDataType data_type; + if (OB_FAIL(sql::ObSQLUtils::get_ext_obj_data_type(params.at(i), data_type))) { + LOG_WARN("fail to get ext obj data type", K(ret)); + } else { + param_info.ext_real_type_ = data_type.get_obj_type(); + param_info.scale_ = data_type.get_meta_type().get_scale(); + } + LOG_DEBUG("ext params info", K(data_type), K(param_info), K(params.at(i))); + } else { + param_info.scale_ = params.at(i).get_scale(); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(params_info_.push_back(param_info))) { + LOG_WARN("failed to push back param info", K(ret)); + } + } + param_info.reset(); + } + return ret; +} + +} +} \ No newline at end of file diff --git a/src/pl/pl_cache/ob_pl_cache_object.h b/src/pl/pl_cache/ob_pl_cache_object.h new file mode 100644 index 000000000..006713f9d --- /dev/null +++ b/src/pl/pl_cache/ob_pl_cache_object.h @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2022 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_PL_CACHE_OBJECT_H_ +#define OCEANBASE_PL_CACHE_OBJECT_H_ +#include "share/ob_define.h" +#include "sql/plan_cache/ob_i_lib_cache_object.h" +#include "sql/plan_cache/ob_i_lib_cache_context.h" +#include "sql/plan_cache/ob_cache_object_factory.h" +#include "sql/plan_cache/ob_lib_cache_register.h" +#include "sql/plan_cache/ob_cache_object.h" +#include "sql/engine/expr/ob_sql_expression_factory.h" +#include "sql/resolver/expr/ob_raw_expr.h" +#include "sql/engine/expr/ob_sql_expression.h" + +namespace oceanbase +{ + + +namespace pl +{ + +class ObPLCacheObject : public sql::ObILibCacheObject +{ +public: + ObPLCacheObject(sql::ObLibCacheNameSpace ns, lib::MemoryContext &mem_context) + : ObILibCacheObject(ns, mem_context), + tenant_schema_version_(OB_INVALID_VERSION), + sys_schema_version_(OB_INVALID_VERSION), + dependency_tables_(allocator_), + params_info_( (ObWrapperAllocator(allocator_)) ), + expr_factory_(allocator_), + sql_expression_factory_(allocator_), + expr_operator_factory_(allocator_), + expressions_(allocator_), + expr_op_size_(0), + frame_info_(allocator_) + {} + + virtual ~ObPLCacheObject() {} + virtual void reset(); + inline bool is_call_stmt() const { return sql::ObLibCacheNameSpace::NS_CALLSTMT == ns_; } + + inline void set_sys_schema_version(int64_t schema_version) { sys_schema_version_ = schema_version; } + inline void set_tenant_schema_version(int64_t schema_version) { tenant_schema_version_ = schema_version; } + inline int64_t get_tenant_schema_version() const { return tenant_schema_version_; } + inline int64_t get_sys_schema_version() const { return sys_schema_version_; } + + inline int64_t get_dependency_table_size() const { return dependency_tables_.count(); } + inline const sql::DependenyTableStore &get_dependency_table() const { return dependency_tables_; } + int init_dependency_table_store(int64_t dependency_table_cnt) { return dependency_tables_.init(dependency_table_cnt); } + inline sql::DependenyTableStore &get_dependency_table() { return dependency_tables_; } + int set_params_info(const ParamStore ¶ms); + const common::Ob2DArray &get_params_info() const { return params_info_; } + + inline sql::ObRawExprFactory &get_expr_factory() { return expr_factory_; } + inline sql::ObSqlExpressionFactory &get_sql_expression_factory() { return sql_expression_factory_; } + inline sql::ObExprOperatorFactory &get_expr_operator_factory() { return expr_operator_factory_; } + inline const common::ObIArray &get_expressions() const { return expressions_; } + inline common::ObIArray &get_expressions() { return expressions_; } + inline int set_expressions(common::ObIArray &exprs) { return expressions_.assign(exprs); } + inline int64_t get_expr_op_size() const { return expr_op_size_; } + inline void set_expr_op_size(int64_t size) { expr_op_size_ = size; } + inline sql::ObExprFrameInfo &get_frame_info() { return frame_info_; } + + TO_STRING_KV(K_(expr_op_size), + K_(tenant_schema_version), + K_(sys_schema_version), + K_(dependency_tables)); + +protected: + int64_t tenant_schema_version_; + int64_t sys_schema_version_; + sql::DependenyTableStore dependency_tables_; + // stored args information after paramalization + common::Ob2DArray params_info_; + sql::ObRawExprFactory expr_factory_; + sql::ObSqlExpressionFactory sql_expression_factory_; + sql::ObExprOperatorFactory expr_operator_factory_; + common::ObFixedArray expressions_; + int64_t expr_op_size_; + sql::ObExprFrameInfo frame_info_; +}; + +} // namespace pl end +} // namespace oceanbase end + +#endif \ No newline at end of file diff --git a/src/pl/sys_package/ob_dbms_session.cpp b/src/pl/sys_package/ob_dbms_session.cpp index 8e4fb1fd8..ee74bdde5 100644 --- a/src/pl/sys_package/ob_dbms_session.cpp +++ b/src/pl/sys_package/ob_dbms_session.cpp @@ -305,6 +305,27 @@ int ObDBMSSession::set_identifier(sql::ObExecContext &ctx, return ret; } +int ObDBMSSession::reset_package(sql::ObExecContext &ctx, + sql::ParamStore ¶ms, + common::ObObj &result) +{ + int ret = OB_SUCCESS; + sql::ObSQLSessionInfo *session = ctx.get_my_session(); + ObPLContext *pl_ctx = nullptr; + ObString client_id; + if (OB_UNLIKELY(OB_ISNULL(session))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session info is nullptr", K(ret)); + } else if (OB_UNLIKELY(0 != params.count())) { + ObString func_name("RESET_PACKAGE"); + ret = OB_ERR_WRONG_FUNC_ARGUMENTS_TYPE; + LOG_USER_ERROR(OB_ERR_WRONG_FUNC_ARGUMENTS_TYPE, func_name.length(), func_name.ptr()); + } else { + session->set_need_reset_package(true); + } + return ret; +} + int ObDBMSSession::check_argument(const ObObj &input_param, bool allow_null, bool need_case_up, int32_t param_idx, int64_t max_len, ObString &output_param) diff --git a/src/pl/sys_package/ob_dbms_session.h b/src/pl/sys_package/ob_dbms_session.h index c98414de3..5f66a51a1 100644 --- a/src/pl/sys_package/ob_dbms_session.h +++ b/src/pl/sys_package/ob_dbms_session.h @@ -34,6 +34,8 @@ public: sql::ObExecContext &ctx, sql::ParamStore ¶ms, common::ObObj &result); static int set_identifier( sql::ObExecContext &ctx, sql::ParamStore ¶ms, common::ObObj &result); + static int reset_package( + sql::ObExecContext &ctx, sql::ParamStore ¶ms, common::ObObj &result); private: static int check_argument(const ObObj &input_param, bool allow_null, bool need_case_up, int32_t param_idx, diff --git a/src/pl/sys_package/ob_dbms_sql.cpp b/src/pl/sys_package/ob_dbms_sql.cpp index 8f89dafcb..e14fd74c0 100644 --- a/src/pl/sys_package/ob_dbms_sql.cpp +++ b/src/pl/sys_package/ob_dbms_sql.cpp @@ -175,8 +175,17 @@ int ObDbmsInfo::set_bind_param(const ObString ¶m_name, const ObObjParam¶ } if (OB_INVALID_INDEX != idx) { - OZ (ob_write_obj(alloc, param_value, bind_params_.at(idx).param_value_), - param_name, param_value); + if (param_value.is_pl_extend() + && param_value.get_ext() != 0 + && param_value.get_meta().get_extend_type() != PL_REF_CURSOR_TYPE) { + if (bind_params_.at(idx).param_value_.get_ext() != 0) { + OZ (ObUserDefinedType::destruct_obj(bind_params_.at(idx).param_value_)); + } + OZ (ObUserDefinedType::deep_copy_obj(alloc, param_value, bind_params_.at(idx).param_value_)); + } else { + OZ (ob_write_obj(alloc, param_value, bind_params_.at(idx).param_value_), + param_name, param_value); + } OX (bind_params_.at(idx).param_value_.set_accuracy(param_value.get_accuracy())); OX (bind_params_.at(idx).param_value_.set_param_meta()); } else { @@ -184,7 +193,13 @@ int ObDbmsInfo::set_bind_param(const ObString ¶m_name, const ObObjParam¶ ObObj clone_value; BindParam clone_param; OZ (ob_write_string(alloc, param_name, clone_name), param_name, param_value); - OZ (ob_write_obj(alloc, param_value, clone_value), param_name, param_value); + if (param_value.is_pl_extend() + && param_value.get_ext() != 0 + && param_value.get_meta().get_extend_type() != PL_REF_CURSOR_TYPE) { + OZ (ObUserDefinedType::deep_copy_obj(alloc, param_value, clone_value)); + } else { + OZ (ob_write_obj(alloc, param_value, clone_value), param_name, param_value); + } OX (clone_param = BindParam(clone_name, clone_value)); OX (clone_param.param_value_.set_accuracy(param_value.get_accuracy())); OX (clone_param.param_value_.set_param_meta()); @@ -288,16 +303,17 @@ int ObDbmsCursorInfo::parse(const ObString &sql_stmt, ObSQLSessionInfo &session) char **param_names = NULL; ObString clone_name; // 解析语句 - OZ (parser.parse(sql_stmt, parse_result, DBMS_SQL_MODE), sql_stmt); + if (OB_FAIL(parser.parse(sql_stmt, parse_result, DBMS_SQL_MODE))) { + LOG_WARN("failed to parse sql_stmt", K(sql_stmt), K(ret)); + int64_t error_offset = + parse_result.start_col_ > 0 ? (parse_result.start_col_ - 1) : 0; + session.get_warnings_buffer().set_error_line_column(0, error_offset); + } OZ (ObResolverUtils::resolve_stmt_type(parse_result, stmt_type_), sql_stmt); // cann't execute multi select stmt - if (OB_FAIL(ret)) { - } else if (ObStmt::is_ddl_stmt(stmt_type_, true)) { - ret = OB_NO_STMT_PARSE; - LOG_WARN("dbms_cursor need parse a select stmt.", K(ret)); - } else if (ObStmt::is_select_stmt(stmt_type_) - && !parser.is_pl_stmt(sql_stmt) - && !parser.is_single_stmt(sql_stmt)) { + if (OB_SUCC(ret) + && !parser.is_pl_stmt(sql_stmt) + && !parser.is_single_stmt(sql_stmt)) { ret = OB_ERR_CMD_NOT_PROPERLY_ENDED; LOG_WARN("execute immdeidate only support one stmt", K(ret)); } @@ -318,6 +334,30 @@ int ObDbmsCursorInfo::parse(const ObString &sql_stmt, ObSQLSessionInfo &session) return ret; } +int64_t ObDbmsCursorInfo::get_dbms_id() +{ + int64_t id = -1; + if (0 == (get_id() & CANDIDATE_CURSOR_ID)) { + // ps cursor id + id = get_id(); + } else { + id = get_id() - CANDIDATE_CURSOR_ID; + } + return id; +} + +int64_t ObDbmsCursorInfo::convert_to_dbms_cursor_id(int64_t id) +{ + int64_t new_id = -1; + if (1 == (id & CANDIDATE_CURSOR_ID)) { + // ps cursor id + new_id = id; + } else { + new_id = id + CANDIDATE_CURSOR_ID; + } + return new_id; +} + } diff --git a/src/pl/sys_package/ob_dbms_sql.h b/src/pl/sys_package/ob_dbms_sql.h index 453b42350..80d1bd582 100644 --- a/src/pl/sys_package/ob_dbms_sql.h +++ b/src/pl/sys_package/ob_dbms_sql.h @@ -169,6 +169,17 @@ private: class ObDbmsCursorInfo : public ObPLCursorInfo, public ObDbmsInfo { +public: + // cursor id in OB + /* ps cursor : always equal with stmt id, always smaller than candidate_cursor_id_ + * ref cursor : always start with CANDIDATE_CURSOR_ID, user can't get ref cursor id by SQL + * only client and server use the id when interacting + * dbms sql cursor : always start with CANDIDATE_CURSOR_ID, user can get cursor id by SQL + * CANDIDATE_CURSOR_ID may be out of precision. + * so we should use get_dbms_id and convert_to_dbms_cursor_id to provide a vaild id for user + */ + static const int64_t CANDIDATE_CURSOR_ID = 1LL << 31; + public: ObDbmsCursorInfo(common::ObIAllocator &alloc) : ObPLCursorInfo(true), @@ -189,6 +200,8 @@ public: int64_t get_affected_rows() const { return affected_rows_; } int prepare_entity(sql::ObSQLSessionInfo &session); int64_t search_array(const ObString &name, ObIArray &array); + int64_t get_dbms_id(); + static int64_t convert_to_dbms_cursor_id(int64_t id); private: // affected_rows_ 在每次 open 都会被重置 diff --git a/src/rootserver/ob_ddl_operator.cpp b/src/rootserver/ob_ddl_operator.cpp index 2fc62f73d..7d0f071e1 100644 --- a/src/rootserver/ob_ddl_operator.cpp +++ b/src/rootserver/ob_ddl_operator.cpp @@ -8606,39 +8606,37 @@ int ObDDLOperator::create_trigger(ObTriggerInfo &trigger_info, ObErrorInfo &error_info, ObIArray &dep_infos, const ObString *ddl_stmt_str, - bool for_insert_errors, bool is_update_table_schema_version, bool is_for_truncate_table) { int ret = OB_SUCCESS; - //for_insert_errors is false: create trigger normally - //for_insert_errors is true: Insert error information into the system table after the trigger is built so the following steps can be skipped - if (!for_insert_errors) { - ObSchemaService *schema_service = schema_service_.get_schema_service(); - const uint64_t tenant_id = trigger_info.get_tenant_id(); - int64_t new_schema_version = OB_INVALID_VERSION; - bool is_replace = false; - OV (OB_NOT_NULL(schema_service)); - if (!is_for_truncate_table) { - // If create_trigger through truncate table, trigger_info already has its own trigger_id. - // but there is no such trigger in the internal table at this time, so is_replace must be false - OX (is_replace = (OB_INVALID_ID != trigger_info.get_trigger_id())); - if (!is_replace) { - OZ (fill_trigger_id(*schema_service, trigger_info), trigger_info.get_trigger_name()); - } - } - OZ (schema_service_.gen_new_schema_version(tenant_id, new_schema_version), - tenant_id, trigger_info.get_trigger_name()); - OX (trigger_info.set_schema_version(new_schema_version)); - OZ (schema_service->get_trigger_sql_service().create_trigger(trigger_info, is_replace, - trans, ddl_stmt_str), - trigger_info.get_trigger_name(), is_replace); - if (!trigger_info.is_system_type() && is_update_table_schema_version) { - uint64_t base_table_id = trigger_info.get_base_object_id(); - OZ (schema_service->get_table_sql_service().update_data_table_schema_version( - trans, tenant_id, base_table_id, false/*in offline ddl white list*/), - base_table_id, trigger_info.get_trigger_name()); + + ObSchemaService *schema_service = schema_service_.get_schema_service(); + const uint64_t tenant_id = trigger_info.get_tenant_id(); + int64_t new_schema_version = OB_INVALID_VERSION; + bool is_replace = false; + OV (OB_NOT_NULL(schema_service)); + if (!is_for_truncate_table) { + // If create_trigger through truncate table, trigger_info already has its own trigger_id. + // but there is no such trigger in the internal table at this time, so is_replace must be false + OX (is_replace = (OB_INVALID_ID != trigger_info.get_trigger_id())); + if (!is_replace) { + OZ (fill_trigger_id(*schema_service, trigger_info), trigger_info.get_trigger_name()); } + } + OZ (schema_service_.gen_new_schema_version(tenant_id, new_schema_version), + tenant_id, trigger_info.get_trigger_name()); + OX (trigger_info.set_schema_version(new_schema_version)); + OZ (schema_service->get_trigger_sql_service().create_trigger(trigger_info, is_replace, + trans, ddl_stmt_str), + trigger_info.get_trigger_name(), is_replace); + if (!trigger_info.is_system_type() && is_update_table_schema_version) { + uint64_t base_table_id = trigger_info.get_base_object_id(); + OZ (schema_service->get_table_sql_service().update_data_table_schema_version( + trans, tenant_id, base_table_id, false/*in offline ddl white list*/), + base_table_id, trigger_info.get_trigger_name()); + } + if (OB_FAIL(ret)) { } else if (0 == dep_infos.count()) { // create trigger in mysql mode or create trigger when truncate table, dep_infos.count() is 0, // no need to deal with dependencies. diff --git a/src/rootserver/ob_ddl_operator.h b/src/rootserver/ob_ddl_operator.h index e617207b8..575ce97a8 100644 --- a/src/rootserver/ob_ddl_operator.h +++ b/src/rootserver/ob_ddl_operator.h @@ -793,7 +793,6 @@ public: share::schema::ObErrorInfo &error_info, ObIArray &dep_infos, const common::ObString *ddl_stmt_str/*=NULL*/, - bool for_insert_errors, bool is_update_table_schema_version = true, bool is_for_truncate_table = false); // set ddl_stmt_str to NULL if the statement is not 'drop trigger xxx'. diff --git a/src/rootserver/ob_ddl_service.cpp b/src/rootserver/ob_ddl_service.cpp index 576ab14d1..56784ba73 100644 --- a/src/rootserver/ob_ddl_service.cpp +++ b/src/rootserver/ob_ddl_service.cpp @@ -14703,7 +14703,7 @@ int ObDDLService::rebuild_triggers_on_hidden_table( if (OB_SUCC(ret)) { ObSEArray dep_infos; OZ (ddl_operator.create_trigger(new_trigger_info, trans, error_info, dep_infos, - nullptr, false/*for_insert_errors*/, false/*is_update_table_schema_version*/)); + nullptr, false/*is_update_table_schema_version*/)); } } } @@ -28202,7 +28202,7 @@ int ObDDLService::create_trigger(const ObCreateTriggerArg &arg) int ret = OB_SUCCESS; ObSchemaGetterGuard schema_guard; ObTriggerInfo new_trigger_info; - //for_insert_errors_ is false, Indicates that the trigger is created normally + //in_second_stage_ is false, Indicates that the trigger is created normally //true Indicates that the error message is inserted into the system table after the trigger is created //So the following steps can be skipped uint64_t tenant_id = OB_INVALID_ID; @@ -28217,7 +28217,7 @@ int ObDDLService::create_trigger(const ObCreateTriggerArg &arg) } else if (FALSE_IT(tenant_id = new_trigger_info.get_tenant_id())) { } else if (OB_FAIL(get_tenant_schema_guard_with_version_in_inner_table(tenant_id, schema_guard))) { LOG_WARN("o get schema guard in inner table failed", KR(ret), K(tenant_id)); - } else if (!arg.for_insert_errors_) { + } else { const ObTriggerInfo *old_trigger_info = NULL; if (!arg.is_valid()) { ret = OB_INVALID_ARGUMENT; @@ -28245,7 +28245,7 @@ int ObDDLService::create_trigger(const ObCreateTriggerArg &arg) const_cast(arg.error_info_), const_cast &>(arg.dependency_infos_), &arg.ddl_stmt_str_, - arg.for_insert_errors_, + arg.in_second_stage_, schema_guard))) { LOG_WARN("create trigger in trans failed", K(ret)); } @@ -28256,7 +28256,7 @@ int ObDDLService::create_trigger_in_trans(ObTriggerInfo &trigger_info, ObErrorInfo &error_info, ObIArray &dep_infos, const ObString *ddl_stmt_str, - bool for_insert_errors, + bool in_second_stage, share::schema::ObSchemaGetterGuard &schema_guard) { int ret = OB_SUCCESS; @@ -28269,10 +28269,10 @@ int ObDDLService::create_trigger_in_trans(ObTriggerInfo &trigger_info, } else if (OB_FAIL(trans.start(sql_proxy_, tenant_id, refreshed_schema_version))) { LOG_WARN("start transaction failed", KR(ret), K(tenant_id), K(refreshed_schema_version)); } - if (OB_SUCC(ret) && !for_insert_errors) { + if (OB_SUCC(ret) && !in_second_stage) { OZ (adjust_trigger_action_order(schema_guard, trans, ddl_operator, trigger_info, true)); } - OZ (ddl_operator.create_trigger(trigger_info, trans, error_info, dep_infos, ddl_stmt_str, for_insert_errors)); + OZ (ddl_operator.create_trigger(trigger_info, trans, error_info, dep_infos, ddl_stmt_str)); if (trans.is_started()) { int temp_ret = OB_SUCCESS; if (OB_SUCCESS != (temp_ret = trans.end(OB_SUCC(ret)))) { @@ -28527,7 +28527,6 @@ int ObDDLService::create_trigger_for_truncate_table(ObSchemaGetterGuard &schema_ ObSEArray dep_infos; if (OB_FAIL(ddl_operator.create_trigger(new_trigger_info, trans, error_info, dep_infos, &origin_trigger_info->get_trigger_body(), - false, /* for_insert_error */ is_update_table_schema_version, true))) { LOG_WARN("failed to create trigger for truncate table", K(ret)); diff --git a/src/share/inner_table/ob_inner_table_schema.12151_12200.cpp b/src/share/inner_table/ob_inner_table_schema.12151_12200.cpp index 0dc3b3652..79770dab8 100644 --- a/src/share/inner_table/ob_inner_table_schema.12151_12200.cpp +++ b/src/share/inner_table/ob_inner_table_schema.12151_12200.cpp @@ -736,6 +736,25 @@ int ObInnerTableSchema::all_virtual_trigger_schema(ObTableSchema &table_schema) false, //is_nullable false); //is_autoincrement } + + if (OB_SUCC(ret)) { + ObObj analyze_flag_default; + analyze_flag_default.set_int(0); + ADD_COLUMN_SCHEMA_T("analyze_flag", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false, //is_autoincrement + analyze_flag_default, + analyze_flag_default); //default_value + } table_schema.set_index_using_type(USING_BTREE); table_schema.set_row_store_type(ENCODING_ROW_STORE); table_schema.set_store_format(OB_STORE_FORMAT_DYNAMIC_MYSQL); @@ -1262,6 +1281,25 @@ int ObInnerTableSchema::all_virtual_trigger_history_schema(ObTableSchema &table_ true, //is_nullable false); //is_autoincrement } + + if (OB_SUCC(ret)) { + ObObj analyze_flag_default; + analyze_flag_default.set_int(0); + ADD_COLUMN_SCHEMA_T("analyze_flag", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + true, //is_nullable + false, //is_autoincrement + analyze_flag_default, + analyze_flag_default); //default_value + } table_schema.set_index_using_type(USING_BTREE); table_schema.set_row_store_type(ENCODING_ROW_STORE); table_schema.set_store_format(OB_STORE_FORMAT_DYNAMIC_MYSQL); diff --git a/src/share/inner_table/ob_inner_table_schema.15101_15150.cpp b/src/share/inner_table/ob_inner_table_schema.15101_15150.cpp index e56ade0b7..1edb31b1c 100644 --- a/src/share/inner_table/ob_inner_table_schema.15101_15150.cpp +++ b/src/share/inner_table/ob_inner_table_schema.15101_15150.cpp @@ -4481,6 +4481,21 @@ int ObInnerTableSchema::all_virtual_tenant_trigger_sys_agent_schema(ObTableSchem false); //is_autoincrement } + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("ANALYZE_FLAG", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObNumberType, //column_type + CS_TYPE_INVALID, //column_collation_type + 38, //column_length + 38, //column_precision + 0, //column_scale + false, //is_nullable + false); //is_autoincrement + } + if (OB_SUCC(ret)) { ADD_COLUMN_SCHEMA("GMT_CREATE", //column_name ++column_id, //column_id diff --git a/src/share/inner_table/ob_inner_table_schema.15151_15200.cpp b/src/share/inner_table/ob_inner_table_schema.15151_15200.cpp index 9a338b947..aafcab9e0 100644 --- a/src/share/inner_table/ob_inner_table_schema.15151_15200.cpp +++ b/src/share/inner_table/ob_inner_table_schema.15151_15200.cpp @@ -1524,6 +1524,21 @@ int ObInnerTableSchema::all_virtual_tenant_trigger_real_agent_ora_schema(ObTable false); //is_autoincrement } + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("ANALYZE_FLAG", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObNumberType, //column_type + CS_TYPE_INVALID, //column_collation_type + 38, //column_length + 38, //column_precision + 0, //column_scale + false, //is_nullable + false); //is_autoincrement + } + if (OB_SUCC(ret)) { ADD_COLUMN_SCHEMA("GMT_CREATE", //column_name ++column_id, //column_id diff --git a/src/share/inner_table/ob_inner_table_schema.251_300.cpp b/src/share/inner_table/ob_inner_table_schema.251_300.cpp index 2b30f0bc6..a537d8ff4 100644 --- a/src/share/inner_table/ob_inner_table_schema.251_300.cpp +++ b/src/share/inner_table/ob_inner_table_schema.251_300.cpp @@ -1547,6 +1547,25 @@ int ObInnerTableSchema::all_tenant_trigger_schema(ObTableSchema &table_schema) false, //is_nullable false); //is_autoincrement } + + if (OB_SUCC(ret)) { + ObObj analyze_flag_default; + analyze_flag_default.set_int(0); + ADD_COLUMN_SCHEMA_T("analyze_flag", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false, //is_autoincrement + analyze_flag_default, + analyze_flag_default); //default_value + } table_schema.set_index_using_type(USING_BTREE); table_schema.set_row_store_type(ENCODING_ROW_STORE); table_schema.set_store_format(OB_STORE_FORMAT_DYNAMIC_MYSQL); @@ -2089,6 +2108,25 @@ int ObInnerTableSchema::all_tenant_trigger_history_schema(ObTableSchema &table_s true, //is_nullable false); //is_autoincrement } + + if (OB_SUCC(ret)) { + ObObj analyze_flag_default; + analyze_flag_default.set_int(0); + ADD_COLUMN_SCHEMA_T("analyze_flag", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + true, //is_nullable + false, //is_autoincrement + analyze_flag_default, + analyze_flag_default); //default_value + } table_schema.set_index_using_type(USING_BTREE); table_schema.set_row_store_type(ENCODING_ROW_STORE); table_schema.set_store_format(OB_STORE_FORMAT_DYNAMIC_MYSQL); diff --git a/src/share/inner_table/ob_inner_table_schema_def.py b/src/share/inner_table/ob_inner_table_schema_def.py index ed4cb09a4..2c2fdbe97 100644 --- a/src/share/inner_table/ob_inner_table_schema_def.py +++ b/src/share/inner_table/ob_inner_table_schema_def.py @@ -2247,6 +2247,7 @@ all_trigger_def = dict( ('ref_trg_db_name', 'varchar:OB_MAX_TRIGGER_NAME_LENGTH', 'true'), ('ref_trg_name', 'varchar:OB_MAX_TRIGGER_NAME_LENGTH', 'true'), ('action_order', 'int', 'false'), + ('analyze_flag', 'int', 'false', 0), ], ) diff --git a/src/share/ob_rpc_struct.h b/src/share/ob_rpc_struct.h index ad5f4c2b2..da029b832 100644 --- a/src/share/ob_rpc_struct.h +++ b/src/share/ob_rpc_struct.h @@ -5827,7 +5827,7 @@ public: K(base_object_name_), K(trigger_info_), K(with_replace_), - K(for_insert_errors_), + K(in_second_stage_), K(error_info_), K(dependency_infos_)); public: @@ -5841,7 +5841,7 @@ public: struct { uint32_t with_replace_:1; - uint32_t for_insert_errors_:1; + uint32_t in_second_stage_:1; // is second create trigger stage uint32_t reserved_:30; }; }; diff --git a/src/share/schema/ob_routine_info.h b/src/share/schema/ob_routine_info.h index 3988b6851..350dd24d1 100644 --- a/src/share/schema/ob_routine_info.h +++ b/src/share/schema/ob_routine_info.h @@ -80,6 +80,11 @@ enum ObRoutineFlag SP_FLAG_READS_SQL_DATA = 65536, SP_FLAG_MODIFIES_SQL_DATA = 131072, SP_FLAG_CONTAINS_SQL = 262144, + SP_FLAG_WPS = SP_FLAG_CONTAINS_SQL * 2, + SP_FLAG_RPS = SP_FLAG_WPS * 2, + SP_FLAG_HAS_SEQUENCE = SP_FLAG_RPS * 2, + SP_FLAG_HAS_OUT_PARAM = SP_FLAG_HAS_SEQUENCE * 2, + SP_FLAG_EXTERNAL_STATE = SP_FLAG_HAS_OUT_PARAM * 2, }; namespace oceanbase @@ -152,7 +157,16 @@ public: virtual bool is_modifies_sql_data() const = 0; virtual void set_contains_sql() = 0; virtual bool is_contains_sql() const = 0; - + virtual bool is_wps() const = 0; + virtual bool is_rps() const = 0; + virtual bool is_has_sequence() const = 0; + virtual bool is_has_out_param() const = 0; + virtual bool is_external_state() const = 0; + virtual void set_wps() = 0; + virtual void set_rps() = 0; + virtual void set_has_sequence() = 0; + virtual void set_has_out_param() = 0; + virtual void set_external_state() = 0; TO_STRING_EMPTY(); }; @@ -469,7 +483,26 @@ public: OB_INLINE void set_no_sql() { flag_ &= ~SP_FLAG_READS_SQL_DATA; flag_ &= ~SP_FLAG_MODIFIES_SQL_DATA; flag_ |= SP_FLAG_NO_SQL;} OB_INLINE void set_reads_sql_data() { flag_ &= ~SP_FLAG_NO_SQL; flag_ &= ~SP_FLAG_MODIFIES_SQL_DATA; flag_ |= SP_FLAG_READS_SQL_DATA;} OB_INLINE void set_modifies_sql_data() { flag_ &= ~SP_FLAG_NO_SQL; flag_ &= ~SP_FLAG_READS_SQL_DATA; flag_ |= SP_FLAG_MODIFIES_SQL_DATA;} - OB_INLINE void set_contains_sql() { flag_ &= ~SP_FLAG_NO_SQL; flag_ &= ~SP_FLAG_READS_SQL_DATA; flag_ &= ~SP_FLAG_MODIFIES_SQL_DATA;} + OB_INLINE void set_contains_sql() + { + flag_ &= ~SP_FLAG_NO_SQL; + flag_ &= ~SP_FLAG_READS_SQL_DATA; + flag_ &= ~SP_FLAG_MODIFIES_SQL_DATA; + flag_ |= SP_FLAG_CONTAINS_SQL; + } + + + OB_INLINE bool is_wps() const { return SP_FLAG_WPS == (flag_ & SP_FLAG_WPS); } + OB_INLINE bool is_rps() const { return SP_FLAG_RPS == (flag_ & SP_FLAG_RPS); } + OB_INLINE bool is_has_sequence() const { return SP_FLAG_HAS_SEQUENCE == (flag_ & SP_FLAG_HAS_SEQUENCE); } + OB_INLINE bool is_has_out_param() const { return SP_FLAG_HAS_OUT_PARAM == (flag_ & SP_FLAG_HAS_OUT_PARAM); } + OB_INLINE bool is_external_state() const { return SP_FLAG_EXTERNAL_STATE == (flag_ & SP_FLAG_EXTERNAL_STATE); } + + OB_INLINE void set_wps() { flag_ |= SP_FLAG_WPS;} + OB_INLINE void set_rps() { flag_ |= SP_FLAG_RPS;} + OB_INLINE void set_has_sequence() { flag_ |= SP_FLAG_HAS_SEQUENCE;} + OB_INLINE void set_has_out_param() { flag_ |= SP_FLAG_HAS_OUT_PARAM;} + OB_INLINE void set_external_state() { flag_ |= SP_FLAG_EXTERNAL_STATE;} OB_INLINE bool is_aggregate() const { return SP_FLAG_AGGREGATE == (flag_ & SP_FLAG_AGGREGATE); } diff --git a/src/share/schema/ob_schema_getter_guard.cpp b/src/share/schema/ob_schema_getter_guard.cpp index 54fcaac42..1762779d0 100644 --- a/src/share/schema/ob_schema_getter_guard.cpp +++ b/src/share/schema/ob_schema_getter_guard.cpp @@ -817,6 +817,107 @@ int ObSchemaGetterGuard::get_routine_infos_in_udt( return ret; } +int ObSchemaGetterGuard::get_routine_info_in_udt(const uint64_t tenant_id, + const uint64_t udt_id, + const uint64_t subprogram_id, + const ObRoutineInfo *&routine_info) +{ + int ret = OB_SUCCESS; + const ObSchemaMgr *mgr = NULL; + routine_info = NULL; + + ObArray schemas; + if (!check_inner_stat()) { + ret = OB_INNER_STAT_ERROR; + LOG_WARN("inner stat error", KR(ret)); + } else if (OB_INVALID_ID == tenant_id || OB_INVALID_ID == udt_id || OB_INVALID_ID == subprogram_id) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(tenant_id), K(udt_id), K(subprogram_id)); + } else if (OB_FAIL(check_tenant_schema_guard(tenant_id))) { + LOG_WARN("fail to check tenant schema guard", KR(ret), K(tenant_id), K_(tenant_id)); + } else if (OB_FAIL(check_lazy_guard(tenant_id, mgr))) { + LOG_WARN("fail to check lazy guard", KR(ret), K(tenant_id)); + } else if (OB_FAIL(mgr->routine_mgr_.get_routine_schemas_in_udt(tenant_id, udt_id, schemas))) { + LOG_WARN("get routine schemas in package failed", KR(ret), K(tenant_id), K(udt_id)); + } else { + bool is_break = false; + FOREACH_CNT_X(schema, schemas, (OB_SUCC(ret) && !is_break)) { + const ObSimpleRoutineSchema *tmp_schema = *schema; + const ObRoutineInfo *sub_routine_info = NULL; + if (OB_ISNULL(tmp_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("NULL ptr", KR(ret), KP(tmp_schema)); + } else if (OB_FAIL(get_schema(ROUTINE_SCHEMA, + tmp_schema->get_tenant_id(), + tmp_schema->get_routine_id(), + sub_routine_info, + tmp_schema->get_schema_version()))) { + LOG_WARN("get schema failed", KR(ret), K(tenant_id), + "routine_id", tmp_schema->get_routine_id(), + "schema_version", tmp_schema->get_schema_version()); + } else if (OB_ISNULL(sub_routine_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("routine info is null", KR(ret)); + } else if (subprogram_id == sub_routine_info->get_subprogram_id()) { + routine_info = sub_routine_info; + is_break = true; + } + } + } + return ret; +} + +int ObSchemaGetterGuard::get_routine_info_in_package(const uint64_t tenant_id, + const uint64_t package_id, + const uint64_t subprogram_id, + const ObRoutineInfo *&routine_info) +{ + int ret = OB_SUCCESS; + const ObSchemaMgr *mgr = NULL; + routine_info = NULL; + + ObArray schemas; + if (!check_inner_stat()) { + ret = OB_INNER_STAT_ERROR; + LOG_WARN("inner stat error", KR(ret)); + } else if (OB_INVALID_ID == tenant_id || OB_INVALID_ID == package_id || OB_INVALID_ID == subprogram_id) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(tenant_id), K(package_id), K(subprogram_id)); + } else if (OB_FAIL(check_tenant_schema_guard(tenant_id))) { + LOG_WARN("fail to check tenant schema guard", KR(ret), K(tenant_id), K_(tenant_id)); + } else if (OB_FAIL(check_lazy_guard(tenant_id, mgr))) { + LOG_WARN("fail to check lazy guard", KR(ret), K(tenant_id)); + } else if (OB_FAIL(mgr->routine_mgr_.get_routine_schemas_in_package(tenant_id, package_id, schemas))) { + LOG_WARN("get routine schemas in package failed", KR(ret), K(tenant_id), K(package_id)); + } else { + bool is_break = false; + FOREACH_CNT_X(schema, schemas, (OB_SUCC(ret) && !is_break)) { + const ObSimpleRoutineSchema *tmp_schema = *schema; + const ObRoutineInfo *sub_routine_info = NULL; + if (OB_ISNULL(tmp_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("NULL ptr", KR(ret), KP(tmp_schema)); + } else if (OB_FAIL(get_schema(ROUTINE_SCHEMA, + tmp_schema->get_tenant_id(), + tmp_schema->get_routine_id(), + sub_routine_info, + tmp_schema->get_schema_version()))) { + LOG_WARN("get schema failed", KR(ret), K(tenant_id), + "routine_id", tmp_schema->get_routine_id(), + "schema_version", tmp_schema->get_schema_version()); + } else if (OB_ISNULL(sub_routine_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("routine info is null", KR(ret)); + } else if (subprogram_id == sub_routine_info->get_subprogram_id()) { + routine_info = sub_routine_info; + is_break = true; + } + } + } + + return ret; +} + int ObSchemaGetterGuard::get_routine_infos_in_package( const uint64_t tenant_id, const uint64_t package_id, common::ObIArray &routine_infos) diff --git a/src/share/schema/ob_schema_getter_guard.h b/src/share/schema/ob_schema_getter_guard.h index c58aebe87..a8d6a9cac 100644 --- a/src/share/schema/ob_schema_getter_guard.h +++ b/src/share/schema/ob_schema_getter_guard.h @@ -312,9 +312,17 @@ public: int get_udt_infos_in_database(const uint64_t tenant_id, const uint64_t database_id, common::ObIArray &udt_infos); + int get_routine_info_in_udt(const uint64_t tenant_id, + const uint64_t udt_id, + const uint64_t subprogram_id, + const ObRoutineInfo *&routine_info); int get_routine_infos_in_udt(const uint64_t tenant_id, const uint64_t udt_id, common::ObIArray &routine_infos); + int get_routine_info_in_package(const uint64_t tenant_id, + const uint64_t package_id, + const uint64_t subprogram_id, + const ObRoutineInfo *&routine_info); int get_routine_infos_in_package(const uint64_t tenant_id, const uint64_t package_id, common::ObIArray &routine_infos); diff --git a/src/share/schema/ob_schema_retrieve_utils.ipp b/src/share/schema/ob_schema_retrieve_utils.ipp index 59b44f9a8..971ac4029 100644 --- a/src/share/schema/ob_schema_retrieve_utils.ipp +++ b/src/share/schema/ob_schema_retrieve_utils.ipp @@ -2186,6 +2186,7 @@ int ObSchemaRetrieveUtils::fill_trigger_schema( ObString default_value; int64_t order_type_defualt_value = 0; int64_t action_order_default_value = 1; + uint64_t analyze_flag_default_value = 0; trigger_info.set_tenant_id(tenant_id); EXTRACT_INT_FIELD_TO_CLASS_MYSQL_WITH_TENANT_ID(result, trigger_id, trigger_info, tenant_id); EXTRACT_INT_FIELD_MYSQL(result, "is_deleted", is_deleted, bool); @@ -2222,6 +2223,8 @@ int ObSchemaRetrieveUtils::fill_trigger_schema( true, true, default_value); EXTRACT_INT_FIELD_TO_CLASS_MYSQL_WITH_DEFAULT_VALUE(result, action_order, trigger_info, int64_t, false, true, action_order_default_value); + EXTRACT_INT_FIELD_TO_CLASS_MYSQL_WITH_DEFAULT_VALUE(result, analyze_flag, trigger_info, uint64_t, + true, true, analyze_flag_default_value); } return ret; } diff --git a/src/share/schema/ob_table_schema.cpp b/src/share/schema/ob_table_schema.cpp index 78dadd10c..d3a7d2f07 100644 --- a/src/share/schema/ob_table_schema.cpp +++ b/src/share/schema/ob_table_schema.cpp @@ -6890,6 +6890,26 @@ int ObTableSchema::has_before_update_row_trigger(ObSchemaGetterGuard &schema_gua return ret; } +int ObTableSchema::is_allow_parallel_of_trigger(ObSchemaGetterGuard &schema_guard, + bool &is_forbid_parallel) const +{ + int ret = OB_SUCCESS; + const ObTriggerInfo *trigger_info = NULL; + is_forbid_parallel = false; + const uint64_t tenant_id = get_tenant_id(); + for (int i = 0; OB_SUCC(ret) && !is_forbid_parallel && i < trigger_list_.count(); i++) { + OZ (schema_guard.get_trigger_info(tenant_id, trigger_list_.at(i), trigger_info), trigger_list_.at(i)); + OV (OB_NOT_NULL(trigger_info), OB_ERR_UNEXPECTED, trigger_list_.at(i)); + OX (is_forbid_parallel = trigger_info->is_reads_sql_data() || + trigger_info->is_modifies_sql_data() || + trigger_info->is_wps() || + trigger_info->is_rps() || + trigger_info->is_has_sequence() || + trigger_info->is_external_state()); + } + return ret; +} + const ObColumnSchemaV2 *ObColumnIterByPrevNextID::get_first_column() const { ObColumnSchemaV2 *ret_col = NULL; diff --git a/src/share/schema/ob_table_schema.h b/src/share/schema/ob_table_schema.h index cb187b7b3..c75d4b2d4 100644 --- a/src/share/schema/ob_table_schema.h +++ b/src/share/schema/ob_table_schema.h @@ -1284,6 +1284,8 @@ public: bool &trigger_exist) const; int has_before_update_row_trigger(ObSchemaGetterGuard &schema_guard, bool &trigger_exist) const; + int is_allow_parallel_of_trigger(ObSchemaGetterGuard &schema_guard, + bool &is_forbid_parallel) const; //label security inline bool has_label_se_column() const { return label_se_column_ids_.count() > 0; } diff --git a/src/share/schema/ob_trigger_info.cpp b/src/share/schema/ob_trigger_info.cpp index 076606f88..7c43d3b3d 100644 --- a/src/share/schema/ob_trigger_info.cpp +++ b/src/share/schema/ob_trigger_info.cpp @@ -53,7 +53,8 @@ OB_SERIALIZE_MEMBER((ObTriggerInfo, ObSimpleTriggerSchema), order_type_, ref_trg_db_name_, ref_trg_name_, - action_order_); + action_order_, + analyze_flag_); ObTriggerInfo &ObTriggerInfo::operator =(const ObTriggerInfo &other) { @@ -103,6 +104,7 @@ void ObTriggerInfo::reset() reset_string(ref_trg_name_); action_order_ = 0; ObSimpleTriggerSchema::reset(); + analyze_flag_ = 0; } bool ObTriggerInfo::is_valid_for_create() const @@ -164,6 +166,7 @@ int ObTriggerInfo::deep_copy(const ObTriggerInfo &other) OZ (set_ref_trg_db_name(other.get_ref_trg_db_name())); OZ (set_ref_trg_name(other.get_ref_trg_name())); OX (set_action_order(other.get_action_order())); + OX (set_analyze_flag(other.get_analyze_flag())); return ret; } diff --git a/src/share/schema/ob_trigger_info.h b/src/share/schema/ob_trigger_info.h index 1723de81a..53be8b75e 100644 --- a/src/share/schema/ob_trigger_info.h +++ b/src/share/schema/ob_trigger_info.h @@ -408,6 +408,29 @@ public: OB_INLINE const common::ObString &get_ref_trg_db_name() const { return ref_trg_db_name_; } OB_INLINE const common::ObString &get_ref_trg_name() const { return ref_trg_name_; } OB_INLINE int64_t get_action_order() const { return action_order_; } + + OB_INLINE void set_analyze_flag(uint64_t flag) { analyze_flag_ = flag; } + OB_INLINE uint64_t get_analyze_flag() const { return analyze_flag_; } + + OB_INLINE void set_no_sql() { is_no_sql_ = true; is_reads_sql_data_ = false; is_modifies_sql_data_ = false; is_contains_sql_ = false; } + OB_INLINE bool is_no_sql() const { return is_no_sql_; } + OB_INLINE void set_reads_sql_data() { is_no_sql_ = false; is_reads_sql_data_ = true; is_modifies_sql_data_ = false; is_contains_sql_ = false; } + OB_INLINE bool is_reads_sql_data() const { return is_reads_sql_data_; } + OB_INLINE void set_modifies_sql_data() { is_no_sql_ = false; is_reads_sql_data_ = false; is_modifies_sql_data_ = true; is_contains_sql_ = false; } + OB_INLINE bool is_modifies_sql_data() const { return is_modifies_sql_data_; } + OB_INLINE void set_contains_sql() { is_no_sql_ = false; is_reads_sql_data_ = false; is_modifies_sql_data_ = false; is_contains_sql_ = true; } + OB_INLINE bool is_contains_sql() const { return is_contains_sql_; } + + OB_INLINE void set_wps(bool v) { is_wps_ = v; } + OB_INLINE bool is_wps() const { return is_wps_; } + OB_INLINE void set_rps(bool v) { is_rps_ = v; } + OB_INLINE bool is_rps() const { return is_rps_; } + OB_INLINE void set_has_sequence(bool v) { is_has_sequence_ = v; } + OB_INLINE bool is_has_sequence() const { return is_has_sequence_; } + OB_INLINE void set_has_out_param(bool v) { is_has_out_param_ = v; } + OB_INLINE bool is_has_out_param() const { return is_has_out_param_; } + OB_INLINE void set_external_state(bool v) { is_external_state_ = v; } + OB_INLINE bool is_external_state() const { return is_external_state_; } OB_INLINE bool is_row_level_before_trigger() const { return is_simple_dml_type() && timing_points_.only_before_row(); } OB_INLINE bool is_row_level_after_trigger() const { return is_simple_dml_type() && timing_points_.only_after_row(); } OB_INLINE bool is_stmt_level_before_trigger() const { return is_simple_dml_type() && timing_points_.only_before_stmt(); } @@ -508,7 +531,8 @@ public: K(order_type_), K(ref_trg_db_name_), K(ref_trg_name_), - K(action_order_)); + K(action_order_), + K(analyze_flag_)); protected: static int gen_package_source_simple(const ObTriggerInfo &trigger_info, const common::ObString &base_object_database, @@ -595,6 +619,21 @@ protected: common::ObString ref_trg_db_name_; // 排序方式中指定的trigger的db name common::ObString ref_trg_name_; // 排序方式中指定的trigger的name int64_t action_order_; // 该值在rs端计算,从系统表里面读出来的值是有意义的 + union { + uint64_t analyze_flag_; + struct { + uint64_t is_no_sql_ : 1; + uint64_t is_reads_sql_data_ : 1; + uint64_t is_modifies_sql_data_ : 1; + uint64_t is_contains_sql_ : 1; + uint64_t is_wps_ : 1; + uint64_t is_rps_ : 1; + uint64_t is_has_sequence_ : 1; + uint64_t is_has_out_param_ : 1; + uint64_t is_external_state_ : 1; + uint64_t reserved_:54; + }; + }; }; diff --git a/src/share/schema/ob_trigger_sql_service.cpp b/src/share/schema/ob_trigger_sql_service.cpp index cf986278e..5566f28e6 100644 --- a/src/share/schema/ob_trigger_sql_service.cpp +++ b/src/share/schema/ob_trigger_sql_service.cpp @@ -264,6 +264,18 @@ int ObTriggerSqlService::fill_dml_sql(const ObTriggerInfo &trigger_info, OZ (dml.add_column("ref_trg_db_name", ObHexEscapeSqlStr(trigger_info.get_ref_trg_db_name()))); OZ (dml.add_column("ref_trg_name", ObHexEscapeSqlStr(trigger_info.get_ref_trg_name()))); OZ (dml.add_column("action_order", trigger_info.get_action_order())); + if (OB_SUCC(ret)) { + uint64_t data_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(trigger_info.get_tenant_id(), data_version))) { + LOG_WARN("failed to get data version", K(ret)); + } else if (data_version < DATA_VERSION_4_2_0_0 && 0 != trigger_info.get_analyze_flag()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("tenant data version is less than 4.2, analyze_flag column is not supported", K(ret), K(data_version)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "tenant data version is less than 4.2, analyze_flag column"); + } else if (data_version >= DATA_VERSION_4_2_0_0) { + OZ (dml.add_column("analyze_flag", trigger_info.get_analyze_flag())); + } + } return ret; } diff --git a/src/sql/code_generator/ob_dml_cg_service.cpp b/src/sql/code_generator/ob_dml_cg_service.cpp index 2af582290..36c45f36e 100644 --- a/src/sql/code_generator/ob_dml_cg_service.cpp +++ b/src/sql/code_generator/ob_dml_cg_service.cpp @@ -1690,6 +1690,7 @@ int ObDmlCgService::add_trigger_arg(const ObTriggerInfo &trigger_info, ObDMLBase trigger_arg.set_trigger_id(trigger_info.get_trigger_id()); trigger_arg.set_trigger_events(trigger_info.get_trigger_events()); trigger_arg.set_timing_points(trigger_info.get_timing_points()); + trigger_arg.set_analyze_flag(trigger_info.get_analyze_flag()); if (OB_FAIL(dml_ctdef.trig_ctdef_.tg_args_.push_back(trigger_arg))) { LOG_WARN("failed to add trigger arg", K(ret)); } else { @@ -2077,10 +2078,27 @@ int ObDmlCgService::convert_normal_triggers(ObLogDelUpd &log_op, } LOG_DEBUG("debug trigger", K(trig_ctdef.new_row_exprs_.count()), K(trig_ctdef.old_row_exprs_.count())); - cg_.phy_plan_->set_has_nested_sql(true); - //为了支持触发器/UDF支持异常捕获,要求含有trigger的涉及修改表数据的dml串行执行 - cg_.phy_plan_->set_need_serial_exec(true); - cg_.phy_plan_->set_contain_pl_udf_or_trigger(true); + bool is_forbid_parallel = false; + const ObTriggerInfo *trigger_info = NULL; + for (int64_t i = 0; OB_SUCC(ret) && !is_forbid_parallel && i < trigger_infos.count(); ++i) { + trigger_info = trigger_infos.at(i); + if (trigger_info->is_modifies_sql_data() || + trigger_info->is_wps() || + trigger_info->is_rps() || + trigger_info->is_has_sequence()) { + is_forbid_parallel = true; + } else if (trigger_info->is_reads_sql_data()) { // dml + trigger(select) serial execute + is_forbid_parallel = true; + } else if (trigger_info->is_external_state()) { + is_forbid_parallel = true; + } + } + if (is_forbid_parallel) { + cg_.phy_plan_->set_has_nested_sql(true); + //为了支持触发器/UDF支持异常捕获,要求含有trigger的涉及修改表数据的dml串行执行 + cg_.phy_plan_->set_need_serial_exec(true); + cg_.phy_plan_->set_contain_pl_udf_or_trigger(true); + } } } return ret; diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index 450ae7864..03b565c99 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -6575,7 +6575,7 @@ int ObStaticEngineCG::set_other_properties(const ObLogPlan &log_plan, ObPhysical if (OB_ISNULL(log_plan.get_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); - } else if (log_plan.get_stmt()->get_query_ctx()->has_pl_udf_) { + } else if (log_plan.get_stmt()->get_query_ctx()->disable_udf_parallel_) { if (log_plan.get_stmt()->is_insert_stmt() || log_plan.get_stmt()->is_update_stmt() || log_plan.get_stmt()->is_delete_stmt() || diff --git a/src/sql/engine/cmd/ob_routine_executor.cpp b/src/sql/engine/cmd/ob_routine_executor.cpp index 2c952c188..32f46aa02 100644 --- a/src/sql/engine/cmd/ob_routine_executor.cpp +++ b/src/sql/engine/cmd/ob_routine_executor.cpp @@ -68,6 +68,7 @@ int ObCallProcedureExecutor::execute(ObExecContext &ctx, ObCallProcedureStmt &st int ret = OB_SUCCESS; uint64_t package_id = OB_INVALID_ID; uint64_t routine_id = OB_INVALID_ID; + ObCallProcedureInfo *call_proc_info = NULL; LOG_DEBUG("call procedure execute", K(stmt)); if (OB_ISNULL(ctx.get_pl_engine()) || OB_ISNULL(ctx.get_output_row())) { ret = OB_ERR_UNEXPECTED; @@ -89,27 +90,42 @@ int ObCallProcedureExecutor::execute(ObExecContext &ctx, ObCallProcedureStmt &st ctx.get_my_session()->get_current_query_string(), ctx.get_stmt_factory()->get_query_ctx()->get_sql_stmt()))) { LOG_WARN("fail to set query string"); + } else if (OB_ISNULL(call_proc_info = stmt.get_call_proc_info())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("call procedure info is null", K(ret)); } else { ParamStore params( (ObWrapperAllocator(ctx.get_allocator())) ); const share::schema::ObRoutineInfo *routine_info = NULL; - if (!stmt.can_direct_use_param()) { + if (!call_proc_info->can_direct_use_param()) { ObObjParam param; - for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_params().count(); ++i) { - const ObRawExpr *expr = stmt.get_params().at(i); + const ParamStore &origin_params = ctx.get_physical_plan_ctx()->get_param_store_for_update(); + pl::ExecCtxBak exec_ctx_bak; + sql::ObPhysicalPlanCtx phy_plan_ctx(ctx.get_allocator()); + phy_plan_ctx.set_timeout_timestamp(ctx.get_physical_plan_ctx()->get_timeout_timestamp()); + exec_ctx_bak.backup(ctx); + ctx.set_physical_plan_ctx(&phy_plan_ctx); + if (call_proc_info->get_expr_op_size() > 0) { + OZ (ctx.init_expr_op(call_proc_info->get_expr_op_size())); + } + OZ (call_proc_info->get_frame_info().pre_alloc_exec_memory(ctx)); + + for (int64_t i = 0; OB_SUCC(ret) && i < origin_params.count(); ++i) { + OZ (phy_plan_ctx.get_param_store_for_update().push_back(origin_params.at(i))); + } + + for (int64_t i = 0; OB_SUCC(ret) && i < call_proc_info->get_expressions().count(); ++i) { + const ObSqlExpression *expr = call_proc_info->get_expressions().at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param expr NULL", K(i), K(ret)); } else { param.reset(); param.ObObj::reset(); - param.set_accuracy(expr->get_accuracy()); - param.set_result_flag(expr->get_result_flag()); - if (OB_FAIL(ObSQLUtils::calc_raw_expr_without_row(ctx, expr, param, - &(ctx.get_physical_plan_ctx()->get_param_store_for_update()), ctx.get_allocator()))) { + if (OB_FAIL(ObSQLUtils::calc_sql_expression_without_row(ctx, *expr, param))) { LOG_WARN("failed to calc exec param expr", K(i), K(*expr), K(ret)); } else { - if (expr->has_flag(ObExprInfoFlag::IS_PL_MOCK_DEFAULT_EXPR)) { + if (expr->get_is_pl_mock_default_expr()) { param.set_is_pl_mock_default_param(true); } if (OB_FAIL(params.push_back(param))) { @@ -120,12 +136,18 @@ int ObCallProcedureExecutor::execute(ObExecContext &ctx, ObCallProcedureStmt &st } } } // for end + + if (call_proc_info->get_expr_op_size() > 0) { + ctx.reset_expr_op(); + ctx.get_allocator().free(ctx.get_expr_op_ctx_store()); + } + exec_ctx_bak.restore(ctx); } else { LOG_DEBUG("direct use params", K(ret), K(stmt)); int64_t param_cnt = ctx.get_physical_plan_ctx()->get_param_store().count(); - if (stmt.get_param_cnt() != param_cnt) { + if (call_proc_info->get_param_cnt() != param_cnt) { ret = OB_ERR_SP_WRONG_ARG_NUM; - LOG_WARN("argument number not equal", K(stmt.get_param_cnt()), K(param_cnt), K(ret)); + LOG_WARN("argument number not equal", K(call_proc_info->get_param_cnt()), K(param_cnt), K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < param_cnt; ++i) { LOG_DEBUG("params", "param", ctx.get_physical_plan_ctx()->get_param_store().at(i), K(i)); @@ -135,14 +157,14 @@ int ObCallProcedureExecutor::execute(ObExecContext &ctx, ObCallProcedureStmt &st } } if (OB_SUCC(ret)) { - package_id = stmt.get_package_id(); - routine_id = stmt.get_routine_id(); + package_id = call_proc_info->get_package_id(); + routine_id = call_proc_info->get_routine_id(); } if (OB_SUCC(ret)) { ObArray path; ObArray nocopy_params; ObObj result; - int64_t pkg_id = stmt.is_udt_routine() + int64_t pkg_id = call_proc_info->is_udt_routine() ? share::schema::ObUDTObjectType::mask_object_id(package_id) : package_id; if (OB_FAIL(ctx.get_pl_engine()->execute(ctx, ctx.get_allocator(), @@ -160,20 +182,20 @@ int ObCallProcedureExecutor::execute(ObExecContext &ctx, ObCallProcedureStmt &st } } if (OB_FAIL(ret)) { - } else if (stmt.get_output_count() > 0) { - ctx.get_output_row()->count_ = stmt.get_output_count(); + } else if (call_proc_info->get_output_count() > 0) { + ctx.get_output_row()->count_ = call_proc_info->get_output_count(); if (OB_ISNULL(ctx.get_output_row()->cells_ = static_cast( - ctx.get_allocator().alloc(sizeof(ObObj) * stmt.get_output_count())))) { + ctx.get_allocator().alloc(sizeof(ObObj) * call_proc_info->get_output_count())))) { ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to alloc obj array", K(stmt.get_output_count()), K(ret)); + LOG_WARN("fail to alloc obj array", K(call_proc_info->get_output_count()), K(ret)); } else { int64_t idx = 0; for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) { - if (stmt.is_out_param(i)) { + if (call_proc_info->is_out_param(i)) { if (ob_is_enum_or_set_type(params.at(i).get_type())) { OZ (ObSPIService::cast_enum_set_to_string( ctx, - stmt.get_out_type().at(idx).get_type_info(), + call_proc_info->get_out_type().at(idx).get_type_info(), params.at(i), ctx.get_output_row()->cells_[idx])); OX (idx++); @@ -183,30 +205,26 @@ int ObCallProcedureExecutor::execute(ObExecContext &ctx, ObCallProcedureStmt &st } if (OB_FAIL(ret)) { - } else if (!stmt.can_direct_use_param()) { - const ObRawExpr *expr = stmt.get_params().at(i); - if (OB_LIKELY(expr->is_const_raw_expr())) { - const ObConstRawExpr *const_expr = static_cast(expr); - if (T_QUESTIONMARK == const_expr->get_expr_type()) { - int64_t idx = const_expr->get_value().get_unknown(); + } else if (!call_proc_info->can_direct_use_param()) { + const ObSqlExpression *expr = call_proc_info->get_expressions().at(i); + ObItemType expr_type = expr->get_expr_items().at(0).get_item_type(); + if (OB_LIKELY(IS_CONST_TYPE(expr_type))) { + const ObObj &value = expr->get_expr_items().at(0).get_obj(); + if (T_QUESTIONMARK == expr_type) { + int64_t idx = value.get_unknown(); ctx.get_physical_plan_ctx()->get_param_store_for_update().at(idx) = params.at(i); } else { /* do nothing */ } - } else if (T_OP_GET_USER_VAR == expr->get_expr_type()) { //这里只有可能出现用户变量 - const ObSysFunRawExpr *func_expr = static_cast(expr); + } else if (T_OP_GET_USER_VAR == expr_type) { //这里只有可能出现用户变量 ObExprCtx expr_ctx; - if (OB_FAIL(ObSQLUtils::wrap_expr_ctx(stmt.get_stmt_type(), ctx, ctx.get_allocator(), expr_ctx))) { + if (expr->get_expr_items().count() < 2 || T_VARCHAR != expr->get_expr_items().at(1).get_item_type()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected result expr", K(*expr), K(ret)); + } else if (OB_FAIL(ObSQLUtils::wrap_expr_ctx(stmt.get_stmt_type(), ctx, ctx.get_allocator(), expr_ctx))) { LOG_WARN("Failed to wrap expr ctx", K(ret)); - } else if (OB_ISNULL(func_expr->get_param_expr(0))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("sys var is NULL", K(*func_expr), K(ret)); - } else if (OB_UNLIKELY(!func_expr->get_param_expr(0)->is_const_raw_expr() - || !static_cast(func_expr->get_param_expr(0))->get_value().is_varchar())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid sys var", K(*func_expr->get_param_expr(0)), K(ret)); } else { - const ObString var_name = static_cast(func_expr->get_param_expr(0))->get_value().get_varchar(); + const ObString var_name = expr->get_expr_items().at(1).get_obj().get_string(); if (OB_FAIL(ObVariableSetExecutor::set_user_variable(params.at(i), var_name, expr_ctx))) { LOG_WARN("set user variable failed", K(ret)); } diff --git a/src/sql/engine/cmd/ob_trigger_executor.cpp b/src/sql/engine/cmd/ob_trigger_executor.cpp index 79fe4c7b8..3b370c8bd 100644 --- a/src/sql/engine/cmd/ob_trigger_executor.cpp +++ b/src/sql/engine/cmd/ob_trigger_executor.cpp @@ -59,10 +59,7 @@ int ObCreateTriggerExecutor::execute(ObExecContext &ctx, ObCreateTriggerStmt &st ctx.get_allocator(), arg)); if (OB_SUCC(ret)) { - if (lib::is_oracle_mode() || - (lib::is_mysql_mode() && arg.error_info_.get_error_status() != ERROR_STATUS_NO_ERROR)) { - OZ (common_rpc_proxy->create_trigger(arg), common_rpc_proxy->get_server()); - } + OZ (common_rpc_proxy->create_trigger(arg), common_rpc_proxy->get_server()); } OZ (ctx.get_sql_ctx()->schema_guard_->reset()); return ret; @@ -134,7 +131,8 @@ int ObCreateTriggerExecutor::analyze_dependencies(ObSchemaGetterGuard &schema_gu if (OB_SUCC(ret)) { arg.trigger_info_.deep_copy(*trigger_info); arg.error_info_.collect_error_info(&arg.trigger_info_); - arg.for_insert_errors_ = true; + arg.in_second_stage_ = true; + arg.with_replace_ = true; } } return ret; diff --git a/src/sql/engine/dml/ob_dml_ctx_define.h b/src/sql/engine/dml/ob_dml_ctx_define.h index 77f9c9e59..8ac466c34 100644 --- a/src/sql/engine/dml/ob_dml_ctx_define.h +++ b/src/sql/engine/dml/ob_dml_ctx_define.h @@ -153,7 +153,8 @@ public: ObTriggerArg() : trigger_id_(common::OB_INVALID_ID), trigger_events_(), - timing_points_() + timing_points_(), + analyze_flag_(0) {} inline void reset() { @@ -174,6 +175,23 @@ public: { timing_points_.set_value(timing_points); } + inline void set_analyze_flag(uint64_t flag) { analyze_flag_ = flag; } + + inline bool is_no_sql() const { return is_no_sql_; } + inline bool is_reads_sql_data() const { return is_reads_sql_data_; } + inline bool is_modifies_sql_data() const { return is_modifies_sql_data_; } + inline bool is_contains_sql() const { return is_contains_sql_; } + inline bool is_wps() const { return is_wps_; } + inline bool is_rps() const { return is_rps_; } + inline bool is_has_sequence() const { return is_has_sequence_; } + inline bool is_has_out_param() const { return is_has_out_param_; } + inline bool is_external_state() const { return is_external_state_; } + + inline bool is_execute_single_row() const + { + return (is_modifies_sql_data_ || is_wps_ || is_rps_ || is_has_sequence_ || + is_reads_sql_data_ || is_external_state_); + } inline uint64_t get_trigger_id() const { return trigger_id_; } inline bool has_when_condition() const { return timing_points_.has_when_condition(); } @@ -198,6 +216,21 @@ private: share::schema::ObTimingPoints timing_points_; common::ObString package_spec_; common::ObString package_body_; + union { + uint64_t analyze_flag_; + struct { + uint64_t is_no_sql_ : 1; // it marks trigger do not contain sql stmt + uint64_t is_reads_sql_data_ : 1; // it marks trigger contain read sql stmt, such as select stmt + uint64_t is_modifies_sql_data_ : 1; // it marks trigger contain write sql stmt + uint64_t is_contains_sql_ : 1; // it marks trigger do not contain read and write sql, but contain other sql stmt, such as set stmt + uint64_t is_wps_ : 1; // it marks trigger write package var + uint64_t is_rps_ : 1; // it marks trigger read package var + uint64_t is_has_sequence_ : 1; // it marks trigger used sequence + uint64_t is_has_out_param_ : 1; // it marks trigger has out param + uint64_t is_external_state_ : 1; // it marks trigger access other store routine or global var etc.. + uint64_t reserved_:54; + }; + }; }; typedef common::ObFixedArray ObTriggerArgArray; diff --git a/src/sql/engine/dml/ob_table_delete_op.cpp b/src/sql/engine/dml/ob_table_delete_op.cpp index 6630ccbc3..8a15aa0bd 100644 --- a/src/sql/engine/dml/ob_table_delete_op.cpp +++ b/src/sql/engine/dml/ob_table_delete_op.cpp @@ -142,8 +142,11 @@ int ObTableDeleteOp::check_need_exec_single_row() for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.del_ctdefs_.count() && !execute_single_row_; ++i) { const ObTableDeleteSpec::DelCtDefArray &ctdefs = MY_SPEC.del_ctdefs_.at(i); const ObDelCtDef &del_ctdef = *ctdefs.at(0); - if (has_before_row_trigger(del_ctdef) || has_after_row_trigger(del_ctdef)) { - execute_single_row_ = true; + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < del_ctdef.trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = del_ctdef.trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } const ObForeignKeyArgArray &fk_args = del_ctdef.fk_args_; for (int j = 0; OB_SUCC(ret) && j < fk_args.count() && !execute_single_row_; j++) { diff --git a/src/sql/engine/dml/ob_table_insert_all_op.cpp b/src/sql/engine/dml/ob_table_insert_all_op.cpp index 646039c95..eb35f0de9 100644 --- a/src/sql/engine/dml/ob_table_insert_all_op.cpp +++ b/src/sql/engine/dml/ob_table_insert_all_op.cpp @@ -111,8 +111,11 @@ int ObTableInsertAllOp::check_need_exec_single_row() const ObInsCtDef &ins_ctdef = *(ctdefs.at(0)); const uint64_t table_id = ins_ctdef.das_base_ctdef_.index_tid_; const ObForeignKeyArgArray &fk_args = ins_ctdef.fk_args_; - if (has_before_row_trigger(ins_ctdef) || has_after_row_trigger(ins_ctdef)) { - execute_single_row_ = true; + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < ins_ctdef.trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = ins_ctdef.trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } for (int j = 0; OB_SUCC(ret) && j < fk_args.count() && !execute_single_row_; j++) { const ObForeignKeyArg &fk_arg = fk_args.at(j); diff --git a/src/sql/engine/dml/ob_table_insert_op.cpp b/src/sql/engine/dml/ob_table_insert_op.cpp index 366ca7914..e784c2658 100644 --- a/src/sql/engine/dml/ob_table_insert_op.cpp +++ b/src/sql/engine/dml/ob_table_insert_op.cpp @@ -116,8 +116,11 @@ int ObTableInsertOp::check_need_exec_single_row() for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.ins_ctdefs_.count() && !execute_single_row_; ++i) { const ObTableInsertSpec::InsCtDefArray &ctdefs = MY_SPEC.ins_ctdefs_.at(i); const ObInsCtDef &ins_ctdef = *ctdefs.at(0); - if (has_before_row_trigger(ins_ctdef) || has_after_row_trigger(ins_ctdef)) { - execute_single_row_ = true; + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < ins_ctdef.trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = ins_ctdef.trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } } } diff --git a/src/sql/engine/dml/ob_table_insert_up_op.cpp b/src/sql/engine/dml/ob_table_insert_up_op.cpp index dd5bc1825..caf64cfee 100644 --- a/src/sql/engine/dml/ob_table_insert_up_op.cpp +++ b/src/sql/engine/dml/ob_table_insert_up_op.cpp @@ -97,9 +97,17 @@ int ObTableInsertUpOp::check_need_exec_single_row() const ObInsCtDef *ins_ctdef = insert_up_ctdef->ins_ctdef_; const ObUpdCtDef *upd_ctdef = insert_up_ctdef->upd_ctdef_; if (OB_NOT_NULL(ins_ctdef) && OB_NOT_NULL(upd_ctdef)) { - if (has_before_row_trigger(*ins_ctdef) || has_after_row_trigger(*ins_ctdef) || - has_before_row_trigger(*upd_ctdef) || has_after_row_trigger(*upd_ctdef)) { - execute_single_row_ = true; + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < ins_ctdef->trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = ins_ctdef->trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); + } + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < upd_ctdef->trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = upd_ctdef->trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } } else { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/engine/dml/ob_table_merge_op.cpp b/src/sql/engine/dml/ob_table_merge_op.cpp index b87a92471..1b3061222 100644 --- a/src/sql/engine/dml/ob_table_merge_op.cpp +++ b/src/sql/engine/dml/ob_table_merge_op.cpp @@ -161,22 +161,31 @@ int ObTableMergeOp::check_need_exec_single_row() ObMergeCtDef *merge_ctdef = MY_SPEC.merge_ctdefs_.at(0); if (!execute_single_row_ && OB_NOT_NULL(merge_ctdef->ins_ctdef_)) { const ObInsCtDef &ins_ctdef = *merge_ctdef->ins_ctdef_; - if (has_before_row_trigger(ins_ctdef) || has_after_row_trigger(ins_ctdef)) { - execute_single_row_ = true; + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < ins_ctdef.trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = ins_ctdef.trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } } if (!execute_single_row_ && OB_NOT_NULL(merge_ctdef->upd_ctdef_)) { const ObUpdCtDef &upd_ctdef = *merge_ctdef->upd_ctdef_; - if (has_before_row_trigger(upd_ctdef) || has_after_row_trigger(upd_ctdef)) { - execute_single_row_ = true; + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < upd_ctdef.trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = upd_ctdef.trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } } if (!execute_single_row_ && OB_NOT_NULL(merge_ctdef->del_ctdef_)) { const ObDelCtDef &del_ctdef = *merge_ctdef->del_ctdef_; - if (has_before_row_trigger(del_ctdef) || has_after_row_trigger(del_ctdef)) { - execute_single_row_ = true; + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < del_ctdef.trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = del_ctdef.trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } } } diff --git a/src/sql/engine/dml/ob_table_replace_op.cpp b/src/sql/engine/dml/ob_table_replace_op.cpp index 8a617c91d..ca47d5e09 100644 --- a/src/sql/engine/dml/ob_table_replace_op.cpp +++ b/src/sql/engine/dml/ob_table_replace_op.cpp @@ -102,10 +102,20 @@ int ObTableReplaceOp::check_need_exec_single_row() ObReplaceCtDef *replace_ctdef = MY_SPEC.replace_ctdefs_.at(0); const ObInsCtDef *ins_ctdef = replace_ctdef->ins_ctdef_; const ObDelCtDef *del_ctdef = replace_ctdef->del_ctdef_; - if (OB_NOT_NULL(ins_ctdef) || OB_NOT_NULL(del_ctdef)) { - if (has_before_row_trigger(*ins_ctdef) || has_after_row_trigger(*ins_ctdef) - || has_before_row_trigger(*del_ctdef) || has_after_row_trigger(*del_ctdef)) { - execute_single_row_ = true; + if (OB_NOT_NULL(ins_ctdef)) { + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < ins_ctdef->trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = ins_ctdef->trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); + } + } + if (OB_NOT_NULL(del_ctdef)) { + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < del_ctdef->trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = del_ctdef->trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } } else { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/engine/dml/ob_table_update_op.cpp b/src/sql/engine/dml/ob_table_update_op.cpp index a700d46a6..f648fc578 100644 --- a/src/sql/engine/dml/ob_table_update_op.cpp +++ b/src/sql/engine/dml/ob_table_update_op.cpp @@ -121,8 +121,11 @@ int ObTableUpdateOp::check_need_exec_single_row() for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.upd_ctdefs_.count() && !execute_single_row_; ++i) { const ObTableUpdateSpec::UpdCtDefArray &ctdefs = MY_SPEC.upd_ctdefs_.at(i); const ObUpdCtDef &upd_ctdef = *ctdefs.at(0); - if (has_before_row_trigger(upd_ctdef) || has_after_row_trigger(upd_ctdef)) { - execute_single_row_ = true; + for (int64_t j = 0; + OB_SUCC(ret) && !execute_single_row_ && j < upd_ctdef.trig_ctdef_.tg_args_.count(); + ++j) { + const ObTriggerArg &tri_arg = upd_ctdef.trig_ctdef_.tg_args_.at(j); + execute_single_row_ = tri_arg.is_execute_single_row(); } } } diff --git a/src/sql/engine/dml/ob_trigger_handler.cpp b/src/sql/engine/dml/ob_trigger_handler.cpp index b1d8782c7..cfc9d0bf7 100644 --- a/src/sql/engine/dml/ob_trigger_handler.cpp +++ b/src/sql/engine/dml/ob_trigger_handler.cpp @@ -406,6 +406,8 @@ int TriggerHandle::calc_trigger_routine( OZ (exec_ctx.get_pl_engine()->execute( exec_ctx, exec_ctx.get_allocator(), trigger_id, routine_id, path, params, nocopy_params, result), trigger_id, routine_id, params); + CK (OB_NOT_NULL(exec_ctx.get_my_session())); + OZ (exec_ctx.get_my_session()->reset_all_package_state_by_dbms_session(true)); return ret; } diff --git a/src/sql/ob_result_set.cpp b/src/sql/ob_result_set.cpp index d9515a6db..0ad8db4fe 100644 --- a/src/sql/ob_result_set.cpp +++ b/src/sql/ob_result_set.cpp @@ -882,6 +882,15 @@ int ObResultSet::close() } ret = auto_end_plan_trans(*physical_plan_, ret, async); } + + if (is_user_sql_ && my_session_.need_reset_package()) { + // need_reset_package is set, it must be reset package, wether exec succ or not. + int tmp_ret = my_session_.reset_all_package_state_by_dbms_session(true); + if (OB_SUCCESS != tmp_ret) { + LOG_WARN("reset all package fail. ", K(tmp_ret), K(ret)); + ret = OB_SUCCESS == ret ? tmp_ret : ret; + } + } //NG_TRACE_EXT(result_set_close, OB_ID(ret), ret, OB_ID(arg1), prev_ret, //OB_ID(arg2), ins_ret, OB_ID(arg3), errcode_, OB_ID(async), async); return ret; // 后面所有的操作都通过callback来完成 @@ -1160,22 +1169,6 @@ bool ObResultSet::need_end_trans_callback() const return need; } -static int check_is_pl_jsontype(const oceanbase::pl::ObUserDefinedType *user_type) -{ - INIT_SUCC(ret); - - if (OB_ISNULL(user_type)) { - } else if (user_type->get_type() == oceanbase::pl::PL_OPAQUE_TYPE) { - if (user_type->get_name().compare("JSON_OBJECT_T") == 0 - || user_type->get_name().compare("JSON_ELEMENT_T") == 0) { - ret = OB_ERR_PL_JSONTYPE_USAGE; - LOG_WARN("invalid pl json type userage in pl/sql", K(ret), - K(user_type->get_type()), K(user_type->get_user_type_id())); - } - } - return ret; -} - int ObResultSet::ExternalRetrieveInfo::build_into_exprs( ObStmt &stmt, pl::ObPLBlockNS *ns, bool is_dynamic_sql) { @@ -1187,56 +1180,13 @@ int ObResultSet::ExternalRetrieveInfo::build_into_exprs( } is_select_for_update_ = (static_cast(stmt)).has_for_update(); has_hidden_rowid_ = (static_cast(stmt)).has_hidden_rowid(); + is_bulk_ = (static_cast(stmt)).is_bulk(); } else if (stmt.is_insert_stmt() || stmt.is_update_stmt() || stmt.is_delete_stmt()) { ObDelUpdStmt &dml_stmt = static_cast(stmt); OZ (into_exprs_.assign(dml_stmt.get_returning_into_exprs())); + is_bulk_ = (static_cast(stmt)).is_bulk(); } - bool need_check = !into_exprs_.empty() && !is_dynamic_sql; - if (OB_SUCC(ret) && need_check) { - ObArray basic_types; - ObBitSet<> basic_into; - for (int64_t i = 0; OB_SUCC(ret) && i < into_exprs_.count(); ++i) { - ObRawExpr *expr = into_exprs_.at(i); - CK (OB_NOT_NULL(expr)); - CK (expr->get_result_type().is_valid()); - if (OB_SUCC(ret)) { - pl::ObPLDataType final_type; - // T_OBJ_ACCESS_REF expr, access obj type (not user defined type) - bool access_obj_type = false; - if (expr->is_obj_access_expr()) { - // T_OBJ_ACCESS_REF return ObExtendType for object access for writing, get obj type - // from %final_type; - // see comment in ObPLInto::add_into - const auto &access_expr = static_cast(*expr); - OZ(access_expr.get_final_type(final_type)); - OX(access_obj_type = !final_type.is_user_type()); - } - if (OB_FAIL(ret)) { - } else if (expr->get_result_type().is_ext() && !access_obj_type) { - CK (expr->is_obj_access_expr()); - if (OB_SUCC(ret) && NULL != ns) { - const pl::ObUserDefinedType *user_type = NULL; - OZ (ns->get_pl_data_type_by_id(final_type.get_user_type_id(), user_type)); - OZ (ns->expand_data_type(user_type, basic_types)); - OZ (check_is_pl_jsontype(user_type)); - } - } else { - ObDataType type; - if (access_obj_type) { - type.set_meta_type(final_type.get_data_type()->get_meta_type()); - type.set_accuracy(final_type.get_data_type()->get_accuracy()); - } else { - type.set_meta_type(expr->get_result_type().get_obj_meta()); - type.set_accuracy(expr->get_result_type().get_accuracy()); - } - OZ (basic_types.push_back(type)); - OZ (basic_into.add_member(basic_types.count() - 1)); - } - } - } - OZ (check_into_exprs(stmt, basic_types, basic_into)); - } return ret; } diff --git a/src/sql/ob_result_set.h b/src/sql/ob_result_set.h index 6f57551a6..f02c796da 100644 --- a/src/sql/ob_result_set.h +++ b/src/sql/ob_result_set.h @@ -73,7 +73,8 @@ public: route_sql_(), is_select_for_update_(false), has_hidden_rowid_(false), - stmt_sql_() {} + stmt_sql_(), + is_bulk_(false) {} virtual ~ExternalRetrieveInfo() {} int build(ObStmt &stmt, @@ -94,6 +95,7 @@ public: bool is_select_for_update_; bool has_hidden_rowid_; ObString stmt_sql_; + bool is_bulk_; }; enum PsMode @@ -164,6 +166,7 @@ public: ObString &get_stmt_sql(); bool get_is_select_for_update(); inline bool has_hidden_rowid(); + inline bool is_bulk(); /// whether the result is with rows (true for SELECT statement) bool is_with_rows() const; // tell mysql if need to do async end trans @@ -621,6 +624,11 @@ inline bool ObResultSet::has_hidden_rowid() return external_retrieve_info_.has_hidden_rowid_; } +inline bool ObResultSet::is_bulk() +{ + return external_retrieve_info_.is_bulk_; +} + inline bool ObResultSet::is_with_rows() const { return (p_field_columns_->count() > 0 && !is_prepare_stmt()); diff --git a/src/sql/ob_spi.cpp b/src/sql/ob_spi.cpp index 44f867c09..7e4c9cc98 100644 --- a/src/sql/ob_spi.cpp +++ b/src/sql/ob_spi.cpp @@ -968,10 +968,58 @@ int ObSPIService::spi_calc_package_expr(ObPLExecCtx *ctx, return ret; } +int ObSPIService::check_and_deep_copy_result(ObIAllocator &alloc, + const ObObj &src, + ObObj &dst) +{ + int ret = OB_SUCCESS; + + if (dst.is_pl_extend()) { + if (!src.is_pl_extend()) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(ret)); + } else if (PL_CURSOR_TYPE == src.get_meta().get_extend_type() || + PL_REF_CURSOR_TYPE == src.get_meta().get_extend_type() || + PL_OPAQUE_TYPE == src.get_meta().get_extend_type()) { + OZ (ObUserDefinedType::deep_copy_obj(alloc, src, dst, true)); + } else { + ObPLComposite *composite = reinterpret_cast(dst.get_ext()); + if (NULL == composite) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", KPC(composite), K(ret)); + } else { + if (OB_SUCC(ret)) { + ObPLComposite *src_composite = reinterpret_cast(src.get_ext()); + if (NULL == src_composite || src_composite->get_type() != composite->get_type()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", KPC(src_composite), K(ret)); + } else if (OB_INVALID_ID == src_composite->get_id() || OB_INVALID_ID == composite->get_id()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", K(src_composite->get_id()), K(composite->get_id()), K(ret)); + } else if (src_composite->get_id() != composite->get_id()) { + ret = OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("src id is not same as dst id", K(src_composite->get_id()), K(composite->get_id()), K(ret)); + } else { + OZ (pl::ObUserDefinedType::deep_copy_obj(alloc, src, dst)); + } + } + } + } + } else if (src.is_pl_extend()) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(ret)); + } else { + OZ (deep_copy_obj(alloc, src, dst)); + } + + return ret; +} + int ObSPIService::spi_set_package_variable( ObExecContext *exec_ctx, ObPLPackageGuard *guard, - uint64_t package_id, int64_t var_idx, const ObObj &value) + uint64_t package_id, int64_t var_idx, const ObObj &value, + ObIAllocator *allocator, bool need_deep_copy) { int ret = OB_SUCCESS; ObPL *pl_engine = NULL; @@ -983,6 +1031,7 @@ int ObSPIService::spi_set_package_variable( CK (OB_NOT_NULL(sql_proxy = exec_ctx->get_sql_proxy())); CK (OB_NOT_NULL(pl_engine = session_info->get_pl_engine())); if (OB_SUCC(ret)) { + ObObj result = *const_cast(&value); ObPLPackageManager &pl_manager = pl_engine->get_package_manager(); share::schema::ObSchemaGetterGuard schema_guard; ObPLPackageGuard package_guard(session_info->get_effective_tenant_id()); @@ -995,26 +1044,39 @@ int ObSPIService::spi_set_package_variable( OZ (GCTX.schema_service_->get_tenant_schema_guard( session_info->get_effective_tenant_id(), schema_guard)); OZ (package_guard.init()); + if (need_deep_copy) { + CK (OB_NOT_NULL(allocator)); + OZ (pl_manager.get_package_var_val( + resolve_ctx, *exec_ctx, package_id, OB_INVALID_VERSION, OB_INVALID_VERSION, var_idx, result), + K(package_id), K(var_idx)); + OZ (check_and_deep_copy_result(*allocator, value, result)); + } OZ (pl_manager.set_package_var_val( - resolve_ctx, *exec_ctx, package_id, var_idx, value), + resolve_ctx, *exec_ctx, package_id, var_idx, result), K(package_id), K(var_idx)); } return ret; } int ObSPIService::spi_set_package_variable( - ObPLExecCtx *ctx, uint64_t package_id, int64_t var_idx, const ObObj &value) + ObPLExecCtx *ctx, uint64_t package_id, int64_t var_idx, const ObObj &value, + bool need_deep_copy) { int ret = OB_SUCCESS; + ObIAllocator *allocator = NULL; + if (need_deep_copy) { + OZ (spi_get_package_allocator(ctx, package_id, allocator)); + } OZ (spi_set_package_variable( - ctx->exec_ctx_, ctx->guard_, package_id, var_idx, value)); + ctx->exec_ctx_, ctx->guard_, package_id, var_idx, value, allocator, need_deep_copy)); return ret; } int ObSPIService::spi_set_variable(ObPLExecCtx *ctx, const ObSqlExpression* expr, const ObObjParam *value, - bool is_default) + bool is_default, + bool need_copy) { int ret = OB_SUCCESS; if (OB_ISNULL(ctx) || OB_ISNULL(expr) || OB_ISNULL(value)) { @@ -1049,19 +1111,26 @@ int ObSPIService::spi_set_variable(ObPLExecCtx *ctx, ctx, expr->get_expr_items().at(1).get_obj().get_uint64(), // pkg id expr->get_expr_items().at(2).get_obj().get_int(), // var idx - *value)); // value + *value, // value + need_copy)); } else if (T_OP_GET_SUBPROGRAM_VAR == expr_type) { ObSQLSessionInfo *session_info = NULL; uint64_t package_id = OB_INVALID_ID; uint64_t routine_id = OB_INVALID_ID; int64_t var_idx = OB_INVALID_INDEX; + ObPLExecState *state = NULL; + ObObjParam result = *const_cast(value); CK (OB_NOT_NULL(ctx->exec_ctx_)); CK (OB_NOT_NULL(session_info = ctx->exec_ctx_->get_my_session())); OX (package_id = expr->get_expr_items().at(1).get_obj().get_uint64()); OX (routine_id = expr->get_expr_items().at(2).get_obj().get_uint64()); OX (var_idx = expr->get_expr_items().at(3).get_obj().get_int()); - OZ (ObPLContext::set_subprogram_var_from_local( - *session_info, package_id, routine_id, var_idx, *value)); + OZ (ObPLContext::get_exec_state_from_local(*session_info, package_id, routine_id, state)); + if (need_copy) { + OZ (state->get_var(var_idx, result)); + OZ (check_and_deep_copy_result(*ctx->allocator_, *value, result)); + } + OZ (state->set_var(var_idx, result)); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid sys func", K(expr_type), K(ret)); @@ -1334,6 +1403,7 @@ int ObSPIService::spi_inner_execute(ObPLExecCtx *ctx, const int64_t *pl_integer_ranges, int64_t is_bulk, bool is_forall, + bool is_type_record, bool for_update) { int ret = OB_SUCCESS; @@ -1439,7 +1509,15 @@ int ObSPIService::spi_inner_execute(ObPLExecCtx *ctx, NULL, row_count, is_bulk, - is_forall))) { + is_forall, + false, + NULL, + false, + false, + INT64_MAX, + NULL, + 0, + is_type_record))) { LOG_WARN("failed to execute inner_fetch for pl/sql", K(ret), K(ps_sql), K(sql), K(type)); } else if (out_params.has_out_param()) { OZ (process_function_out_result( @@ -1800,6 +1878,7 @@ int ObSPIService::spi_query(ObPLExecCtx *ctx, const bool *exprs_not_null_flag, const int64_t *pl_integer_ranges, bool is_bulk, + bool is_type_record, bool for_update) { int ret = OB_SUCCESS; @@ -1808,7 +1887,7 @@ int ObSPIService::spi_query(ObPLExecCtx *ctx, into_exprs, into_count, column_types, type_count, exprs_not_null_flag, - pl_integer_ranges, is_bulk, false, for_update), + pl_integer_ranges, is_bulk, false, is_type_record, for_update), sql, type); return ret; } @@ -1826,13 +1905,15 @@ int ObSPIService::spi_execute(ObPLExecCtx *ctx, const int64_t *pl_integer_ranges, bool is_bulk, bool is_forall, + bool is_type_record, bool for_update) { int ret = OB_SUCCESS; FLTSpanGuard(pl_spi_execute); OZ (spi_inner_execute(ctx, NULL, ps_sql, type, param_exprs, param_count, into_exprs, into_count, column_types, type_count, - exprs_not_null_flag, pl_integer_ranges, is_bulk, is_forall, for_update)); + exprs_not_null_flag, pl_integer_ranges, is_bulk, + is_forall, is_type_record, for_update)); return ret; } @@ -1909,6 +1990,7 @@ int ObSPIService::spi_parse_prepare(common::ObIAllocator &allocator, prepare_result.type_ = pl_prepare_result.result_set_->get_stmt_type(); prepare_result.for_update_ = pl_prepare_result.result_set_->get_is_select_for_update(); prepare_result.has_hidden_rowid_ = false; + prepare_result.is_bulk_ = false; if (OB_FAIL(ret)) { } else if (OB_FAIL(resolve_exec_params(parse_result, session, @@ -1963,6 +2045,7 @@ int ObSPIService::spi_build_record_type(common::ObIAllocator &allocator, OZ (secondary_namespace->get_pl_data_type_by_id(udt_id, user_type)); CK (OB_NOT_NULL(user_type)); OX (pl_type.set_user_type_id(user_type->get_type(), udt_id)); + OX (pl_type.set_type_from(user_type->get_type_from())); } else { ObDataType data_type; data_type.set_meta_type(columns->at(i).type_.get_meta()); @@ -2043,6 +2126,7 @@ int ObSPIService::spi_resolve_prepare(common::ObIAllocator &allocator, prepare_result.type_ = pl_prepare_result.result_set_->get_stmt_type(); prepare_result.for_update_ = pl_prepare_result.result_set_->get_is_select_for_update(); prepare_result.has_hidden_rowid_ = pl_prepare_result.result_set_->has_hidden_rowid(); + prepare_result.is_bulk_ = pl_prepare_result.result_set_->is_bulk(); if (OB_FAIL(ret)) { } else if (OB_NOT_NULL(prepare_result.record_type_)) { if (stmt::T_SELECT != prepare_result.type_) { @@ -2373,7 +2457,8 @@ int ObSPIService::spi_execute_immediate(ObPLExecCtx *ctx, const bool *exprs_not_null_flag, const int64_t *pl_integer_ranges, bool is_bulk, - bool is_returning) + bool is_returning, + bool is_type_record) { int ret = OB_SUCCESS; // HEAP_VAR(char[OB_MAX_SQL_LENGTH], sql_buffer) { @@ -2474,7 +2559,24 @@ int ObSPIService::spi_execute_immediate(ObPLExecCtx *ctx, ret = OB_ERR_INOUT_PARAM_PLACEMENT_NOT_PROPERLY; LOG_WARN("using out/inout param mode is not allowed", K(ret)); } + if (OB_SUCC(ret) && ObStmt::is_dml_stmt(stmt_type)) { + if (PL_PARAM_IN == pm && + NULL != params[i] && + params[i]->is_pl_extend() && + PL_RECORD_TYPE == params[i]->get_meta().get_extend_type()) { + const ObUserDefinedType *user_type = NULL; + ObPLComposite *composite = reinterpret_cast(params[i]->get_ext()); + CK (OB_NOT_NULL(composite)); + OZ (ctx->get_user_type(composite->get_id(), user_type)); + CK (OB_NOT_NULL(user_type)); + if (OB_SUCC(ret) && user_type->is_type_record()) { + ret = OB_ERR_EXPR_SQL_TYPE; + LOG_WARN("expressions have to be of SQL types", K(ret)); + } + } + } } + if (OB_SUCC(ret)) { ObParser parser(*ctx->allocator_, STD_MODE); ObMPParseStat parse_stat; @@ -2585,7 +2687,14 @@ int ObSPIService::spi_execute_immediate(ObPLExecCtx *ctx, row_count, is_bulk, false, - true/*is_dynamic_sql*/)); + true/*is_dynamic_sql*/, + NULL, + false, + false, + INT64_MAX, + NULL, + 0, + is_type_record)); //此处仅需要处理非DML RETURNING返回的USING OUT参数 OZ (dynamic_out_params( @@ -2810,8 +2919,20 @@ int ObSPIService::cursor_open_check(ObPLExecCtx *ctx, if (OB_SUCC(ret)) { // 理论上reopen的时候, cg openfor 的时候,已经close了,保险起见,这儿再close一次 // OZ (cursor_close_impl(ctx, cursor, true, OB_INVALID_ID, OB_INVALID_ID, true)); + /* OB cursor close 逻辑 + * 1. 释放数据部分(spi_result/spi_cursor), 其余部分做 reset + * 2. 尽管 cursor 做了 close, obj.get_ext 的结果仍然是原来 cursor 的地址 + * OB cursor reopen 逻辑 (不包含 ps cursor) + * 1. spi_open_cursor 时,会判断一下 obj.get_ext 的结果是不是空 + * a. 为空,说明第一次 open , 直接分配内存即可 + * b. 不为空,说明是 reopen,一般不需要重新分配内存 + * 2. reopen 时需要重新设置 session_cursor, session_cursor 内存分配位置有别于 local_cursor, 所以这个标记需要设置 + * a. 此时不需要重新 make_cursor , 内存已经分配过了, cursor_close_impl 里的 close 并没有把 cursor 从 session 上摘掉 + * b. 这个值以前没有设置成功为什么也没有出问题? 因为 spi 中 server cursor 的判断都是使用 cursor_id 做判断 + * server cursor 的 close 全部都使用 reuse, cursor_id 不会被 清空, 所以暂时没有出现问题 + */ if (cursor->is_session_cursor()) { - OZ (session->make_cursor(cursor)); + //OZ (session->make_cursor(cursor)); OX (cursor->set_is_session_cursor()); } else { // local ref cursor, just reset @@ -3363,14 +3484,17 @@ int ObSPIService::spi_cursor_open(ObPLExecCtx *ctx, OZ (cursor->prepare_spi_cursor(spi_cursor, session_info->get_effective_tenant_id(), size), K(size)); - if (is_server_cursor) { + //if (is_server_cursor) { + // not only server cursor need field set + // normal cursor maybe convert to session cursor by to_cursor_number + // so all kind of cursor need do the copy CK (OB_NOT_NULL(cursor->get_allocator())); CK (OB_NOT_NULL(spi_result.get_result_set())); OZ (ObDbmsInfo::deep_copy_field_columns( *cursor->get_allocator(), spi_result.get_result_set()->get_field_columns(), spi_cursor->fields_)); - } + //} OZ (fill_cursor(*spi_result.get_result_set(), spi_cursor)); OX (spi_cursor->row_store_.finish_add_row()) OX (cursor->open(spi_cursor)); @@ -3721,7 +3845,8 @@ int ObSPIService::do_cursor_fetch(ObPLExecCtx *ctx, bool is_bulk, int64_t limit, const ObDataType *return_types, - int64_t return_type_count) + int64_t return_type_count, + bool is_type_record) { int ret = OB_SUCCESS; ObSPIResultSet *spi_result = NULL; @@ -3832,7 +3957,8 @@ int ObSPIService::do_cursor_fetch(ObPLExecCtx *ctx, false, \ limit, \ return_types, \ - return_type_count); \ + return_type_count, \ + is_type_record); \ } else { \ ret = inner_fetch_with_retry(ctx, \ *cursor->get_cursor_handler(), \ @@ -3850,7 +3976,8 @@ int ObSPIService::do_cursor_fetch(ObPLExecCtx *ctx, limit, \ cursor->get_last_execute_time(), \ return_types, \ - return_type_count); \ + return_type_count, \ + is_type_record); \ } \ } while(0) @@ -3950,7 +4077,8 @@ int ObSPIService::spi_cursor_fetch(ObPLExecCtx *ctx, bool is_bulk, int64_t limit, const ObDataType *return_types, - int64_t return_type_count) + int64_t return_type_count, + bool is_type_record) { int ret = OB_SUCCESS; ObPLCursorInfo *cursor = NULL; @@ -3961,6 +4089,7 @@ int ObSPIService::spi_cursor_fetch(ObPLExecCtx *ctx, ret = OB_ERR_INVALID_CURSOR; LOG_WARN("ref cursor is null", K(ret)); } + OV (!cursor->is_invalid_cursor(), OB_ERR_INVALID_CURSOR); OZ (do_cursor_fetch(ctx, cursor, OB_INVALID_ID != cursor->get_id() @@ -3974,7 +4103,8 @@ int ObSPIService::spi_cursor_fetch(ObPLExecCtx *ctx, is_bulk, limit, return_types, - return_type_count)); + return_type_count, + is_type_record)); if (OB_FAIL(ret) && lib::is_mysql_mode()) { ctx->exec_ctx_->get_my_session()->set_show_warnings_buf(ret); @@ -4041,6 +4171,7 @@ int ObSPIService::spi_cursor_close(ObPLExecCtx *ctx, CK (OB_NOT_NULL(ctx->params_)); OZ (spi_get_cursor_info(ctx, package_id, routine_id, cursor_index, cursor, cur_var, loc), package_id, routine_id, cursor_index, cur_var); + OV (ignore ? true : NULL != cursor ? !cursor->is_invalid_cursor() : true, OB_ERR_INVALID_CURSOR); OZ (cursor_close_impl(ctx, cursor, cur_var.is_ref_cursor_type(), package_id, routine_id, ignore)); if (OB_SUCC(ret) && DECL_PKG == loc) { @@ -5254,7 +5385,8 @@ int ObSPIService::inner_fetch(ObPLExecCtx *ctx, bool for_cursor, int64_t limit, const ObDataType *return_types, - int64_t return_type_count) + int64_t return_type_count, + bool is_type_record) { int ret = OB_SUCCESS; ObResultSet *result_set = spi_result.get_result_set(); @@ -5287,7 +5419,8 @@ int ObSPIService::inner_fetch(ObPLExecCtx *ctx, is_forall, limit, return_types, - return_type_count)))) { + return_type_count, + is_type_record)))) { if (can_retry) { int cli_ret = OB_SUCCESS; retry_ctrl.test_and_save_retry_state( @@ -5324,7 +5457,8 @@ int ObSPIService::inner_fetch_with_retry(ObPLExecCtx *ctx, int64_t limit, int64_t last_exec_time, const ObDataType *return_types, - int64_t return_type_count) + int64_t return_type_count, + bool is_type_record) { int ret = OB_SUCCESS; ObQueryRetryCtrl retry_ctrl; @@ -5391,7 +5525,8 @@ int ObSPIService::inner_fetch_with_retry(ObPLExecCtx *ctx, for_cursor, limit, return_types, - return_type_count); + return_type_count, + is_type_record); } // NOTE: cursor fetch failed can not retry, we only use this to refresh location cache. } while (RETRY_TYPE_NONE != retry_ctrl.get_retry_type() && !for_cursor); @@ -5403,54 +5538,109 @@ int ObSPIService::inner_fetch_with_retry(ObPLExecCtx *ctx, return ret; } -#define STORE_INTO_RESULT(singal_value) \ - ObCastCtx cast_ctx(allocator, &dtc_params, cast_mode, cast_coll_type); \ - if (into_count > 1) { /* 多个variables, 每个都是基础变量 */ \ - CK(return_types != nullptr ? return_type_count == into_count : true); \ - ObSEArray tmp_result; \ - ObSEArray tmp_desc; \ - for (int64_t i = 0; OB_SUCC(ret) && i < actual_column_count; ++i) { \ - tmp_result.reuse(); \ - tmp_desc.reuse(); \ - OZ (tmp_result.push_back(singal_value)); \ - OZ (tmp_desc.push_back(row_desc.at(i))); \ - OZ (store_result(ctx, into_exprs[i], &column_types[i], \ - 1, exprs_not_null + i, pl_integer_ranges + i, \ - tmp_desc, is_strict, \ - cast_ctx, tmp_result, \ - return_types != nullptr ? &return_types[i] : nullptr, \ - return_types != nullptr ? 1 : 0)); \ - } \ - } else { /* 单个record或单个variable */ \ - ObSEArray tmp_result; \ - int i = 0; \ - ObObj tmp = singal_value; \ - if (!(tmp.is_pl_extend() && pl::PL_RECORD_TYPE == tmp.get_meta().get_extend_type())) { \ - for (int64_t i = 0; OB_SUCC(ret) && i < actual_column_count; ++i) { \ - OZ (tmp_result.push_back(singal_value)); \ - } \ - } else { \ - /*查询返回的结果列是Record的场景, 将Record展开*/ \ - ObPLRecord* record = reinterpret_cast(tmp.get_ext()); \ - ObObj *values = NULL; \ - CK (OB_NOT_NULL(record)); \ - CK (OB_NOT_NULL(values = record->get_element())); \ - for (int64_t i = 0; OB_SUCC(ret) && i < record->get_count(); ++i) { \ - ObObj deep_copy; \ - /*may element of record also complex value*/ \ - if (values[i].is_pl_extend()) { \ - OZ (pl::ObUserDefinedType::deep_copy_obj(*cast_ctx.allocator_v2_, values[i], deep_copy)); \ - } else { \ - OZ (deep_copy_obj(*cast_ctx.allocator_v2_, values[i], deep_copy)); \ - } \ - OZ (tmp_result.push_back(deep_copy)); \ - } \ - } \ - OZ (store_result(ctx, into_exprs[0], column_types, \ - type_count, exprs_not_null, pl_integer_ranges, \ - row_desc, is_strict, \ - cast_ctx, tmp_result, return_types, return_type_count)); \ +int ObSPIService::store_into_result(ObPLExecCtx *ctx, + ObCastCtx &cast_ctx, + ObNewRow &cur_row, + const ObSqlExpression **into_exprs, + const ObDataType *column_types, + int64_t type_count, + int64_t into_count, + const bool *exprs_not_null, + const int64_t *pl_integer_ranges, + const ObDataType *return_types, + int64_t return_type_count, + int64_t actual_column_count, + ObIArray &row_desc, + bool is_type_record) +{ + int ret = OB_SUCCESS; + ObExecContext *exec_ctx = ctx->exec_ctx_; + bool is_strict = false; + bool is_null_row = 0 == cur_row.get_count(); + CK (OB_NOT_NULL(exec_ctx), OB_NOT_NULL(exec_ctx->get_my_session())); + CK (is_null_row ? true : (actual_column_count <= cur_row.get_count())); + OX (is_strict = is_strict_mode(exec_ctx->get_my_session()->get_sql_mode())); + + /* 如果into variable只有一个: + 1.是基础类型变量 + 2.create or replace type定义的udt变量 + 3.type定义的record + 2和3都是record类型 + 如果into variable有多个,为上述1和2的组合。 + 对于record变量,目前的行为是展开后获取内部的元素值,然后依次赋值而非深拷后整体赋值 + 如果record内部元素是object, object的赋值动作需要深拷吗 + 对于顶层record,基础类型属性,需要考虑强转, + 复杂数据类型属性在resolve阶段严格限制,执行期不做强转逻辑,只考虑赋值 + 按照这个逻辑,复杂数据类型没有expand的必要,也无需传递到执行期做类型转换 + */ + if (into_count > 1) { + ObSEArray tmp_result; + ObSEArray tmp_desc; + CK (into_count == actual_column_count); + CK(return_types != nullptr ? return_type_count == into_count : true); + for (int64_t i = 0; OB_SUCC(ret) && i < actual_column_count; ++i) { + //循环处理多个into变量的赋值,每个变量赋值需要检测是否需要强转,然后用强转后的obj赋值 + tmp_result.reuse(); + tmp_desc.reuse(); + if (is_null_row) { + OZ (tmp_result.push_back(ObObj(ObNullType))); + } else { + OZ (tmp_result.push_back(cur_row.get_cell(i))); + } + OZ (tmp_desc.push_back(row_desc.at(i))); + OZ (store_result(ctx, into_exprs[i], &column_types[i], + 1, exprs_not_null + i, pl_integer_ranges + i, + tmp_desc, is_strict, + cast_ctx, tmp_result, + return_types != nullptr ? &return_types[i] : nullptr, + return_types != nullptr ? 1 : 0)); + } + } else if (is_type_record) { + /* into后面的是type record(作为一个整体),对应into前面的多个column value + 多个obj存到record中,实现上需要依次为对应属性赋值,需要考虑cast + into record是展开一层的,因此column_types == return_type_count == actual_column_count + 将所有column value收集起来,传递到store result中进行cast校验&赋值 + */ + ObSEArray tmp_result; + for (int64_t i = 0; OB_SUCC(ret) && i < actual_column_count; ++i) { + if (is_null_row) { + OZ (tmp_result.push_back(ObObj(ObNullType))); + } else { + OZ (tmp_result.push_back(cur_row.get_cell(i))); + } + } + OZ (store_result(ctx, into_exprs[0], column_types, + type_count, exprs_not_null, pl_integer_ranges, + row_desc, is_strict, + cast_ctx, tmp_result, return_types, return_type_count, + true)); + } else { + /* + into后面是udt record, 视为单个variable个体,对应into前面单个column value + 本身是一个obj存到record中,当前的实现时,将record对应的obj拆开成多个obj,然后存到record中, + 代码逻辑上可以复用场景1. 理论上应该可以直接找到into record的地址,深拷赋值,不需要强转 + */ + CK (1 == actual_column_count); + if (OB_SUCC(ret)) { + ObSEArray tmp_result; + ObSEArray tmp_desc; + if (is_null_row) { + OZ (tmp_result.push_back(ObObj(ObNullType))); + } else { + OZ (tmp_result.push_back(cur_row.get_cell(0))); + } + OZ (tmp_desc.push_back(row_desc.at(0))); + OZ (store_result(ctx, into_exprs[0], column_types, + 1, exprs_not_null, pl_integer_ranges, + tmp_desc, is_strict, + cast_ctx, tmp_result, + return_types, + return_type_count)); + } } + return ret; +} + int ObSPIService::get_package_var_info_by_expr(const ObSqlExpression *expr, uint64_t &package_id, @@ -5504,7 +5694,8 @@ int ObSPIService::get_result(ObPLExecCtx *ctx, bool is_forall, int64_t limit, //INT64_MAX:无limit const ObDataType *return_types, - int64_t return_type_count) + int64_t return_type_count, + bool is_type_record) { int ret = OB_SUCCESS; ObIAllocator *allocator = ctx->allocator_; @@ -5671,12 +5862,29 @@ int ObSPIService::get_result(ObPLExecCtx *ctx, if (for_dbms_sql) { //DBMS_SQL包的FETCH不需要检查 } else if (NULL != out_using_params) { + ObCastCtx cast_ctx(allocator, &dtc_params, cast_mode, cast_coll_type); + CK (actual_column_count == row_desc.count()); for (int64_t i = 0; OB_SUCC(ret) && i < actual_column_count; ++i) { - OZ (deep_copy_obj(*allocator, current_row.get_cell(i), *out_using_params->at(i))); - out_using_params->at(i)->set_param_meta(); + ObObj &obj = current_row.get_cell(i); + if (obj.is_pl_extend()) { + OZ (check_and_deep_copy_result(*allocator, obj, *out_using_params->at(i))); + } else { + ObSEArray cur_result; + ObSEArray conv_result; + ObSEArray cur_type; + OZ (cur_result.push_back(obj)); + OZ (cur_type.push_back(row_desc.at(i))); + OZ (convert_obj(ctx, cast_ctx, is_strict, NULL, cur_type, cur_result, &column_types[i], 1, conv_result)); + CK (1 == conv_result.count()); + OX (*out_using_params->at(i) = conv_result.at(0)); + OX (out_using_params->at(i)->set_param_meta()); + } } } else { - STORE_INTO_RESULT(current_row.get_cell(i)); + ObCastCtx cast_ctx(allocator, &dtc_params, cast_mode, cast_coll_type); + OZ (store_into_result(ctx, cast_ctx, current_row, into_exprs, column_types, type_count, + into_count, exprs_not_null, pl_integer_ranges, return_types, return_type_count, + actual_column_count, row_desc, is_type_record)); } if (OB_SUCC(ret) && !for_cursor) { //如果不是cursor,into只能返回一行,需要检查返回多行报错 @@ -5734,11 +5942,19 @@ int ObSPIService::get_result(ObPLExecCtx *ctx, // collection may modified by sql fetch, which can be reset and allocator will change, such like stmt a:=b in trigger // so allocator of collection can not be used by collect_cells. // CK (OB_NOT_NULL(collection_allocator = table->get_allocator())); - for (int64_t j = 0; OB_SUCC(ret) && j < table->get_column_count(); ++j) { + if (is_type_record) { + for (int64_t j = 0; OB_SUCC(ret) && j < table->get_column_count(); ++j) { + OZ (cast_ctxs.push_back(ObCastCtx(&tmp_allocator, + &dtc_params, + cast_mode, + cast_coll_type))); + } + } else { + // 对于collection内部是非record场景而言, 每个table只需要一个castctx OZ (cast_ctxs.push_back(ObCastCtx(&tmp_allocator, - &dtc_params, - cast_mode, - cast_coll_type))); + &dtc_params, + cast_mode, + cast_coll_type))); } } ObArray tmp_result; @@ -5747,7 +5963,7 @@ int ObSPIService::get_result(ObPLExecCtx *ctx, if (OB_FAIL(fetch_row(result_set, is_streaming, row_count, current_row))) { break; } - OZ (collect_cells(current_row, column_types, type_count, + OZ (collect_cells(*ctx, current_row, column_types, type_count, row_desc, is_strict, cast_ctxs, hidden_column_count, tmp_result)); } if (OB_FAIL(ret)) { @@ -5787,8 +6003,8 @@ int ObSPIService::get_result(ObPLExecCtx *ctx, } } if (OB_SUCC(ret) && row_count > 0) { // 累积存储在pl table里 - OZ (store_result(bulk_tables, row_count, type_count, tmp_result, - NULL == implicit_cursor ? false : implicit_cursor->get_in_forall())); + OZ (store_result(ctx, bulk_tables, row_count, type_count, tmp_result, + NULL == implicit_cursor ? false : implicit_cursor->get_in_forall(), is_type_record)); } // update package info for (int64_t i = 0; OB_SUCC(ret) && i < package_vars_info.count(); i++) { @@ -5814,7 +6030,11 @@ int ObSPIService::get_result(ObPLExecCtx *ctx, (result_set)->get_stmt_type())) { // dml returning with dynamic sql need set into value to null if (is_dynamic_sql && into_count > 0) { - STORE_INTO_RESULT(ObObj(ObNullType)); + ObCastCtx cast_ctx(allocator, &dtc_params, cast_mode, cast_coll_type); + ObNewRow null_row; + OZ (store_into_result(ctx, cast_ctx, null_row, into_exprs, column_types, type_count, + into_count, exprs_not_null, pl_integer_ranges, return_types, return_type_count, + actual_column_count, row_desc, is_type_record)); } } else { // not fetch into, not returning into, must be select into @@ -5890,9 +6110,9 @@ int ObSPIService::get_result(ObPLExecCtx *ctx, return ret; } -#undef STORE_INTO_RESULT -int ObSPIService::collect_cells(ObNewRow &row, +int ObSPIService::collect_cells(pl::ObPLExecCtx &ctx, + ObNewRow &row, const ObDataType *result_types, int64_t type_count, const ObIArray &row_desc, @@ -5916,7 +6136,13 @@ int ObSPIService::collect_cells(ObNewRow &row, tmp_obj.reset(); ObObj &obj = row.get_cell(i); obj.set_collation_level(result_types[i].get_collation_level()); - if (obj.get_meta() == result_types[i].get_meta_type() + if (obj.is_pl_extend()) { + // need deep copy immediately at bulk into scenes, because when fetch next row, current row will be free + OZ (ObUserDefinedType::deep_copy_obj(*cast_ctxs.at(i).allocator_v2_, obj, tmp_obj, true)); + if (OB_SUCC(ret) && obj.get_meta().get_extend_type() != PL_CURSOR_TYPE) { + OZ (ObUserDefinedType::destruct_obj(obj, ctx.exec_ctx_->get_my_session())); + } + } else if (obj.get_meta() == result_types[i].get_meta_type() && (row_desc.at(i).get_accuracy() == result_types[i].get_accuracy() || (result_types[i].get_meta_type().is_number() // NUMBER目标类型精度未知直接做赋值 && PRECISION_UNKNOWN_YET == result_types[i].get_accuracy().get_precision() @@ -6007,7 +6233,6 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, CK(OB_NOT_NULL(ctx->exec_ctx_)); CK(OB_NOT_NULL(ctx->exec_ctx_->get_my_session())); CK(OB_NOT_NULL(result_types)); - CK(OB_NOT_NULL(result_expr)); CK(current_type.count() == type_count); CK(obj_array.count() == type_count); @@ -6021,7 +6246,10 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, obj.set_collation_level(result_types[i].get_collation_level()); LOG_DEBUG("column convert", K(obj.get_meta()), K(result_types[i].get_meta_type()), K(current_type.at(i)), K(result_types[i].get_accuracy())); - if (obj.get_meta() == result_types[i].get_meta_type() + if (obj.is_pl_extend()/* && pl::PL_RECORD_TYPE == obj.get_meta().get_extend_type()*/) { + //record嵌object场景,object属性在resolver阶段要求强一致,无需强转 + OZ (calc_array.push_back(obj)); + } else if (obj.get_meta() == result_types[i].get_meta_type() && (current_type.at(i).get_accuracy() == result_types[i].get_accuracy() || (result_types[i].get_meta_type().is_number() // NUMBER目标类型精度未知直接做赋值 && PRECISION_UNKNOWN_YET == result_types[i].get_accuracy().get_precision() @@ -6044,12 +6272,18 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, if (OB_SUCC(ret)) { LOG_DEBUG("same type directyly copy", K(obj), K(tmp_obj), K(result_types[i]), K(i)); } + } else if (!obj.is_pl_extend() && result_types[i].get_meta_type().is_ext()) { + ret = OB_ERR_INTO_EXPR_ILLEGAL; + LOG_WARN("PLS-00597: expression 'string' in the INTO list is of wrong type", K(ret)); } else { LOG_DEBUG("column convert", K(i), K(obj.get_meta()), K(result_types[i].get_meta_type()), K(current_type.at(i)), K(result_types[i].get_accuracy())); const ObIArray *type_info = NULL; + // only mysql mode will run this logic if (ob_is_enum_or_set_type(result_types[i].get_obj_type())) { - if (!is_question_mark_expression(*result_expr)) { + if (OB_ISNULL(result_expr)) { + // do nothing + } else if (!is_question_mark_expression(*result_expr)) { ret = OB_NOT_SUPPORTED; LOG_WARN("only can store to local enum set variables", K(ret)); } else { @@ -6107,7 +6341,8 @@ int ObSPIService::store_result(ObPLExecCtx *ctx, ObCastCtx &cast_ctx, ObIArray &obj_array, const ObDataType *return_types, - int64_t return_type_count) + int64_t return_type_count, + bool is_type_record) { int ret = OB_SUCCESS; bool need_convert_type = true; @@ -6124,99 +6359,163 @@ int ObSPIService::store_result(ObPLExecCtx *ctx, CK(OB_NOT_NULL(not_null_flags)); CK(OB_NOT_NULL(pl_integer_ranges)); CK(!obj_array.empty()); - if (OB_SUCC(ret) && type_count != obj_array.count()) { - ret = OB_ERR_SP_INVALID_FETCH_ARG; - LOG_WARN("type count is not equal to column count", - K(obj_array.count()), K(type_count), K(ret)); - } - if (OB_SUCC(ret) - && (is_get_var_func_expression(*result_expr) - || row_desc.count() != obj_array.count())) { - need_convert_type = false; - } - // 检查not null修饰符是否生效 - for (int64_t i = 0; OB_SUCC(ret) && i < type_count; ++i) { - if (not_null_flags[i] && obj_array.at(i).is_null()) { - ret = OB_ERR_NUMERIC_OR_VALUE_ERROR; - LOG_WARN("not null check violated", - K(type_count), - K(obj_array.at(i).is_null()), - K(not_null_flags[i]), - K(i), - K(ret)); + bool is_schema_object = (!is_type_record && + 1 == type_count && + 1 == obj_array.count() && + obj_array.at(0).is_pl_extend()); + if (!is_schema_object) { + if (OB_SUCC(ret) && type_count != obj_array.count()) { + ret = OB_ERR_SP_INVALID_FETCH_ARG; + LOG_WARN("type count is not equal to column count", + K(obj_array.count()), K(type_count), K(ret)); } - } - - // 做类型转换 - if (OB_FAIL(ret)) { - } else if (return_types != nullptr && row_desc.count() == obj_array.count()) { - OZ(convert_obj(ctx, cast_ctx, is_strict, result_expr, row_desc, - obj_array, return_types, return_type_count, tmp_obj_array)); - OX(calc_array = &tmp_obj_array); - - bool is_same = true; - for (int64_t i = 0; OB_SUCC(ret) && is_same && i < type_count; ++i) { - if (!(return_types[i] == result_types[i])) { - is_same = false; + if (OB_SUCC(ret) + && (is_get_var_func_expression(*result_expr) + || row_desc.count() != obj_array.count())) { + need_convert_type = false; + } + // 检查not null修饰符是否生效 + for (int64_t i = 0; OB_SUCC(ret) && i < type_count; ++i) { + if (not_null_flags[i] && obj_array.at(i).is_null()) { + ret = OB_ERR_NUMERIC_OR_VALUE_ERROR; + LOG_WARN("not null check violated", + K(type_count), + K(obj_array.at(i).is_null()), + K(not_null_flags[i]), + K(i), + K(ret)); } } - if (OB_SUCC(ret) && !is_same && need_convert_type) { - ObSEArray current_type; - for (int i = 0; OB_SUCC(ret) && i < return_type_count; ++i) { - OZ(current_type.push_back(return_types[i])); + // 做类型转换 + if (OB_FAIL(ret)) { + } else if (return_types != nullptr && row_desc.count() == obj_array.count()) { + OZ(convert_obj(ctx, cast_ctx, is_strict, result_expr, row_desc, + obj_array, return_types, return_type_count, tmp_obj_array)); + OX(calc_array = &tmp_obj_array); + + bool is_same = true; + for (int64_t i = 0; OB_SUCC(ret) && is_same && i < type_count; ++i) { + if (!(return_types[i] == result_types[i])) { + is_same = false; + } } - OZ(convert_obj(ctx, cast_ctx, is_strict, result_expr, current_type, - tmp_obj_array, result_types, type_count, tmp_obj_array1)); - OX(calc_array = &tmp_obj_array1); + if (OB_SUCC(ret) && !is_same && need_convert_type) { + ObSEArray current_type; + for (int i = 0; OB_SUCC(ret) && i < return_type_count; ++i) { + OZ(current_type.push_back(return_types[i])); + } + + OZ(convert_obj(ctx, cast_ctx, is_strict, result_expr, current_type, + tmp_obj_array, result_types, type_count, tmp_obj_array1)); + OX(calc_array = &tmp_obj_array1); + } + } else if (need_convert_type) { + OZ(convert_obj(ctx, cast_ctx, is_strict, result_expr, row_desc, + obj_array, result_types, type_count, tmp_obj_array)); + OX(calc_array = &tmp_obj_array); + } + // check range + for (int64_t i = 0; OB_SUCC(ret) && i < calc_array->count(); ++i) { + OZ (sql::ObExprPLIntegerChecker::check_range(calc_array->at(i), + calc_array->at(i).get_type(), pl_integer_ranges[i])); } - } else if (need_convert_type) { - OZ(convert_obj(ctx, cast_ctx, is_strict, result_expr, row_desc, - obj_array, result_types, type_count, tmp_obj_array)); - OX(calc_array = &tmp_obj_array); - } - // check range - for (int64_t i = 0; OB_SUCC(ret) && i < calc_array->count(); ++i) { - OZ (sql::ObExprPLIntegerChecker::check_range(calc_array->at(i), - calc_array->at(i).get_type(), pl_integer_ranges[i])); } // 向变量赋值 if (OB_SUCC(ret)) { ParamStore *params = ctx->params_; ObObjParam result_address; if (is_obj_access_expression(*result_expr)) { //通过ObjAccess访问得到的基础变量或record - ObSEArray dst_array; + ObIAllocator *pkg_allocator = NULL; OZ (spi_calc_expr(ctx, result_expr, OB_INVALID_INDEX, &result_address)); - OZ (check_package_dest_and_deep_copy(*ctx, *result_expr, *calc_array, dst_array)); - OZ (store_datums(result_address, dst_array)); + if (OB_SUCC(ret)) { + if (result_expr->get_expr_items().count() > 1 + && T_OP_GET_PACKAGE_VAR == result_expr->get_expr_items().at(1).get_item_type() + && OB_NOT_NULL(result_expr->get_expr_items().at(1).get_expr_operator()) + && result_expr->get_expr_items().at(1).get_expr_operator()->get_result_type().is_ext()) { + uint16_t param_pos = result_expr->get_expr_items().at(1).get_param_idx(); + uint64_t package_id = OB_INVALID_ID; + OX (package_id = result_expr->get_expr_items().at(param_pos).get_obj().get_uint64()); + OZ (spi_get_package_allocator(ctx, package_id, pkg_allocator)); + CK (OB_NOT_NULL(pkg_allocator)); + } + ObIAllocator *alloc = NULL != pkg_allocator ? pkg_allocator : cast_ctx.allocator_v2_; + CK (OB_NOT_NULL(alloc)); + // udt会在store datums深拷 + if (OB_SUCC(ret) && !is_schema_object) { + for (int64_t i = 0; OB_SUCC(ret) && i < calc_array->count(); ++i) { + ObObj tmp; + if (calc_array->at(i).is_pl_extend()) { + pl::ObUserDefinedType::deep_copy_obj(*alloc, calc_array->at(i), tmp); + } else { + OZ (ob_write_obj(*alloc, calc_array->at(i), tmp)); + } + OX (calc_array->at(i) = tmp); + } + } + OZ (store_datums(result_address, *calc_array, alloc, is_schema_object)); + } } else if (is_question_mark_expression(*result_expr)) { //通过question mark访问得到的基础变量 int64_t param_idx = get_const_value(*result_expr).get_unknown(); ObAccuracy accuracy; if (param_idx >= params->count() || param_idx < 0) { ret = OB_ARRAY_OUT_OF_RANGE; LOG_WARN("param idx out of range", K(ret), K(param_idx), K(params->count())); + } else { + if (params->at(param_idx).is_pl_extend() + && params->at(param_idx).get_ext() != 0 + && params->at(param_idx).get_ext() != calc_array->at(0).get_ext()) { + OZ (ObUserDefinedType::destruct_obj(params->at(param_idx), ctx->exec_ctx_->get_my_session())); + } + ObObj result; + const ObPLDataType &var_type = ctx->func_->get_variables().at(param_idx); + if (OB_FAIL(ret)) { + } else if (!var_type.is_obj_type() || + (var_type.get_data_type() != NULL && var_type.get_data_type()->get_meta_type().is_ext())) { + uint64_t dst_id = OB_INVALID_INDEX; + if (!calc_array->at(0).is_pl_extend()) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(ret)); + } else if (PL_CURSOR_TYPE == calc_array->at(0).get_meta().get_extend_type() || + PL_REF_CURSOR_TYPE == calc_array->at(0).get_meta().get_extend_type() || + PL_OPAQUE_TYPE == calc_array->at(0).get_meta().get_extend_type()) { + OZ (ObUserDefinedType::deep_copy_obj(*cast_ctx.allocator_v2_, calc_array->at(0), result, true)); + } else { + dst_id = var_type.get_user_type_id(); + ObPLComposite *composite = reinterpret_cast(calc_array->at(0).get_ext()); + if (NULL == composite) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", KPC(composite), K(ret)); + } else if (OB_INVALID_ID == dst_id || OB_INVALID_ID == composite->get_id()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", K(dst_id), K(composite->get_id()), K(ret)); + } else if (dst_id != composite->get_id()) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(dst_id), K(composite->get_id()), K(ret)); + } else { + OZ (pl::ObUserDefinedType::deep_copy_obj(*cast_ctx.allocator_v2_, calc_array->at(0), result)); + } + } + } else { + OZ (deep_copy_obj(*cast_ctx.allocator_v2_, calc_array->at(0), result)); + } + OX (params->at(param_idx) = result); + OX (params->at(param_idx).set_param_meta()); + OZ (spi_process_nocopy_params(ctx, param_idx)); + OX (accuracy.set_accuracy(result_types[0].accuracy_)); + OX (params->at(param_idx).set_accuracy(accuracy)); + OZ (spi_pad_char_or_varchar(ctx->exec_ctx_->get_my_session(), result_types[0].get_obj_type(), + accuracy, ctx->allocator_, &(params->at(param_idx)))); } - if (OB_SUCC(ret) - && params->at(param_idx).is_pl_extend() - && params->at(param_idx).get_ext() != 0 - && params->at(param_idx).get_ext() != calc_array->at(0).get_ext()) { - OZ (ObUserDefinedType::destruct_obj(params->at(param_idx), ctx->exec_ctx_->get_my_session())); - } - OX (params->at(param_idx) = calc_array->at(0)); - OX (params->at(param_idx).set_param_meta()); - OZ (spi_process_nocopy_params(ctx, param_idx)); - OX (accuracy.set_accuracy(result_types[0].accuracy_)); - OX (params->at(param_idx).set_accuracy(accuracy)); - OZ (spi_pad_char_or_varchar(ctx->exec_ctx_->get_my_session(), result_types[0].get_obj_type(), - accuracy, ctx->allocator_, &(params->at(param_idx)))); } else if (is_get_var_func_expression(*result_expr) || is_get_package_or_subprogram_var_expression(*result_expr)) { //通过系统函数访问的基础变量(user var/sys var) 或 访问的package/subprogram 变量 ObObjParam value; OX (value = calc_array->at(0)); + CK (!value.is_pl_extend()); OX (value.set_param_meta()); - OZ (spi_set_variable(ctx, static_cast(result_expr), &value)); + OZ (spi_set_variable(ctx, static_cast(result_expr), &value, false, true)); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid result address", @@ -6226,14 +6525,19 @@ int ObSPIService::store_result(ObPLExecCtx *ctx, return ret; } -int ObSPIService::store_result(ObIArray &bulk_tables, +int ObSPIService::store_result(ObPLExecCtx *ctx, + ObIArray &bulk_tables, int64_t row_count, int64_t column_count, - const ObIArray &obj_array, - bool append_mode) + ObIArray &obj_array, + bool append_mode, + bool is_type_record) { int ret = OB_SUCCESS; - if (bulk_tables.empty() || obj_array.empty()) { + if (OB_ISNULL(ctx) || bulk_tables.empty() || obj_array.empty()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Argument passed in is NULL", K(bulk_tables), K(obj_array), K(ret)); + } else if (is_type_record && bulk_tables.count() != 1) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Argument passed in is NULL", K(bulk_tables), K(obj_array), K(ret)); } else { @@ -6250,8 +6554,12 @@ int ObSPIService::store_result(ObIArray &bulk_tables, if (OB_ISNULL(table) || OB_ISNULL(table->get_allocator())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table or allocator is NULL", K(table), K(ret)); + } else if (is_type_record) { + // collection内部是record场景, bulk_tables.count() 只可能是1 + start_idx = 0; } else { - start_idx += 0 == i ? 0 : bulk_tables.at(i - 1)->get_column_count(); + //对于object而言, get_column_count是record的列数, 这里会整体拷贝object, 因此不能用get_column_count作为跳数 + start_idx += 0 == i ? 0 : 1; } if (OB_SUCC(ret) && !need_ignore) { int64_t old_count = table->get_count(); @@ -6280,27 +6588,64 @@ int ObSPIService::store_result(ObIArray &bulk_tables, } if (OB_SUCC(ret)) { - - //如果是复杂类型,暂不支持SQL类型是复杂类型,所以这里肯定是个record - if (table->get_element_desc().is_composite_type()) { + if (is_type_record) { + // collection element is type record ObArray row; + uint64_t record_id = table->get_element_desc().get_udt_id(); + const ObUserDefinedType *into_user_type = NULL; + const ObRecordType *into_record_type = NULL; + OZ (ctx->get_user_type(record_id, into_user_type)); + CK (OB_NOT_NULL(into_user_type)); + CK (into_user_type->is_record_type()); + OX (into_record_type = static_cast(into_user_type)); for (int64_t j = 0; OB_SUCC(ret) && j < row_count; ++j) { OX (row.reset()); + CK (table->get_column_count() == into_record_type->get_record_member_count()); for (int64_t k = 0; OB_SUCC(ret) && k < table->get_column_count(); ++k) { int64_t idx = j * column_count + start_idx + k; ObObj tmp; CK (OB_NOT_NULL(table->get_allocator())); - OZ (deep_copy_obj(*table->get_allocator(), obj_array.at(idx), tmp)); + if (OB_FAIL(ret)) { + } else if (obj_array.at(idx).is_pl_extend()) { + // recognize record member type is compatible + if (into_record_type->get_record_member_type(k)->is_obj_type()) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(ret)); + } else { + uint64_t dst_id = into_record_type->get_record_member_type(k)->get_user_type_id(); + ObPLComposite *composite = reinterpret_cast(obj_array.at(idx).get_ext()); + if (NULL == composite) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", KPC(composite), K(ret)); + } else if (OB_INVALID_ID == dst_id || OB_INVALID_ID == composite->get_id()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", K(dst_id), K(composite->get_id()), K(ret)); + } else if (dst_id != composite->get_id()) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(dst_id), K(composite->get_id()), K(ret)); + } else { + // in collect_cells interface, it has been deep copy using tmp allocator, + // now deep copy to table allocator and destruct obj_array + // @hr351303: consider in collect_cells use table allocator directly to avoid twice deep copy + OZ (pl::ObUserDefinedType::deep_copy_obj(*table->get_allocator(), obj_array.at(idx), tmp)); + if (OB_SUCC(ret) && obj_array.at(idx).get_meta().get_extend_type() != PL_CURSOR_TYPE) { + OZ (ObUserDefinedType::destruct_obj(obj_array.at(idx), ctx->exec_ctx_->get_my_session())); + } + } + } + } else { + OZ (deep_copy_obj(*table->get_allocator(), obj_array.at(idx), tmp)); + } OZ (row.push_back(tmp)); } OZ (table->set_row(row, append_mode ? old_count + j : j)); } - } else { //如果table里是基础类型,直接按顺序存储数据即可 + } else { //如果table里是非record数据,直接按顺序存储数据即可 int64_t current_datum = append_mode ? reinterpret_cast(bulk_addr) + old_count * sizeof(ObObj) : reinterpret_cast(bulk_addr); for (int64_t j = 0; OB_SUCC(ret) && j < row_count; ++j) { - const ObObj ¤t_obj = obj_array.at(j * column_count + start_idx); + ObObj ¤t_obj = obj_array.at(j * column_count + start_idx); if (OB_UNLIKELY(table->is_not_null())) { if (current_obj.is_null()) { ret = OB_ERR_NUMERIC_OR_VALUE_ERROR; @@ -6310,7 +6655,36 @@ int ObSPIService::store_result(ObIArray &bulk_tables, if (OB_SUCC(ret)) { ObObj tmp; CK (OB_NOT_NULL(table->get_allocator())); - OZ (deep_copy_obj(*table->get_allocator(), current_obj, tmp)); + if (OB_FAIL(ret)) { + } else if (current_obj.is_pl_extend()) { + if (table->get_element_desc().is_obj_type()) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(ret)); + } else { + uint64_t dst_id = table->get_element_desc().get_udt_id(); + ObPLComposite *composite = reinterpret_cast(current_obj.get_ext()); + if (NULL == composite) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", KPC(composite), K(ret)); + } else if (OB_INVALID_ID == dst_id || OB_INVALID_ID == composite->get_id()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected composite to store datum", K(dst_id), K(composite->get_id()), K(ret)); + } else if (dst_id != composite->get_id()) { + ret =OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("expr is wrong type", K(dst_id), K(composite->get_id()), K(ret)); + } else { + // in collect_cells interface, it has been deep copy using tmp allocator, + // now deep copy to table allocator and destruct obj_array + // @hr351303: consider that collect_cells interface use table allocator directly to avoid twice deep copy + OZ (pl::ObUserDefinedType::deep_copy_obj(*table->get_allocator(), current_obj, tmp)); + if (OB_SUCC(ret) && current_obj.get_meta().get_extend_type() != PL_CURSOR_TYPE) { + OZ (ObUserDefinedType::destruct_obj(current_obj, ctx->exec_ctx_->get_my_session())); + } + } + } + } else { + OZ (deep_copy_obj(*table->get_allocator(), current_obj, tmp)); + } OZ (store_datum(current_datum, tmp)); } } @@ -6328,12 +6702,22 @@ int ObSPIService::store_result(ObIArray &bulk_tables, return ret; } -int ObSPIService::store_datums(ObObj &dest_addr, const ObIArray &obj_array) +int ObSPIService::store_datums(ObObj &dest_addr, const ObIArray &obj_array, + ObIAllocator *alloc, bool is_schema_object) { int ret = OB_SUCCESS; - if (obj_array.empty()) { + if (obj_array.empty() || OB_ISNULL(alloc)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Argument passed in is NULL", K(dest_addr), K(obj_array), K(ret)); + } else if (is_schema_object) { + ObObj src; + CK (dest_addr.is_pl_extend()); + /* schema record只能作为单独的into variable存在 + 拷贝时,要求src id和dest id必须一致. */ + CK (1 == obj_array.count()); + OX (src = obj_array.at(0)); + CK (src.is_pl_extend()); + OZ (check_and_deep_copy_result(*alloc, src, dest_addr)); } else { int64_t current_datum = 0; if (dest_addr.is_pl_extend()) { diff --git a/src/sql/ob_spi.h b/src/sql/ob_spi.h index 2f35c0227..9771e4e80 100644 --- a/src/sql/ob_spi.h +++ b/src/sql/ob_spi.h @@ -235,6 +235,7 @@ public: TgTimingEvent tg_timing_event_; uint64_t rowid_table_id_; ObString ps_sql_; // sql prepare过后的参数化sql + bool is_bulk_; }; struct PLPrepareCtx @@ -338,16 +339,23 @@ public: static int spi_set_package_variable(pl::ObPLExecCtx *ctx, uint64_t package_id, int64_t var_idx, - const ObObj &value); + const ObObj &value, + bool need_deep_copy = false); static int spi_set_package_variable(ObExecContext *exec_ctx, pl::ObPLPackageGuard *guard, uint64_t package_id, int64_t var_idx, - const ObObj &value); + const ObObj &value, + ObIAllocator *allocator = NULL, + bool need_deep_copy = false); + static int check_and_deep_copy_result(ObIAllocator &alloc, + const ObObj &src, + ObObj &dst); static int spi_set_variable(pl::ObPLExecCtx *ctx, const ObSqlExpression* expr, const ObObjParam *value, - bool is_default = false); + bool is_default = false, + bool need_copy = false); static int spi_query(pl::ObPLExecCtx *ctx, const char* sql, int64_t type, @@ -358,6 +366,7 @@ public: const bool *exprs_not_null_flag = NULL, const int64_t *pl_integer_ranges = NULL, bool is_bulk = false, + bool is_type_record = false, bool for_update = false); static int spi_check_autonomous_trans(pl::ObPLExecCtx *ctx); static int spi_prepare(common::ObIAllocator &allocator, @@ -382,6 +391,7 @@ public: const int64_t *pl_integer_rangs, bool is_bulk = false, bool is_forall = false, + bool is_type_record = false, bool for_update = false); static int spi_execute_immediate(pl::ObPLExecCtx *ctx, @@ -396,7 +406,8 @@ public: const bool *exprs_not_null_flag, const int64_t *pl_integer_rangs, bool is_bulk = false, - bool is_returning = false); + bool is_returning = false, + bool is_type_record = false); static int spi_get_subprogram_cursor_info(pl::ObPLExecCtx *ctx, uint64_t package_id, @@ -477,7 +488,8 @@ public: bool is_bulk, int64_t limit, const ObDataType *return_types, - int64_t return_type_count); + int64_t return_type_count, + bool is_type_record = false); static int spi_cursor_close(pl::ObPLExecCtx *ctx, uint64_t package_id, uint64_t routine_id, @@ -663,6 +675,7 @@ public: ObSPIOutParams &out_params); static void adjust_pl_status_for_xa(sql::ObExecContext &ctx, int &result); + static int fill_cursor(ObResultSet &result_set, ObSPICursor *cursor); private: static int recreate_implicit_savapoint_if_need(pl::ObPLExecCtx *ctx, int &result); @@ -731,6 +744,7 @@ private: const int64_t *pl_integer_rangs, int64_t is_bulk, bool is_forall = false, + bool is_type_record = false, bool for_update = false); static int dbms_cursor_execute(pl::ObPLExecCtx *ctx, @@ -795,7 +809,8 @@ private: bool for_cursor = false, int64_t limit = INT64_MAX, const ObDataType *return_types = nullptr, - int64_t return_type_count = 0); + int64_t return_type_count = 0, + bool is_type_record = false); static int inner_fetch_with_retry( pl::ObPLExecCtx *ctx, ObSPIResultSet &spi_result, @@ -813,7 +828,8 @@ private: int64_t limit, int64_t last_exec_time, const ObDataType *return_types = nullptr, - int64_t return_type_count = 0); + int64_t return_type_count = 0, + bool is_type_record = false); static int convert_obj(pl::ObPLExecCtx *ctx, ObCastCtx &cast_ctx, @@ -845,14 +861,16 @@ private: bool is_forall = false, int64_t limit = INT64_MAX, const ObDataType *return_types = nullptr, - int64_t return_type_count = 0); + int64_t return_type_count = 0, + bool is_type_record = false); static int fetch_row(void *result_set, bool is_streaming, int64_t &row_count, ObNewRow &row); - static int collect_cells(ObNewRow &row, + static int collect_cells(pl::ObPLExecCtx &ctx, + ObNewRow &row, const ObDataType *result_types, int64_t type_count, const ObIArray &row_desc, @@ -871,23 +889,40 @@ private: ObCastCtx &cast_ctx, ObIArray &obj_array, const ObDataType *return_types, - int64_t return_type_count); + int64_t return_type_count, + bool is_type_record = false); static int get_package_var_info_by_expr(const ObSqlExpression *expr, uint64_t &package_id, uint64_t &var_idx); - static int store_result(ObIArray &bulk_tables, + static int store_result(pl::ObPLExecCtx *ctx, + ObIArray &bulk_tables, int64_t row_count, int64_t column_count, - const ObIArray &obj_array, - bool append_mode); + ObIArray &obj_array, + bool append_mode, + bool is_type_record); - static int store_datums(ObObj &dest_addr, const ObIArray &result); + static int store_into_result(pl::ObPLExecCtx *ctx, + ObCastCtx &cast_ctx, + ObNewRow &cur_row, + const ObSqlExpression **into_exprs, + const ObDataType *column_types, + int64_t type_count, + int64_t into_count, + const bool *exprs_not_null, + const int64_t *pl_integer_ranges, + const ObDataType *return_types, + int64_t return_type_count, + int64_t actual_column_count, + ObIArray &row_desc, + bool is_type_record); + + static int store_datums(ObObj &dest_addr, const ObIArray &result, + ObIAllocator *alloc, bool is_schema_object); static int store_datum(int64_t ¤t_addr, const ObObj &obj); - static int fill_cursor(ObResultSet &result_set, ObSPICursor *cursor); - static const ObPostExprItem &get_last_expr_item(const ObSqlExpression &expr); static const ObInfixExprItem &get_first_expr_item(const ObSqlExpression &expr); @@ -954,7 +989,8 @@ private: bool is_bulk, int64_t limit, const ObDataType *return_types = nullptr, - int64_t return_type_count = 0); + int64_t return_type_count = 0, + bool is_type_record = false); static int check_package_dest_and_deep_copy(pl::ObPLExecCtx &ctx, diff --git a/src/sql/ob_sql.cpp b/src/sql/ob_sql.cpp index 60e4c6a2b..77706403f 100644 --- a/src/sql/ob_sql.cpp +++ b/src/sql/ob_sql.cpp @@ -326,11 +326,12 @@ int ObSql::fill_result_set(ObResultSet &result_set, LOG_WARN("fail to get expr", K(ret), K(i), K(size)); } if (OB_SUCC(ret)) { - ObCollationType charsetnr; - if (OB_FAIL(ObCharset::get_default_collation(expr->get_collation_type(), charsetnr))) { - LOG_WARN("fail to get table item charset collation", K(expr->get_collation_type()), K(i), K(ret)); + if (ob_is_string_or_lob_type(expr->get_data_type()) + && CS_TYPE_BINARY != expr->get_collation_type() + && ObCharset::is_valid_collation(collation_type)) { + field.charsetnr_ = static_cast(collation_type); } else { - field.charsetnr_ = static_cast(charsetnr); + field.charsetnr_ = static_cast(expr->get_collation_type()); } } if (OB_SUCC(ret)) { @@ -433,115 +434,119 @@ int ObSql::fill_result_set(ObResultSet &result_set, case stmt::T_CALL_PROCEDURE: { ObCallProcedureStmt &call_stmt = static_cast(basic_stmt); ObString tname = ObString::make_string("procedure"); + if (NULL == call_stmt.get_call_proc_info()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("call proc info is null", K(ret)); + } else { + int64_t size = call_stmt.get_call_proc_info()->get_output_count(); + field.charsetnr_ = CS_TYPE_UTF8MB4_GENERAL_CI; - int64_t size = call_stmt.get_output_count(); - field.charsetnr_ = CS_TYPE_UTF8MB4_GENERAL_CI; + if (0 == size) { + break; + } - if (0 == call_stmt.get_output_count()) { + if (OB_SUCC(ret) && OB_FAIL(result_set.reserve_field_columns(size))) { + LOG_WARN("reserve field columns failed", K(ret), K(size)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < size; ++i) { + ObCollationType charsetnr; + ObDataType *type = call_stmt.get_call_proc_info()->get_out_type().at(i).get_data_type(); + ObObjType out_obj_type = call_stmt.get_call_proc_info()->get_out_type().at(i).get_obj_type(); + if (ObUnknownType == out_obj_type + || ObExtendType == out_obj_type) { + // do nothing ... + } else if (OB_NOT_NULL(type)) { + if (ob_is_string_or_lob_type(out_obj_type) + && CS_TYPE_ANY == type->get_collation_type()) { + charsetnr = ObCharset::is_valid_collation(collation_type) + ? collation_type + : CS_TYPE_UTF8MB4_BIN; + } else { + OZ (ObCharset::get_default_collation(type->get_collation_type(), charsetnr)); + } + OX (field.charsetnr_ = static_cast(charsetnr)); + } + if (OB_SUCC(ret)) { + field.type_.set_type(out_obj_type); + if (OB_NOT_NULL(type)) { + field.accuracy_ = type->get_accuracy(); + // Setup Collation and Collation levl + if (ob_is_string_or_lob_type(out_obj_type) + || ob_is_raw(out_obj_type) + || ob_is_enum_or_set_type(out_obj_type)) { + field.type_.set_collation_type(type->get_collation_type()); + field.type_.set_collation_level(type->get_collation_level()); + } + } + if (ObExtendType == out_obj_type) { + field.length_ = field.accuracy_.get_length(); + } else if (ObCharType == out_obj_type + || ObVarcharType == out_obj_type + || ob_is_nstring_type(out_obj_type)) { + if (-1 == field.accuracy_.get_length()) { + field.length_ = ObCharType == out_obj_type ? + OB_MAX_ORACLE_CHAR_LENGTH_BYTE : OB_MAX_ORACLE_VARCHAR_LENGTH; + } else { + field.length_ = field.accuracy_.get_length(); + } + } else if (ob_is_enum_or_set_type(out_obj_type)) { + CK (OB_NOT_NULL(type)); + OZ (common::ObField::get_field_mb_length(field.type_.get_type(), + field.accuracy_, + type->get_collation_type(), + field.length_)); + OX (field.type_.set_type(ObVarcharType)); + } else { + OZ (common::ObField::get_field_mb_length(field.type_.get_type(), + field.accuracy_, + common::CS_TYPE_INVALID, + field.length_)); + } + // Setup Scale + if (OB_SUCC(ret)) { + if (ObVarcharType == field.type_.get_type()) { + field.type_.set_varchar(type_name); + } else if (ObNumberType == field.type_.get_type()) { + field.type_.set_number(number); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(ob_write_string(alloc, tname, field.tname_))) { + LOG_WARN("fail to alloc string", K(call_stmt.get_call_proc_info()->get_out_name().at(i)), K(ret)); + } else if (OB_FAIL(ob_write_string(alloc, tname, field.org_tname_))) { + LOG_WARN("fail to alloc string", K(call_stmt.get_call_proc_info()->get_out_name().at(i)), K(ret)); + } else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_call_proc_info()->get_out_name().at(i), field.cname_))) { + LOG_WARN("fail to alloc string", K(call_stmt.get_call_proc_info()->get_out_name().at(i)), K(ret)); + } else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_call_proc_info()->get_out_name().at(i), field.org_cname_))) { + LOG_WARN("fail to alloc string", K(call_stmt.get_call_proc_info()->get_out_name().at(i)), K(ret)); + } else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_call_proc_info()->get_out_type_name().at(i), field.type_name_))) { + LOG_WARN("fail to alloc string", K(call_stmt.get_call_proc_info()->get_out_type_name().at(i)), K(ret)); + } else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_call_proc_info()->get_out_type_owner().at(i), field.type_owner_))) { + LOG_WARN("fail to alloc string", K(call_stmt.get_call_proc_info()->get_out_type_owner().at(i)), K(ret)); + } else { /*do nothing*/ } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(result_set.add_field_column(field))) { + LOG_WARN("fail to add field column to result_set.", K(ret)); + } + } + + if (OB_SUCC(ret)) { + field.cname_.assign(NULL, 0); + field.org_cname_.assign(NULL, 0); + field.dname_.assign(NULL, 0); + field.tname_.assign(NULL, 0); + field.org_tname_.assign(NULL, 0); + field.type_.reset(); + field.type_.set_type(ObExtendType); + field.type_name_.assign(NULL, 0); + field.type_owner_.assign(NULL, 0); + } + } break; } - - if (OB_SUCC(ret) && OB_FAIL(result_set.reserve_field_columns(size))) { - LOG_WARN("reserve field columns failed", K(ret), K(size)); - } - for (int64_t i = 0; OB_SUCC(ret) && i < size; ++i) { - ObCollationType charsetnr; - ObDataType *type = call_stmt.get_out_type().at(i).get_data_type(); - ObObjType out_obj_type = call_stmt.get_out_type().at(i).get_obj_type(); - if (ObUnknownType == out_obj_type - || ObExtendType == out_obj_type) { - // do nothing ... - } else if (OB_NOT_NULL(type)) { - if (ob_is_string_or_lob_type(out_obj_type) - && CS_TYPE_ANY == type->get_collation_type()) { - charsetnr = ObCharset::is_valid_collation(collation_type) - ? collation_type - : CS_TYPE_UTF8MB4_BIN; - } else { - OZ (ObCharset::get_default_collation(type->get_collation_type(), charsetnr)); - } - OX (field.charsetnr_ = static_cast(charsetnr)); - } - if (OB_SUCC(ret)) { - field.type_.set_type(out_obj_type); - if (OB_NOT_NULL(type)) { - field.accuracy_ = type->get_accuracy(); - // Setup Collation and Collation levl - if (ob_is_string_or_lob_type(out_obj_type) - || ob_is_raw(out_obj_type) - || ob_is_enum_or_set_type(out_obj_type)) { - field.type_.set_collation_type(type->get_collation_type()); - field.type_.set_collation_level(type->get_collation_level()); - } - } - if (ObExtendType == out_obj_type) { - field.length_ = field.accuracy_.get_length(); - } else if (ObCharType == out_obj_type - || ObVarcharType == out_obj_type - || ob_is_nstring_type(out_obj_type)) { - if (-1 == field.accuracy_.get_length()) { - field.length_ = ObCharType == out_obj_type ? - OB_MAX_ORACLE_CHAR_LENGTH_BYTE : OB_MAX_ORACLE_VARCHAR_LENGTH; - } else { - field.length_ = field.accuracy_.get_length(); - } - } else if (ob_is_enum_or_set_type(out_obj_type)) { - CK (OB_NOT_NULL(type)); - OZ (common::ObField::get_field_mb_length(field.type_.get_type(), - field.accuracy_, - type->get_collation_type(), - field.length_)); - OX (field.type_.set_type(ObVarcharType)); - } else { - OZ (common::ObField::get_field_mb_length(field.type_.get_type(), - field.accuracy_, - common::CS_TYPE_INVALID, - field.length_)); - } - // Setup Scale - if (OB_SUCC(ret)) { - if (ObVarcharType == field.type_.get_type()) { - field.type_.set_varchar(type_name); - } else if (ObNumberType == field.type_.get_type()) { - field.type_.set_number(number); - } - } - } - if (OB_SUCC(ret)) { - if (OB_FAIL(ob_write_string(alloc, tname, field.tname_))) { - LOG_WARN("fail to alloc string", K(call_stmt.get_out_name().at(i)), K(ret)); - } else if (OB_FAIL(ob_write_string(alloc, tname, field.org_tname_))) { - LOG_WARN("fail to alloc string", K(call_stmt.get_out_name().at(i)), K(ret)); - } else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_out_name().at(i), field.cname_))) { - LOG_WARN("fail to alloc string", K(call_stmt.get_out_name().at(i)), K(ret)); - } else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_out_name().at(i), field.org_cname_))) { - LOG_WARN("fail to alloc string", K(call_stmt.get_out_name().at(i)), K(ret)); - } else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_out_type_name().at(i), field.type_name_))) { - LOG_WARN("fail to alloc string", K(call_stmt.get_out_type_name().at(i)), K(ret)); - } else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_out_type_owner().at(i), field.type_owner_))) { - LOG_WARN("fail to alloc string", K(call_stmt.get_out_type_owner().at(i)), K(ret)); - } else { /*do nothing*/ } - } - - if (OB_SUCC(ret)) { - if (OB_FAIL(result_set.add_field_column(field))) { - LOG_WARN("fail to add field column to result_set.", K(ret)); - } - } - - if (OB_SUCC(ret)) { - field.cname_.assign(NULL, 0); - field.org_cname_.assign(NULL, 0); - field.dname_.assign(NULL, 0); - field.tname_.assign(NULL, 0); - field.org_tname_.assign(NULL, 0); - field.type_.reset(); - field.type_.set_type(ObExtendType); - field.type_name_.assign(NULL, 0); - field.type_owner_.assign(NULL, 0); - } - } - break; } default: break; @@ -573,7 +578,7 @@ int ObSql::fill_result_set(ObResultSet &result_set, OX (param_field.inout_mode_ = ObRoutineParamInOut::SP_PARAM_INOUT); OZ (result_set.add_field_column(column_field), K(i), K(question_marks_count), K(column_field)); - } else if (OB_NOT_NULL(call_stmt) && call_stmt->is_out_param(i)) { + } else if (OB_NOT_NULL(call_stmt) && call_stmt->get_call_proc_info()->is_out_param(i)) { OX (param_field.inout_mode_ = ObRoutineParamInOut::SP_PARAM_INOUT); } OZ (result_set.add_param_column(param_field), @@ -2069,6 +2074,9 @@ int ObSql::handle_ps_execute(const ObPsStmtId client_stmt_id, // call procedure stmt call always parse as dynamic sql context.is_dynamic_sql_ = true; } + if (stmt::T_CALL_PROCEDURE == stmt_type && !context.is_execute_call_stmt_) { + context.is_execute_call_stmt_ = true; + } ObParser parser(allocator, session.get_sql_mode(), session.get_local_collation_connection()); ParseResult parse_result; diff --git a/src/sql/ob_sql_context.h b/src/sql/ob_sql_context.h index 05b96e09e..833988336 100644 --- a/src/sql/ob_sql_context.h +++ b/src/sql/ob_sql_context.h @@ -547,7 +547,7 @@ public: anonymous_view_count_(0), all_user_variable_(), has_udf_(false), - has_pl_udf_(false), + disable_udf_parallel_(false), has_is_table_(false), reference_obj_tables_(), is_table_gen_col_with_udf_(false), @@ -584,7 +584,7 @@ public: anonymous_view_count_ = 0; all_user_variable_.reset(); has_udf_ = false; - has_pl_udf_ = false; + disable_udf_parallel_ = false; has_is_table_ = false; sql_schema_guard_.reset(); reference_obj_tables_.reset(); @@ -657,7 +657,7 @@ public: common::ObSArray all_user_variable_; common::hash::ObHashMap calculable_expr_results_; bool has_udf_; - bool has_pl_udf_; //used to mark query has pl udf + bool disable_udf_parallel_; //used to deterministic pl udf parallel execute bool has_is_table_; // used to mark query has information schema table ObSqlSchemaGuard sql_schema_guard_; share::schema::ObReferenceObjTable reference_obj_tables_; diff --git a/src/sql/ob_sql_utils.cpp b/src/sql/ob_sql_utils.cpp index 4b8137b10..5775dde0e 100644 --- a/src/sql/ob_sql_utils.cpp +++ b/src/sql/ob_sql_utils.cpp @@ -494,7 +494,7 @@ int ObSQLUtils::calc_sql_expression_without_row( LOG_WARN("session is NULL", K(ret)); } else { const sql::ObExpr *new_expr = expr.get_expr(); - exec_ctx.get_physical_plan_ctx()->set_cur_time(ObTimeUtility::current_time()); + exec_ctx.get_physical_plan_ctx()->set_cur_time(ObTimeUtility::current_time(), *exec_ctx.get_my_session()); if (NULL == new_expr) { ret = OB_ERR_UNEXPECTED; LOG_WARN("static engine should have implement this function. unexpected null", K(ret)); diff --git a/src/sql/optimizer/ob_optimizer.cpp b/src/sql/optimizer/ob_optimizer.cpp index 8a32852f1..c9a8c6bea 100644 --- a/src/sql/optimizer/ob_optimizer.cpp +++ b/src/sql/optimizer/ob_optimizer.cpp @@ -512,7 +512,7 @@ int ObOptimizer::check_pdml_supported_feature(const ObDMLStmt &stmt, } else if (stmt_has_dblink) { is_use_pdml = false; ctx_.set_has_dblink(true); - } else if (ctx_.contain_user_nested_sql()) { + } else if (!ctx_.has_trigger() && ctx_.contain_user_nested_sql()) { //user nested sql can't use PDML plan, force to use DAS plan //if online ddl has pl udf, only this way, allow it use PDML plan //such as: @@ -521,6 +521,11 @@ int ObOptimizer::check_pdml_supported_feature(const ObDMLStmt &stmt, //create index with PL UDF allow to use PDML plan during build index table is_use_pdml = false; ctx_.add_plan_note(PDML_DISABLED_BY_NESTED_SQL); + } else if (ctx_.has_trigger() && !ctx_.is_allow_parallel_trigger()) { + // if sql linked trigger, and trigger do not access package var, sequence, sql stmt etc.., + // allow it use PDML plan + is_use_pdml = false; + ctx_.add_plan_note(PDML_DISABLED_BY_NESTED_SQL); } else if (stmt::T_DELETE == stmt.get_stmt_type()) { // // if no trigger, no foreign key, delete can do pdml, even if with local unique index @@ -758,7 +763,7 @@ int ObOptimizer::check_whether_contain_nested_sql(const ObDMLStmt &stmt) { int ret = OB_SUCCESS; const ObDelUpdStmt *del_upd_stmt = nullptr; - if (stmt.get_query_ctx()->has_pl_udf_) { + if (stmt.get_query_ctx()->disable_udf_parallel_) { ctx_.set_has_pl_udf(true); } if (ObSQLUtils::is_nested_sql(ctx_.get_exec_ctx())) { @@ -775,6 +780,7 @@ int ObOptimizer::check_whether_contain_nested_sql(const ObDMLStmt &stmt) const ObTableSchema *table_schema = nullptr; ObSQLSessionInfo *session = ctx_.get_session_info(); bool trigger_exists = false; + bool is_forbid_parallel = false; if (OB_ISNULL(table_info) || OB_ISNULL(schema_guard) || OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sql schema guard is nullptr", K(ret), K(table_info), K(schema_guard), K(session)); @@ -793,6 +799,13 @@ int ObOptimizer::check_whether_contain_nested_sql(const ObDMLStmt &stmt) ctx_.set_has_trigger(true); } } + if (OB_SUCC(ret) && trigger_exists) { + if (OB_FAIL(table_schema->is_allow_parallel_of_trigger(*schema_guard, is_forbid_parallel))) { + LOG_WARN("check allow parallel failed", K(ret)); + } else if (!is_forbid_parallel) { + ctx_.set_allow_parallel_trigger(true); + } + } } } return ret; diff --git a/src/sql/optimizer/ob_optimizer_context.h b/src/sql/optimizer/ob_optimizer_context.h index 871652b98..17f77bd18 100644 --- a/src/sql/optimizer/ob_optimizer_context.h +++ b/src/sql/optimizer/ob_optimizer_context.h @@ -462,6 +462,8 @@ ObOptimizerContext(ObSQLSessionInfo *session_info, bool has_trigger() const { return has_trigger_; } void set_has_pl_udf(bool v) { has_pl_udf_ = v; } bool has_pl_udf() const { return has_pl_udf_; } + void set_allow_parallel_trigger(bool v) { is_allow_parallel_trigger_ = v; } + bool is_allow_parallel_trigger() const { return is_allow_parallel_trigger_; } void set_has_dblink(bool v) { has_dblink_ = v; } bool has_dblink() const { return has_dblink_; } void set_has_subquery_in_function_table(bool v) { has_subquery_in_function_table_ = v; } @@ -543,6 +545,7 @@ private: int8_t has_pl_udf_ : 1; //this sql has pl user defined function int8_t has_subquery_in_function_table_ : 1; //this stmt has function table int8_t has_dblink_ : 1; //this stmt has dblink table + int8_t is_allow_parallel_trigger_ : 1; //this sql linked trigger can parallel execute }; }; bool has_for_update_; diff --git a/src/sql/plan_cache/ob_lib_cache_register.cpp b/src/sql/plan_cache/ob_lib_cache_register.cpp index 192f320a1..b9e5a43ca 100644 --- a/src/sql/plan_cache/ob_lib_cache_register.cpp +++ b/src/sql/plan_cache/ob_lib_cache_register.cpp @@ -18,6 +18,7 @@ #include "pl/ob_pl.h" #include "pl/ob_pl_package.h" #include "observer/table/ob_table_cache.h" +#include "sql/resolver/cmd/ob_call_procedure_stmt.h" #define USING_LOG_PREFIX SQL_PC diff --git a/src/sql/plan_cache/ob_lib_cache_register.h b/src/sql/plan_cache/ob_lib_cache_register.h index 5a74e41a0..46ec949e3 100644 --- a/src/sql/plan_cache/ob_lib_cache_register.h +++ b/src/sql/plan_cache/ob_lib_cache_register.h @@ -18,7 +18,7 @@ LIB_CACHE_OBJ_DEF(NS_ANON, "ANON", pl::ObPLObjectKey, pl::ObPLObjectSet, pl::ObP LIB_CACHE_OBJ_DEF(NS_TRGR, "TRGR", pl::ObPLObjectKey, pl::ObPLObjectSet, pl::ObPLPackage, ObNewModIds::OB_SQL_PHY_PL_OBJ) // trigger cache LIB_CACHE_OBJ_DEF(NS_PKG, "PKG", pl::ObPLObjectKey, pl::ObPLObjectSet, pl::ObPLPackage, ObNewModIds::OB_SQL_PHY_PL_OBJ) // package cache LIB_CACHE_OBJ_DEF(NS_TABLEAPI, "TABLEAPI", table::ObTableApiCacheKey, table::ObTableApiCacheNode, table::ObTableApiCacheObj, "OB_TABLEAPI_OBJ") // tableapi cache - +LIB_CACHE_OBJ_DEF(NS_CALLSTMT, "CALLSTMT", pl::ObPLObjectKey, pl::ObPLObjectSet, ObCallProcedureInfo, ObNewModIds::OB_SQL_PHY_PL_OBJ) // call stmt cache #endif /*LIB_CACHE_OBJ_DEF*/ #ifndef OCEANBASE_SQL_PLAN_CACHE_OB_LIB_CACHE_REGISTER_ diff --git a/src/sql/plan_cache/ob_pc_ref_handle.cpp b/src/sql/plan_cache/ob_pc_ref_handle.cpp index 7f4530552..342d6c4ce 100644 --- a/src/sql/plan_cache/ob_pc_ref_handle.cpp +++ b/src/sql/plan_cache/ob_pc_ref_handle.cpp @@ -64,7 +64,8 @@ const char* ObCacheRefHandleMgr::handle_name(const CacheRefHandleID handle_id) "lc_ref_cache_obj_stat_handle", "plan_baseline_handle", "tableapi_node_handle", - "sql_plan_handle" + "sql_plan_handle", + "callstmt_handle" }; static_assert(sizeof(handle_names)/sizeof(const char*) == MAX_HANDLE, "invalid handle name array"); if (handle_id < MAX_HANDLE) { diff --git a/src/sql/plan_cache/ob_pc_ref_handle.h b/src/sql/plan_cache/ob_pc_ref_handle.h index d12e743db..ade879412 100644 --- a/src/sql/plan_cache/ob_pc_ref_handle.h +++ b/src/sql/plan_cache/ob_pc_ref_handle.h @@ -129,6 +129,7 @@ enum CacheRefHandleID PLAN_BASELINE_HANDLE, TABLEAPI_NODE_HANDLE, SQL_PLAN_HANDLE, + CALLSTMT_HANDLE, MAX_HANDLE }; diff --git a/src/sql/privilege_check/ob_privilege_check.cpp b/src/sql/privilege_check/ob_privilege_check.cpp index e0521e45a..373ceb5cf 100644 --- a/src/sql/privilege_check/ob_privilege_check.cpp +++ b/src/sql/privilege_check/ob_privilege_check.cpp @@ -597,8 +597,6 @@ int add_procs_priv_in_dml( if (OB_ISNULL(dml_stmt) || OB_ISNULL(dml_stmt->get_query_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); - } else if (!dml_stmt->get_query_ctx()->has_pl_udf_) { - // do nothing } else if (dml_stmt->get_relation_exprs(relation_exprs)) { LOG_WARN("failed to get relation exprs", K(ret)); } @@ -2695,10 +2693,10 @@ int get_call_ora_need_privs( int ret = OB_SUCCESS; ObOraNeedPriv need_priv; ObPackedObjPriv packed_privs = 0; - const ObCallProcedureStmt * call_stmt = dynamic_cast(basic_stmt); - if (call_stmt != NULL) { - need_priv.db_name_ = call_stmt->get_db_name(); - uint64_t pkg_id = call_stmt->get_package_id(); + ObCallProcedureStmt * call_stmt = const_cast(dynamic_cast(basic_stmt)); + if (call_stmt != NULL && call_stmt->get_call_proc_info() != NULL) { + need_priv.db_name_ = call_stmt->get_call_proc_info()->get_db_name(); + uint64_t pkg_id = call_stmt->get_call_proc_info()->get_package_id(); /* 对于sys库的package,不需要权限 */ if (need_priv.db_name_ == OB_SYS_DATABASE_NAME && (OB_INVALID_ID == pkg_id @@ -2727,11 +2725,11 @@ int get_call_ora_need_privs( } } else { need_priv.grantee_id_ = user_id; - if (call_stmt->get_package_id() != OB_INVALID_ID) { - need_priv.obj_id_ = call_stmt->get_package_id(); + if (call_stmt->get_call_proc_info()->get_package_id() != OB_INVALID_ID) { + need_priv.obj_id_ = call_stmt->get_call_proc_info()->get_package_id(); need_priv.obj_type_ = static_cast(ObObjectType::PACKAGE); } else { - need_priv.obj_id_ = call_stmt->get_routine_id(); + need_priv.obj_id_ = call_stmt->get_call_proc_info()->get_routine_id(); need_priv.obj_type_ = static_cast(ObObjectType::PROCEDURE); } need_priv.obj_level_ = OBJ_LEVEL_FOR_TAB_PRIV; diff --git a/src/sql/resolver/cmd/ob_call_procedure_resolver.cpp b/src/sql/resolver/cmd/ob_call_procedure_resolver.cpp index aadb88bf8..c68c26fb6 100644 --- a/src/sql/resolver/cmd/ob_call_procedure_resolver.cpp +++ b/src/sql/resolver/cmd/ob_call_procedure_resolver.cpp @@ -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 ¶ms) { int ret = OB_SUCCESS; CK (OB_NOT_NULL(routine_info)); - CK (OB_NOT_NULL(stmt)); - ObArray 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(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(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())) { 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 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(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 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 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(i), static_cast(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(i), static_cast(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; } diff --git a/src/sql/resolver/cmd/ob_call_procedure_resolver.h b/src/sql/resolver/cmd/ob_call_procedure_resolver.h index 76db0baa9..12ae2ed49 100644 --- a/src/sql/resolver/cmd/ob_call_procedure_resolver.h +++ b/src/sql/resolver/cmd/ob_call_procedure_resolver.h @@ -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 ¶ms); int resolve_cparam_without_assign(const ParseNode *param_node, const int64_t position, common::ObIArray ¶ms); @@ -50,6 +53,9 @@ private: int resolve_param_exprs(const ParseNode *params_node, ObIArray &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); diff --git a/src/sql/resolver/cmd/ob_call_procedure_stmt.cpp b/src/sql/resolver/cmd/ob_call_procedure_stmt.cpp index fdfa09d0f..274454fd1 100644 --- a/src/sql/resolver/cmd/ob_call_procedure_stmt.cpp +++ b/src/sql/resolver/cmd/ob_call_procedure_stmt.cpp @@ -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& params) +int ObCallProcedureInfo::prepare_expression(const common::ObArray params) { int ret = OB_SUCCESS; + ObArray 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 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(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(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(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 +{ + +} + } } diff --git a/src/sql/resolver/cmd/ob_call_procedure_stmt.h b/src/sql/resolver/cmd/ob_call_procedure_stmt.h index 4289d2d7a..32ab0a8dc 100644 --- a/src/sql/resolver/cmd/ob_call_procedure_stmt.h +++ b/src/sql/resolver/cmd/ob_call_procedure_stmt.h @@ -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 &get_params() const { return params_; } - inline common::ObIArray &get_params() { return params_; } - inline int add_param(sql::ObRawExpr* param) { return params_.push_back(param); } - int add_params(const common::ObIArray& 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 params); + int final_expression(const common::ObArray 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 params_; ObBitSet<> out_idx_; ObSEArray out_mode_; ObSEArray 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 diff --git a/src/sql/resolver/ddl/ob_create_package_resolver.cpp b/src/sql/resolver/ddl/ob_create_package_resolver.cpp index 965eb3385..b88d21a25 100644 --- a/src/sql/resolver/ddl/ob_create_package_resolver.cpp +++ b/src/sql/resolver/ddl/ob_create_package_resolver.cpp @@ -347,7 +347,7 @@ int ObCreatePackageResolver::resolve_functions_spec(const ObPackageInfo &package routine_info.set_reads_sql_data(); } else if (pl_routine_info->is_modifies_sql_data()) { routine_info.set_modifies_sql_data(); - } else { + } else if (pl_routine_info->is_contains_sql()) { routine_info.set_contains_sql(); } // udt type 相关信息设置 @@ -713,6 +713,32 @@ int ObCreatePackageBodyResolver::update_routine_route_sql(ObIAllocator &allocato OX (routine_info.set_route_sql(route_sql)); OZ (ObSQLUtils::convert_sql_text_to_schema_for_storing(allocator, session_info.get_dtc_params(), routine_body)); OX (routine_info.set_routine_body(routine_body)); + if (OB_SUCC(ret)) { + if (pl_routine_info->is_modifies_sql_data()) { + routine_info.set_modifies_sql_data(); + } else if (pl_routine_info->is_reads_sql_data()) { + routine_info.set_reads_sql_data(); + } else if (pl_routine_info->is_contains_sql()) { + routine_info.set_contains_sql(); + } else if (pl_routine_info->is_no_sql()) { + routine_info.set_no_sql(); + } + if (pl_routine_info->is_wps()) { + routine_info.set_wps(); + } + if (pl_routine_info->is_rps()) { + routine_info.set_rps(); + } + if (pl_routine_info->is_has_sequence()) { + routine_info.set_has_sequence(); + } + if (pl_routine_info->is_has_out_param()) { + routine_info.set_has_out_param(); + } + if (pl_routine_info->is_external_state()) { + routine_info.set_external_state(); + } + } } } OZ (public_routine_list.push_back(routine_info)); diff --git a/src/sql/resolver/ddl/ob_create_routine_resolver.cpp b/src/sql/resolver/ddl/ob_create_routine_resolver.cpp index 113f40c24..e95607cb1 100644 --- a/src/sql/resolver/ddl/ob_create_routine_resolver.cpp +++ b/src/sql/resolver/ddl/ob_create_routine_resolver.cpp @@ -92,7 +92,7 @@ int ObCreateRoutineResolver::analyze_router_sql(obrpc::ObCreateRoutineArg *crt_r if (OB_SUCC(ret)) { pl::ObPLRouter router(routine_info, *session_info_, *schema_checker_->get_schema_guard(), *params_.sql_proxy_); ObString route_sql; - if (OB_FAIL(router.analyze(route_sql, crt_routine_arg->dependency_infos_))) { + if (OB_FAIL(router.analyze(route_sql, crt_routine_arg->dependency_infos_, routine_info))) { LOG_WARN("failed to analyze route sql", K(route_sql), K(ret)); } else if (OB_FAIL(ObSQLUtils::convert_sql_text_to_schema_for_storing( *allocator_, session_info_->get_dtc_params(), route_sql))) { @@ -514,6 +514,28 @@ int ObCreateRoutineResolver::resolve_param_type(const ParseNode *type_node, return ret; } +int ObCreateRoutineResolver::analyze_expr_type(ObRawExpr *&expr, + ObRoutineInfo &routine_info) +{ + int ret = OB_SUCCESS; + CK (OB_NOT_NULL(expr)); + if (OB_FAIL(ret)) { + } else if (T_OP_GET_PACKAGE_VAR == expr->get_expr_type()) { + OX (routine_info.set_rps()); + } else if (T_FUN_UDF == expr->get_expr_type()) { + OX (routine_info.set_external_state()); + } else { + for (int64_t i = 0; + OB_SUCC(ret) && + (!routine_info.is_rps() || !routine_info.is_external_state()) && + i < expr->get_param_count(); + ++i) { + OZ (analyze_expr_type(expr->get_param_expr(i), routine_info)); + } + } + return ret; +} + int ObCreateRoutineResolver::resolve_param_list(const ParseNode *param_list, ObRoutineInfo &routine_info) { int ret = OB_SUCCESS; @@ -568,9 +590,11 @@ int ObCreateRoutineResolver::resolve_param_list(const ParseNode *param_list, ObR break; case MODE_OUT: routine_param.set_out_sp_param_flag(); + routine_info.set_has_out_param(); break; case MODE_INOUT: routine_param.set_inout_sp_param_flag(); + routine_info.set_has_out_param(); break; default: ret = OB_ERR_UNEXPECTED; @@ -625,6 +649,7 @@ int ObCreateRoutineResolver::resolve_param_list(const ParseNode *param_list, ObR *allocator_, session_info_->get_dtc_params(), default_value)); OZ (routine_param.set_default_value(default_value)); OX (match_info.need_cast_ ? routine_param.set_default_cast() : void(NULL)); + OZ (analyze_expr_type(default_expr, routine_info)); } } } diff --git a/src/sql/resolver/ddl/ob_create_routine_resolver.h b/src/sql/resolver/ddl/ob_create_routine_resolver.h index 56017b3fe..9d21a02d4 100644 --- a/src/sql/resolver/ddl/ob_create_routine_resolver.h +++ b/src/sql/resolver/ddl/ob_create_routine_resolver.h @@ -70,6 +70,7 @@ private: int resolve_sp_name(const ParseNode *parse_node, obrpc::ObCreateRoutineArg *crt_routine_arg); int resolve_sp_body(const ParseNode *parse_node, share::schema::ObRoutineInfo &routine_info); int resolve_ret_type(const ParseNode *ret_type_node, share::schema::ObRoutineInfo &func_info); + int analyze_expr_type(ObRawExpr *&expr, share::schema::ObRoutineInfo &routine_info); int resolve_param_list(const ParseNode *param_list, share::schema::ObRoutineInfo &routine_info); int resolve_replace(const ParseNode *parse_node, obrpc::ObCreateRoutineArg *crt_routine_arg); int resolve_editionable(const ParseNode *parse_node, obrpc::ObCreateRoutineArg *crt_routine_arg); diff --git a/src/sql/resolver/ddl/ob_trigger_resolver.cpp b/src/sql/resolver/ddl/ob_trigger_resolver.cpp index 3f767bebf..a3cc373e9 100644 --- a/src/sql/resolver/ddl/ob_trigger_resolver.cpp +++ b/src/sql/resolver/ddl/ob_trigger_resolver.cpp @@ -1063,6 +1063,16 @@ int ObTriggerResolver::analyze_trigger(ObSchemaGetterGuard &schema_guard, &(package_spec_ast.get_body()->get_namespace()), package_body_ast, true)); + if (OB_SUCC(ret)) { + uint64_t data_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(trigger_info.get_tenant_id(), data_version))) { + LOG_WARN("failed to get data version", K(ret)); + } else if (data_version < DATA_VERSION_4_2_0_0) { + // do nothing + } else { + OX (const_cast(trigger_info).set_analyze_flag(package_body_ast.get_analyze_flag())); + } + } if (OB_SUCC(ret) && lib::is_oracle_mode()) { if (is_alter_compile) { OZ (ObPLCompiler::update_schema_object_dep_info(package_body_ast, diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index f00af6855..a5dff9d1f 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -1733,6 +1733,67 @@ int ObDMLResolver::resolve_columns_field_list_first(ObRawExpr *&expr, ObArrayget_type() == oceanbase::pl::PL_OPAQUE_TYPE) { + if (user_type->get_name().compare("JSON_OBJECT_T") == 0 + || user_type->get_name().compare("JSON_ELEMENT_T") == 0) { + ret = OB_ERR_PL_JSONTYPE_USAGE; + LOG_WARN("invalid pl json type userage in pl/sql", K(ret), + K(user_type->get_type()), K(user_type->get_user_type_id())); + } + } + return ret; +} + +int ObDMLResolver::generate_pl_data_type(ObRawExpr *expr, pl::ObPLDataType &pl_data_type) +{ + int ret = OB_SUCCESS; + + CK (OB_NOT_NULL(expr)); + CK (OB_NOT_NULL(params_.secondary_namespace_)); + CK (expr->get_result_type().is_valid()); + if (OB_SUCC(ret)) { + pl::ObPLDataType final_type; + // T_OBJ_ACCESS_REF expr, access obj type (not user defined type) + bool access_obj_type = false; + if (expr->is_obj_access_expr()) { + // T_OBJ_ACCESS_REF return ObExtendType for object access for writing, get obj type + // from %final_type; + // see comment in ObPLInto::add_into + const auto &access_expr = static_cast(*expr); + OZ(access_expr.get_final_type(final_type)); + OX(access_obj_type = !final_type.is_user_type()); + } + if (OB_FAIL(ret)) { + } else if (expr->get_result_type().is_ext() && !access_obj_type) { + CK (expr->is_obj_access_expr()); + OX (pl_data_type = final_type); + if (OB_SUCC(ret) && NULL != params_.secondary_namespace_) { + const pl::ObUserDefinedType *user_type = NULL; + OZ (params_.secondary_namespace_->get_pl_data_type_by_id(final_type.get_user_type_id(), user_type)); + OZ (check_is_pl_jsontype(user_type)); + } + } else { + ObDataType type; + if (access_obj_type) { + type.set_meta_type(final_type.get_data_type()->get_meta_type()); + type.set_accuracy(final_type.get_data_type()->get_accuracy()); + } else { + type.set_meta_type(expr->get_result_type().get_obj_meta()); + type.set_accuracy(expr->get_result_type().get_accuracy()); + } + OX (pl_data_type.set_data_type(type)); + OX (pl_data_type.set_type(PL_OBJ_TYPE)); + } + } + + return ret; +} + int ObDMLResolver::resolve_into_variables(const ParseNode *node, ObIArray &user_vars, ObIArray &pl_vars, @@ -1818,43 +1879,6 @@ int ObDMLResolver::resolve_into_variables(const ParseNode *node, ret = OB_NOT_SUPPORTED; LOG_WARN("dynamic sql returning bulk collect is not supported!", K(ret)); LOG_USER_ERROR(OB_NOT_SUPPORTED, "dynamic sql returning bulk collect"); - } else { //非BULK - for (uint64_t i = 0; OB_SUCC(ret) && i < pl_vars.count(); ++i) { - CK (OB_NOT_NULL(pl_vars.at(i))); - if (OB_SUCC(ret) && pl_vars.at(i)->is_obj_access_expr()) { - pl::ObPLDataType pl_type; - const ObUserDefinedType *user_type = NULL; - const ObRecordType *record_type = NULL; - ObObjAccessRawExpr* access_expr = static_cast(pl_vars.at(i)); - OZ (access_expr->get_final_type(pl_type)); - if (OB_FAIL(ret)) { - } else if (pl_type.is_collection_type()) { - if (pl_type.is_udt_type()) { - ret = OB_ERR_INVALID_TYPE_FOR_OP; - LOG_WARN("inconsistent datatypes", K(ret), K(pl_type)); - } else { - ret = OB_ERR_LOCAL_COLL_IN_SQL; - LOG_WARN("local collection types not allowed in SQL statements", - K(ret), K(pl_type)); - } - } else if (pl_type.is_record_type()) { - CK (OB_NOT_NULL(params_.secondary_namespace_)); - OZ (params_.secondary_namespace_->get_pl_data_type_by_id(pl_type.get_user_type_id(), - user_type)); - CK (OB_NOT_NULL(user_type)); - CK (user_type->is_record_type()); - CK (OB_NOT_NULL(record_type = static_cast(user_type))); - for (int64_t i = 0; OB_SUCC(ret) && i < record_type->get_record_member_count(); ++i) { - const ObPLDataType *member = record_type->get_record_member_type(i); - CK (OB_NOT_NULL(member)); - if (OB_SUCC(ret) && !member->is_obj_type()) { - ret = OB_ERR_INTO_EXPR_ILLEGAL; - LOG_WARN("PLS-00597: expression 'string' in the INTO list is of wrong type", K(ret), K(i)); - } - } - } - } - } } } if (OB_SUCC(ret) && !pl_vars.empty() && !user_vars.empty()) { @@ -1884,6 +1908,301 @@ int ObDMLResolver::resolve_into_variables(const ParseNode *node, } } } + + if (OB_SUCC(ret)) { + if (!user_vars.empty()) { + // into user var in mysql mode + CK (OB_NOT_NULL(select_stmt)); + if (OB_SUCC(ret) && NULL != params_.secondary_namespace_ && + select_stmt->get_select_items().count() != user_vars.count()) { + ret = OB_ERR_COLUMN_SIZE; + LOG_WARN("The used SELECT statements have a different number of columns", K(ret)); + } + } else if (1 == node->value_) { // bulk into + bool has_type_record_type = false; + const ObPLDataType *into_var_type = NULL; + for (int64_t i = 0; OB_SUCC(ret) && !has_type_record_type && i < pl_vars.count(); ++i) { + CK (OB_NOT_NULL(pl_vars.at(i))); + if (OB_SUCC(ret) && pl_vars.at(i)->is_obj_access_expr()) { + pl::ObPLDataType pl_type; + const ObUserDefinedType *user_type = NULL; + ObObjAccessRawExpr* access_expr = static_cast(pl_vars.at(i)); + OZ (access_expr->get_final_type(pl_type)); + CK (pl_type.is_collection_type()); + CK (OB_NOT_NULL(params_.secondary_namespace_)); + OZ (params_.secondary_namespace_->get_pl_data_type_by_id(pl_type.get_user_type_id(), + user_type)); + CK (OB_NOT_NULL(user_type)); + if (OB_SUCC(ret)) { + const ObCollectionType *coll_type = static_cast(user_type); + CK (OB_NOT_NULL(coll_type)); + if (OB_FAIL(ret)) { + } else if (coll_type->get_element_type().is_type_record()) { + has_type_record_type = true; + } + } + } + } + + if (OB_FAIL(ret)) { + } else if (has_type_record_type && pl_vars.count() != 1) { + ret = OB_ERR_MULTI_RECORD; + LOG_WARN("coercion into multiple record targets not supported", K(ret)); + } + /* 走到这里如果没报错,有两种可能: + 1.into 变量中, 元素成员是type record的nested table变量只有唯一一个. + 2.into 变量中, 没有元素成员是type record的nested table变量 */ + if (OB_SUCC(ret)) { + pl::ObPLDataType pl_type; + const ObUserDefinedType *into_user_type = NULL; + const ObUserDefinedType *elem_user_type = NULL; + const ObRecordType *into_record_type = NULL; + int64_t value_expr_count = 0; + int64_t into_data_type_count = 0; + bool is_compatible = true; + bool skip_comp = false; + if (has_type_record_type) { + ObObjAccessRawExpr* access_expr = NULL; + const ObCollectionType *coll_type = NULL; + CK (1 == pl_vars.count()); + OX (access_expr = static_cast(pl_vars.at(0))); + OZ (access_expr->get_final_type(pl_type)); + OZ (params_.secondary_namespace_->get_pl_data_type_by_id(pl_type.get_user_type_id(), into_user_type)); + CK (OB_NOT_NULL(into_user_type)); + OX (coll_type = static_cast(into_user_type)); + CK (OB_NOT_NULL(coll_type)); + CK (coll_type->get_element_type().is_record_type()); + OZ (params_.secondary_namespace_->get_pl_data_type_by_id(coll_type->get_element_type().get_user_type_id(), elem_user_type)); + CK (OB_NOT_NULL(elem_user_type)); + OX (into_record_type = static_cast(elem_user_type)); + OX (into_data_type_count = into_record_type->get_record_member_count()); + } else { + into_data_type_count = pl_vars.count(); + } + if (OB_FAIL(ret)) { + } else if (NULL != select_stmt) { // select into + ObIArray &select_items = select_stmt->get_select_items(); + value_expr_count = select_items.count(); + } else { + ObDelUpdStmt *del_up_stmt = static_cast(get_basic_stmt()); + CK (OB_NOT_NULL(del_up_stmt)); + OX (value_expr_count = del_up_stmt->get_returning_exprs().count()); + } + if (OB_SUCC(ret)) { + if (value_expr_count > into_data_type_count) { + ret = OB_ERR_NOT_ENOUGH_VALUES; + LOG_WARN("type not compatible", K(ret)); + } else if (value_expr_count < into_data_type_count) { + ret = OB_ERR_TOO_MANY_VALUES; + LOG_WARN("type not compatible", K(ret)); + } + CK(OB_NOT_NULL(params_.session_info_)); + for (int64_t i = 0; OB_SUCC(ret) && is_compatible && i < into_data_type_count; ++i) { + ObRawExpr *value_expr = NULL; + if (NULL != select_stmt) { + value_expr = select_stmt->get_select_items().at(i).expr_; + } else { + value_expr = static_cast(get_basic_stmt())->get_returning_exprs().at(i); + } + pl::ObPLDataType into_pl_type; + if (OB_ISNULL(value_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr of select item is null", K(ret)); + } else if (OB_FAIL(value_expr->formalize(params_.session_info_))) { + LOG_WARN("formailize column reference expr failed", K(ret)); + } else { + if (has_type_record_type) { + CK (OB_NOT_NULL(into_record_type)); + CK (OB_NOT_NULL(into_record_type->get_record_member_type(i))); + OX (into_pl_type = *(into_record_type->get_record_member_type(i))); + } else if (pl_vars.at(i)->get_expr_type() == T_QUESTIONMARK) { + skip_comp = true; + } else if (!pl_vars.at(i)->is_obj_access_expr()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("into variable need obj access", K(ret)); + } else { + pl::ObPLDataType pl_type; + const ObUserDefinedType *into_user_type = NULL; + const ObCollectionType *coll_type = NULL; + const ObUserDefinedType *elem_user_type = NULL; + ObObjAccessRawExpr* access_expr = static_cast(pl_vars.at(i)); + OZ (access_expr->get_final_type(pl_type)); + OZ (params_.secondary_namespace_->get_pl_data_type_by_id(pl_type.get_user_type_id(), into_user_type)); + CK (OB_NOT_NULL(into_user_type)); + OX (coll_type = static_cast(into_user_type)); + CK (OB_NOT_NULL(coll_type)); + OX (into_pl_type = coll_type->get_element_type()); + } + } + if (OB_SUCC(ret) && !skip_comp) { + if (value_expr->get_data_type() != ObExtendType && into_pl_type.is_obj_type()) { + CK (OB_NOT_NULL(into_pl_type.get_data_type())); + OX (is_compatible = cast_supported(value_expr->get_data_type(), + value_expr->get_collation_type(), + into_pl_type.get_data_type()->get_obj_type(), + into_pl_type.get_data_type()->get_collation_type())); + } else if (value_expr->get_data_type() == ObExtendType && + (!into_pl_type.is_obj_type() || + (into_pl_type.get_data_type() != NULL && into_pl_type.get_data_type()->get_meta_type().is_ext()))) { + uint64_t left_udt_id = value_expr->get_udt_id(); + uint64_t right_udt_id = (NULL == into_pl_type.get_data_type()) ? into_pl_type.get_user_type_id() + : into_pl_type.get_data_type()->get_udt_id(); + if (left_udt_id != right_udt_id) { + is_compatible = false; + } else { + // same composite type, compatible is true, do nothing. + } + } else { + is_compatible = false; + } + } + if (OB_SUCC(ret) && !is_compatible) { + if (into_pl_type.is_udt_type()) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(into_pl_type)); + } else { + ret = OB_ERR_LOCAL_COLL_IN_SQL; + LOG_WARN("local collection types not allowed in SQL statements", + K(ret), K(pl_type)); + } + } + } + } + } + } else { // into + bool has_type_record_type = false; + const ObPLDataType *into_var_type = NULL; + for (int64_t i = 0; OB_SUCC(ret) && !has_type_record_type && i < pl_vars.count(); ++i) { + CK (OB_NOT_NULL(pl_vars.at(i))); + if (OB_SUCC(ret) && pl_vars.at(i)->is_obj_access_expr()) { + pl::ObPLDataType pl_type; + ObObjAccessRawExpr* access_expr = static_cast(pl_vars.at(i)); + OZ (access_expr->get_final_type(pl_type)); + if (OB_FAIL(ret)) { + } else if (pl_type.is_type_record()) { + has_type_record_type = true; + } + } + } + if (OB_FAIL(ret)) { + } else if (has_type_record_type && pl_vars.count() != 1) { + ret = OB_ERR_MULTI_RECORD; + LOG_WARN("coercion into multiple record targets not supported", K(ret)); + } + + /* 走到这里如果没报错,有两种可能: + 1.into变量只有唯一一个type record. + 2.into变量无type record */ + if (OB_SUCC(ret)) { + pl::ObPLDataType pl_type; + const ObUserDefinedType *into_user_type = NULL; + const ObRecordType *into_record_type = NULL; + int64_t value_expr_count = 0; + int64_t into_data_type_count = 0; + bool is_compatible = true; + bool skip_comp = false; + if (has_type_record_type) { + ObObjAccessRawExpr* access_expr = NULL; + const pl::ObPLDataType *element_type = NULL; + CK (1 == pl_vars.count()); + OX (access_expr = static_cast(pl_vars.at(0))); + OZ (access_expr->get_final_type(pl_type)); + OZ (params_.secondary_namespace_->get_pl_data_type_by_id(pl_type.get_user_type_id(), into_user_type)); + CK (OB_NOT_NULL(into_user_type)); + CK (into_user_type->is_record_type()); + OX (into_record_type = static_cast(into_user_type)); + OX (into_data_type_count = into_record_type->get_record_member_count()); + for (int64_t i = 0; OB_SUCC(ret) && i < into_data_type_count; ++i) { + element_type = into_record_type->get_record_member_type(i); + CK (OB_NOT_NULL(element_type)); + if (OB_SUCC(ret) && element_type->is_type_record()) { + ret = OB_ERR_INTO_EXPR_ILLEGAL; + LOG_WARN("inconsistent datatypes", K(ret)); + } + } + } else { + into_data_type_count = pl_vars.count(); + } + if (OB_FAIL(ret)) { + } else if (NULL != select_stmt) { // select into + ObIArray &select_items = select_stmt->get_select_items(); + value_expr_count = select_items.count(); + } else { + ObDelUpdStmt *del_up_stmt = static_cast(get_basic_stmt()); + CK (OB_NOT_NULL(del_up_stmt)); + OX (value_expr_count = del_up_stmt->get_returning_exprs().count()); + } + if (OB_SUCC(ret)) { + if (value_expr_count > into_data_type_count) { + ret = OB_ERR_NOT_ENOUGH_VALUES; + LOG_WARN("type not compatible", K(ret)); + } else if (value_expr_count < into_data_type_count) { + ret = OB_ERR_TOO_MANY_VALUES; + LOG_WARN("type not compatible", K(ret)); + } + CK(OB_NOT_NULL(params_.session_info_)); + for (int64_t i = 0; OB_SUCC(ret) && is_compatible && i < into_data_type_count; ++i) { + ObRawExpr *value_expr = NULL; + if (NULL != select_stmt) { + value_expr = select_stmt->get_select_items().at(i).expr_; + } else { + value_expr = static_cast(get_basic_stmt())->get_returning_exprs().at(i); + } + pl::ObPLDataType into_pl_type; + if (OB_ISNULL(value_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr of select item is null", K(ret)); + } else if (OB_FAIL(value_expr->formalize(params_.session_info_))) { + LOG_WARN("formailize column reference expr failed", K(ret)); + } else { + if (has_type_record_type) { + CK (OB_NOT_NULL(into_record_type)); + CK (OB_NOT_NULL(into_record_type->get_record_member_type(i))); + OX (into_pl_type = *(into_record_type->get_record_member_type(i))); + } else if (pl_vars.at(i)->get_expr_type() == T_QUESTIONMARK) { + skip_comp = true; + } else { + OZ (generate_pl_data_type(pl_vars.at(i), into_pl_type)); + } + } + if (OB_SUCC(ret) && !skip_comp) { + if (value_expr->get_data_type() != ObExtendType && into_pl_type.is_obj_type()) { + CK (OB_NOT_NULL(into_pl_type.get_data_type())); + OX (is_compatible = cast_supported(value_expr->get_data_type(), + value_expr->get_collation_type(), + into_pl_type.get_data_type()->get_obj_type(), + into_pl_type.get_data_type()->get_collation_type())); + } else if (value_expr->get_data_type() == ObExtendType && + (!into_pl_type.is_obj_type() || + (into_pl_type.get_data_type() != NULL && into_pl_type.get_data_type()->get_meta_type().is_ext()))) { + uint64_t left_udt_id = value_expr->get_udt_id(); + uint64_t right_udt_id = (NULL == into_pl_type.get_data_type()) ? into_pl_type.get_user_type_id() + : into_pl_type.get_data_type()->get_udt_id(); + if (left_udt_id != right_udt_id) { + is_compatible = false; + } else { + // same composite type, compatible is true, do nothing. + } + } else { + is_compatible = false; + } + } + if (OB_SUCC(ret) && !is_compatible) { + if (into_pl_type.is_udt_type()) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(into_pl_type)); + } else { + ret = OB_ERR_LOCAL_COLL_IN_SQL; + LOG_WARN("local collection types not allowed in SQL statements", + K(ret), K(pl_type)); + } + } + } + } + } + } + } + if (OB_SUCC(ret) && NULL != select_stmt) { ObIArray &select_items = select_stmt->get_select_items(); CK(OB_NOT_NULL(params_.session_info_)); @@ -2189,14 +2508,19 @@ int ObDMLResolver::resolve_qualified_identifier(ObQualifiedName &q_name, ret = OB_ERR_PRIVATE_UDF_USE_IN_SQL; LOG_WARN("function 'string' may not be used in SQL", K(ret), KPC(udf)); } else { - stmt_->get_query_ctx()->has_pl_udf_ = true; + OX (stmt_->get_query_ctx()->disable_udf_parallel_ |= !udf->is_parallel_enable()); } } else if (T_FUN_PL_COLLECTION_CONSTRUCT == real_ref_expr->get_expr_type()) { if (!params_.is_resolve_table_function_expr_) { //such as insert into tbl values(1,3, coll('a', 1)); - ret = OB_NOT_SUPPORTED; - LOG_WARN("dml with collection or record construction function is not supported", K(ret)); - LOG_USER_ERROR(OB_NOT_SUPPORTED, "dml with collection or record construction function is"); + if ((NULL == params_.secondary_namespace_ && NULL == session_info_->get_pl_context()) || + (current_scope_ != T_FIELD_LIST_SCOPE && current_scope_ != T_INTO_SCOPE)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("dml with collection or record construction function is not supported", K(ret)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "dml with collection or record construction function is"); + } else { + is_external = false; + } } else { is_external = false; } @@ -2282,7 +2606,10 @@ int ObDMLResolver::resolve_qualified_identifier(ObQualifiedName &q_name, } } if (OB_SUCC(ret) && OB_NOT_NULL(real_ref_expr) && real_ref_expr->is_udf_expr()) { - stmt_->get_query_ctx()->has_pl_udf_ = true; + ObUDFRawExpr *udf = static_cast(real_ref_expr); + if (OB_NOT_NULL(udf)) { + OX (stmt_->get_query_ctx()->disable_udf_parallel_ |= !udf->is_parallel_enable()); + } } } } @@ -4123,6 +4450,7 @@ int ObDMLResolver::resolve_function_table_item(const ParseNode &parse_tree, OZ (stmt->add_global_dependency_table(table_version)); OZ (stmt->add_ref_obj_version(dep_obj_id, dep_db_id, ObObjectType::VIEW, table_version, *allocator_)); } + OX (stmt_->get_query_ctx()->disable_udf_parallel_ |= !udf->is_parallel_enable()); } else if (OB_SUCC(ret) && function_table_expr->is_sys_func_expr()) { // xxx } @@ -10167,6 +10495,7 @@ int ObDMLResolver::resolve_external_name(ObQualifiedName &q_name, //the flag will change to false; OX (expr->set_is_called_in_sql(true)); } + OX (stmt_->get_query_ctx()->disable_udf_parallel_ |= !udf_expr->is_parallel_enable()); } else if (T_FUN_PL_OBJECT_CONSTRUCT == expr->get_expr_type()) { ObDMLStmt *stmt = get_stmt(); ObObjectConstructRawExpr *object_expr = static_cast(expr); diff --git a/src/sql/resolver/dml/ob_dml_resolver.h b/src/sql/resolver/dml/ob_dml_resolver.h index 71c02a8e7..60483a968 100644 --- a/src/sql/resolver/dml/ob_dml_resolver.h +++ b/src/sql/resolver/dml/ob_dml_resolver.h @@ -303,6 +303,7 @@ public: const ObIArray &db_ids); ObDMLStmt *get_stmt(); protected: + int generate_pl_data_type(ObRawExpr *expr, pl::ObPLDataType &pl_data_type); int resolve_into_variables(const ParseNode *node, ObIArray &user_vars, ObIArray &pl_vars, diff --git a/src/sql/resolver/dml/ob_dml_stmt.cpp b/src/sql/resolver/dml/ob_dml_stmt.cpp index c5360390c..848d23e69 100644 --- a/src/sql/resolver/dml/ob_dml_stmt.cpp +++ b/src/sql/resolver/dml/ob_dml_stmt.cpp @@ -385,7 +385,8 @@ ObDMLStmt::ObDMLStmt(stmt::StmtType type) user_var_exprs_(), check_constraint_items_(), dblink_id_(OB_INVALID_ID), - is_reverse_link_(false) + is_reverse_link_(false), + is_bulk_(false) { } @@ -495,6 +496,7 @@ int ObDMLStmt::assign(const ObDMLStmt &other) transpose_item_ = other.transpose_item_; dblink_id_ = other.dblink_id_; is_reverse_link_ = other.is_reverse_link_; + is_bulk_ = other.is_bulk_; } return ret; } @@ -657,6 +659,7 @@ int ObDMLStmt::deep_copy_stmt_struct(ObIAllocator &allocator, is_fetch_with_ties_ = other.is_fetch_with_ties_; dblink_id_ = other.dblink_id_; is_reverse_link_ = other.is_reverse_link_; + is_bulk_ = other.is_bulk_; } if (OB_SUCC(ret)) { TransposeItem *tmp = NULL; diff --git a/src/sql/resolver/dml/ob_dml_stmt.h b/src/sql/resolver/dml/ob_dml_stmt.h index 0d462886d..92304c7da 100644 --- a/src/sql/resolver/dml/ob_dml_stmt.h +++ b/src/sql/resolver/dml/ob_dml_stmt.h @@ -973,6 +973,8 @@ public: inline bool is_dblink_stmt() const { return OB_INVALID_ID != dblink_id_; } inline void set_reverse_link() { is_reverse_link_ = true; } inline bool is_reverse_link() const { return is_reverse_link_; } + inline void set_bulk() { is_bulk_ = true; } + inline bool is_bulk() const { return is_bulk_; } int add_subquery_ref(ObQueryRefRawExpr *query_ref); virtual int get_child_stmt_size(int64_t &child_size) const; int64_t get_subquery_expr_size() const { return subquery_exprs_.count(); } @@ -1210,6 +1212,7 @@ protected: */ int64_t dblink_id_; bool is_reverse_link_; + bool is_bulk_; }; template diff --git a/src/sql/resolver/expr/ob_raw_expr.h b/src/sql/resolver/expr/ob_raw_expr.h index 695480453..1784de582 100644 --- a/src/sql/resolver/expr/ob_raw_expr.h +++ b/src/sql/resolver/expr/ob_raw_expr.h @@ -59,6 +59,7 @@ class ObPLCodeGenerator; namespace sql { class ObStmt; +class ObCallProcedureInfo; class ObSQLSessionInfo; class ObExprOperator; class ObRawExprFactory; @@ -1607,6 +1608,7 @@ public: friend sql::ObExpr *ObStaticEngineExprCG::get_rt_expr(const ObRawExpr &raw_expr); friend sql::ObExpr *ObExprOperator::get_rt_expr(const ObRawExpr &raw_expr) const; friend class pl::ObPLCodeGenerator; + friend class sql::ObCallProcedureInfo; friend class sql::ObRTDatumArith; explicit ObRawExpr(ObItemType expr_type = T_INVALID) diff --git a/src/sql/resolver/ob_resolver_define.h b/src/sql/resolver/ob_resolver_define.h index 2516b933c..5210fd3a2 100644 --- a/src/sql/resolver/ob_resolver_define.h +++ b/src/sql/resolver/ob_resolver_define.h @@ -25,6 +25,7 @@ #include "sql/plan_cache/ob_plan_cache_util.h" #include "sql/plan_cache/ob_plan_cache_struct.h" #include "objit/common/ob_item_type.h" +#include "sql/plan_cache/ob_cache_object_factory.h" namespace oceanbase { diff --git a/src/sql/resolver/ob_resolver_utils.h b/src/sql/resolver/ob_resolver_utils.h index b392c5222..f6b3a048a 100644 --- a/src/sql/resolver/ob_resolver_utils.h +++ b/src/sql/resolver/ob_resolver_utils.h @@ -280,6 +280,7 @@ public: const ParseNode *node, ObQualifiedName &q_name, const ObSQLSessionInfo &session_info); + static int resolve_external_symbol(common::ObIAllocator &allocator, sql::ObRawExprFactory &expr_factory, sql::ObSQLSessionInfo &session_info, diff --git a/src/sql/session/ob_basic_session_info.cpp b/src/sql/session/ob_basic_session_info.cpp index 06a7b43bb..ea528262c 100644 --- a/src/sql/session/ob_basic_session_info.cpp +++ b/src/sql/session/ob_basic_session_info.cpp @@ -89,6 +89,7 @@ ObBasicSessionInfo::ObBasicSessionInfo() name_pool_(ObModIds::OB_SQL_SESSION, OB_MALLOC_NORMAL_BLOCK_SIZE), trans_flags_(), sql_scope_flags_(), + need_reset_package_(false), base_sys_var_alloc_(ObModIds::OB_SQL_SESSION, OB_MALLOC_NORMAL_BLOCK_SIZE), inc_sys_var_alloc1_(ObModIds::OB_SQL_SESSION, OB_MALLOC_NORMAL_BLOCK_SIZE), inc_sys_var_alloc2_(ObModIds::OB_SQL_SESSION, OB_MALLOC_NORMAL_BLOCK_SIZE), @@ -144,6 +145,7 @@ ObBasicSessionInfo::ObBasicSessionInfo() thread_id_(0), is_password_expired_(false), process_query_time_(0) + { thread_data_.reset(); MEMSET(sys_vars_, 0, sizeof(sys_vars_)); @@ -334,6 +336,7 @@ void ObBasicSessionInfo::reset(bool skip_sys_var) package_info_allocator_.reset(); trans_flags_.reset(); sql_scope_flags_.reset(); + need_reset_package_ = false; //bucket_allocator_wrapper_.reset(); user_var_val_map_.reuse(); if (!skip_sys_var) { @@ -4759,6 +4762,25 @@ int ObBasicSessionInfo::track_user_var(const common::ObString &user_var) return ret; } +int ObBasicSessionInfo::remove_changed_user_var(const common::ObString &user_var) +{ + int ret = OB_SUCCESS; + if (user_var.empty()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid input value", K(user_var), K(ret)); + } else { + bool found = false; + for (int64_t i = 0; !found && OB_SUCC(ret) && i < changed_user_vars_.count(); ++i) { + if (changed_user_vars_.at(i) == user_var) { + OZ (changed_user_vars_.remove(i)); + OX (found = true); + break; + } + } + } + return ret; +} + int ObBasicSessionInfo::is_sys_var_actully_changed(const ObSysVarClassType &sys_var_id, const ObObj &old_val, ObObj &new_val, diff --git a/src/sql/session/ob_basic_session_info.h b/src/sql/session/ob_basic_session_info.h index f71da0fd1..a5db2a713 100644 --- a/src/sql/session/ob_basic_session_info.h +++ b/src/sql/session/ob_basic_session_info.h @@ -945,6 +945,8 @@ public: const ObSessionVariable *get_user_variable(const common::ObString &var) const; const common::ObObj *get_user_variable_value(const common::ObString &var) const; bool user_variable_exists(const common::ObString &var) const; + inline void set_need_reset_package(bool need_reset) { need_reset_package_ = need_reset; } + bool need_reset_package() { return need_reset_package_; } /// @} inline static ObDataTypeCastParams create_dtc_params(const ObBasicSessionInfo *session_info) @@ -1029,6 +1031,7 @@ public: int add_changed_user_var(const common::ObString &name, common::ObIArray &array); int track_sys_var(const share::ObSysVarClassType &sys_var_id, const common::ObObj &old_val); int track_user_var(const common::ObString &user_var); + int remove_changed_user_var(const common::ObString &user_var); int is_sys_var_actully_changed(const share::ObSysVarClassType &sys_var_id, const common::ObObj &old_val, common::ObObj &new_val, @@ -1936,6 +1939,7 @@ protected: common::ObStringBuf name_pool_; // for variables names and statement names TransFlags trans_flags_; SqlScopeFlags sql_scope_flags_; + bool need_reset_package_; // for dbms_session.reset_package private: common::ObStringBuf base_sys_var_alloc_; // for variables names and statement names diff --git a/src/sql/session/ob_sql_session_info.cpp b/src/sql/session/ob_sql_session_info.cpp index b9a17a2de..410a9de14 100644 --- a/src/sql/session/ob_sql_session_info.cpp +++ b/src/sql/session/ob_sql_session_info.cpp @@ -1723,6 +1723,57 @@ void ObSQLSessionInfo::reset_all_package_state() } } +int ObSQLSessionInfo::reset_all_package_state_by_dbms_session(bool need_set_sync_var) +{ + /* its called by dbms_session.reset_package() + * in this mode + * 1. we also should reset all user variable mocked by package var + * 2. if the package is a trigger, we should do nothing + * + */ + int ret = OB_SUCCESS; + if (0 == package_state_map_.size() + || NULL != get_pl_context() + || false == need_reset_package()) { + // do nothing + } else { + ObSEArray remove_packages; + if (0 != package_state_map_.size()) { + FOREACH(it, package_state_map_) { + if (!share::schema::ObTriggerInfo::is_trigger_package_id(it->second->get_package_id())) { + ret = ret != OB_SUCCESS ? ret : remove_packages.push_back(it->first); + } + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < remove_packages.count(); ++i) { + ObPLPackageState *package_state = NULL; + bool need_reset = false; + OZ (package_state_map_.get_refactored(remove_packages.at(i), package_state)); + CK (OB_NOT_NULL(package_state)); + OZ (package_state_map_.erase_refactored(remove_packages.at(i))); + OX (need_reset = true); + OZ (package_state->remove_user_variables_for_package_state(*this)); + if (need_reset && NULL != package_state) { + package_state->reset(this); + package_state->~ObPLPackageState(); + get_package_allocator().free(package_state); + } + } + if (OB_SUCC(ret) && need_set_sync_var) { + ObSessionVariable sess_var; + ObString key("##__OB_RESET_ALL_PACKAGE_BY_DBMS_SESSION_RESET_PACKAGE__"); + sess_var.meta_.set_timestamp(); + sess_var.value_.set_timestamp(ObTimeUtility::current_time()); + if (OB_FAIL(ObBasicSessionInfo::replace_user_variable(key, sess_var))) { + LOG_WARN("add user var failed", K(ret)); + } + } + // wether reset succ or not, set need_reset_package to false + set_need_reset_package(false); + } + return ret; +} + int ObSQLSessionInfo::reset_all_serially_package_state() { int ret = OB_SUCCESS; @@ -1832,7 +1883,13 @@ int ObSQLSessionInfo::replace_user_variable( } } } - if (is_package_variable && OB_NOT_NULL(get_pl_engine())) { + if (0 == name.case_compare("##__OB_RESET_ALL_PACKAGE_BY_DBMS_SESSION_RESET_PACKAGE__")) { + // "##__OB_RESET_ALL_PACKAGE_BY_DBMS_SESSION_RESET_PACKAGE__" + // this variable is used to reset_package. + // if we get a set stmt of OB_RESET_ALL_PACKAGE_BY_DBMS_SESSION_RESET_PACKAGE + // we should only reset_all_package, do not need set_user_variable + OZ (reset_all_package_state_by_dbms_session(false)); + } else if (is_package_variable && OB_NOT_NULL(get_pl_engine())) { OZ (set_package_variable(ctx, name, value.value_, true)); } else { OZ (ObBasicSessionInfo::replace_user_variable(name, value)); diff --git a/src/sql/session/ob_sql_session_info.h b/src/sql/session/ob_sql_session_info.h index d005c469e..ee56e61b4 100644 --- a/src/sql/session/ob_sql_session_info.h +++ b/src/sql/session/ob_sql_session_info.h @@ -828,6 +828,7 @@ public: void reset_pl_debugger_resource(); void reset_all_package_changed_info(); void reset_all_package_state(); + int reset_all_package_state_by_dbms_session(bool need_set_sync_var); int reset_all_serially_package_state(); bool is_package_state_changed() const; bool get_changed_package_state_num() const; diff --git a/tools/deploy/mysql_test/test_suite/pl/r/mysql/pl_basic_mysql.result b/tools/deploy/mysql_test/test_suite/pl/r/mysql/pl_basic_mysql.result index 789add5b7..5ecae62e2 100644 --- a/tools/deploy/mysql_test/test_suite/pl/r/mysql/pl_basic_mysql.result +++ b/tools/deploy/mysql_test/test_suite/pl/r/mysql/pl_basic_mysql.result @@ -81,11 +81,11 @@ begin select x from dual; end// call p(1); -+---+ -| x | -+---+ -| 1 | -+---+ ++------+ +| x | ++------+ +| 1 | ++------+ select * from a; +------+------+------+ | a1 | a2 | a3 | 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 e043ce55b..7d4f7c3ec 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 @@ -1316,7 +1316,8 @@ Procedure sql_mode Create Procedure character_set_client collation_connection Da opp CREATE DEFINER = admin@% PROCEDURE `test`.`opp` ( IN `n` bigint(20) unsigned, OUT `pp` tinyint(1) -) begin +) +READS SQL DATA begin declare r double; declare b, s bigint unsigned default 0; set r = sqrt(n); @@ -1372,6 +1373,7 @@ bar CREATE DEFINER = admin@% PROCEDURE `test`.`bar` ( IN `x` char(16), IN `y` int(11) ) +MODIFIES SQL DATA COMMENT `111111111111` insert into test.t1 values (x, y) utf8mb4 utf8mb4_general_ci utf8mb4_general_ci show procedure status like 'bar'| @@ -2241,6 +2243,7 @@ Procedure sql_mode Create Procedure character_set_client collation_connection Da bug2564_1 CREATE DEFINER = admin@% PROCEDURE `test`.`bug2564_1` () +MODIFIES SQL DATA COMMENT `Joe's procedure` insert into `t1` values ("foo", 1) utf8mb4 utf8mb4_general_ci utf8mb4_general_ci show create procedure bug2564_2| @@ -4589,8 +4592,8 @@ use test| select schema_name from information_schema.schemata where schema_name like 'bug18344%'| schema_name -bug18344_012345678901 bug18344_0123456789012 +bug18344_012345678901 select routine_name,routine_schema from information_schema.routines where routine_schema like 'bug18344%'| routine_name routine_schema @@ -6116,7 +6119,8 @@ show create procedure proc_25411_a; Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation proc_25411_a CREATE DEFINER = admin@% PROCEDURE `test`.`proc_25411_a` () - begin + +READS SQL DATA begin /* real comment */ select 1; /*! select 2; */ @@ -6140,7 +6144,8 @@ Procedure sql_mode Create Procedure character_set_client collation_connection Da proc_25411_b CREATE DEFINER = admin@% PROCEDURE `test`.`proc_25411_b` ( IN `p1` int(11), IN `p2` int(11), IN `p3` int(11) -) begin +) +READS SQL DATA begin select p1, p2; end utf8mb4 utf8mb4_general_ci utf8mb4_general_ci select name, param_list, body from mysql.proc where name like "%25411%"; @@ -6169,7 +6174,8 @@ show create procedure proc_25411_c; Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation proc_25411_c CREATE DEFINER = admin@% PROCEDURE `test`.`proc_25411_c` () - begin + +READS SQL DATA begin select 1/*!,2*//*!00000,3*//*!99999,4*/; select 1/*! ,2*//*!00000 ,3*//*!99999 ,4*/; select 1/*!,2 *//*!00000,3 *//*!99999,4 */; @@ -6197,7 +6203,8 @@ show create procedure proc_26302; Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation proc_26302 CREATE DEFINER = admin@% PROCEDURE `test`.`proc_26302` () - select 1 /* testing */ utf8mb4 utf8mb4_general_ci utf8mb4_general_ci + +READS SQL DATA select 1 /* testing */ utf8mb4 utf8mb4_general_ci utf8mb4_general_ci select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES where ROUTINE_NAME = "proc_26302"; ROUTINE_NAME ROUTINE_DEFINITION