[CP] [to #2024071600103723443] fix: add param type defence at execution stage & fix several related bugs
This commit is contained in:
parent
696c9127a0
commit
2cdeaddd8c
109
src/pl/ob_pl.cpp
109
src/pl/ob_pl.cpp
@ -2748,7 +2748,7 @@ int ObPL::insert_error_msg(int errcode)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObPL::check_trigger_arg(const ParamStore ¶ms, const ObPLFunction &func)
|
||||
int ObPL::check_trigger_arg(ParamStore ¶ms, const ObPLFunction &func)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (TriggerHandle::is_trigger_body_routine(func.get_package_id(), func.get_routine_id(), func.get_proc_type())) {
|
||||
@ -2774,6 +2774,7 @@ int ObPL::check_trigger_arg(const ParamStore ¶ms, const ObPLFunction &func)
|
||||
ObPLRecord *record = reinterpret_cast<ObPLRecord *>(params.at(i).get_ext());
|
||||
CK (OB_NOT_NULL(record));
|
||||
CK (record->get_count() == (static_cast<const ObRecordType *>(udt))->get_member_count());
|
||||
OX (params.at(i).set_udt_id(udt_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3205,6 +3206,7 @@ int ObPLExecState::init_complex_obj(ObIAllocator &allocator,
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (real_pl_type->is_ref_cursor_type() || real_pl_type->is_sys_refcursor_type()) {
|
||||
OX (obj.set_is_ref_cursor_type(true));
|
||||
OX (obj.set_extend(0, PL_REF_CURSOR_TYPE));
|
||||
} else if (real_pl_type->is_udt_type()) {
|
||||
ObPLUDTNS ns(*schema_guard);
|
||||
OZ (ns.init_complex_obj(allocator, *real_pl_type, obj, false, set_null));
|
||||
@ -3226,6 +3228,92 @@ int ObPLExecState::init_complex_obj(ObIAllocator &allocator,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This function is designed to defend against the modification of stored procedures during execution, which could lead
|
||||
// to unexpected parameters being passed to the stored procedure, resulting in unknown errors.
|
||||
// This function can be removed after the feature of defending the compilation cache of the executing stored procedure
|
||||
// from being eliminated on the PL cache side.
|
||||
int ObPLExecState::defend_stored_routine_change(const ObObjParam &actual_param, const ObPLDataType &formal_param_type)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (actual_param.is_null() || actual_param.is_pl_mock_default_param()) {
|
||||
// no actual param type info(eg: out params), skip check
|
||||
} else if (!actual_param.is_ext()) {
|
||||
if (!formal_param_type.is_obj_type()) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("incorrect argument type, expected complex, but get basic type",
|
||||
K(ret), K(formal_param_type), K(actual_param));
|
||||
}
|
||||
} else if ((actual_param.is_ref_cursor_type() /* refcursor */
|
||||
|| PL_REF_CURSOR_TYPE == actual_param.get_meta().get_extend_type() /* also refcursor */
|
||||
|| PL_CURSOR_TYPE == actual_param.get_meta().get_extend_type() /* cursor */)
|
||||
&& formal_param_type.is_cursor_type()) {
|
||||
// skip check
|
||||
} else { // user defined type
|
||||
uint64_t formal_udt_id = OB_INVALID_ID;
|
||||
uint64_t actual_udt_id = OB_INVALID_ID;
|
||||
|
||||
OV (formal_param_type.is_composite_type(), OB_INVALID_ARGUMENT, formal_param_type);
|
||||
OX (formal_udt_id = formal_param_type.get_user_type_id());
|
||||
OV (OB_INVALID_ID != formal_udt_id, OB_ERR_UNEXPECTED, formal_param_type);
|
||||
|
||||
OX (actual_udt_id = actual_param.get_udt_id());
|
||||
if (OB_SUCC(ret) && OB_INVALID_ID == actual_udt_id) {
|
||||
if (PL_RECORD_TYPE == actual_param.get_meta().get_extend_type()
|
||||
|| PL_NESTED_TABLE_TYPE == actual_param.get_meta().get_extend_type()
|
||||
|| PL_ASSOCIATIVE_ARRAY_TYPE == actual_param.get_meta().get_extend_type()
|
||||
|| PL_VARRAY_TYPE == actual_param.get_meta().get_extend_type()) {
|
||||
const pl::ObPLComposite *actual_composite = nullptr;
|
||||
CK (OB_NOT_NULL(actual_composite = reinterpret_cast<const ObPLComposite *>(actual_param.get_ext())));
|
||||
OX (actual_udt_id = actual_composite->get_id());
|
||||
OV (OB_INVALID_ID != actual_udt_id || actual_composite->is_collection(), // anonymous array has invalid udt id
|
||||
OB_ERR_UNEXPECTED, KPC(actual_composite), actual_param);
|
||||
} else {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected extend type without udt id", K(ret), K(actual_param));
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (OB_INVALID_ID == actual_udt_id || formal_udt_id == actual_udt_id) {
|
||||
// skip anonymous array & same udt id
|
||||
} else {
|
||||
bool is_compatible = true;
|
||||
OZ (ObPLResolver::check_composite_compatible(ctx_, actual_udt_id, formal_udt_id, is_compatible));
|
||||
if (OB_INVALID_ARGUMENT == ret) {
|
||||
LOG_INFO("the type of actual param is not found in the current procedure's lexical scope, "
|
||||
"should search caller's scope",
|
||||
K(ret), K(actual_udt_id), K(formal_udt_id));
|
||||
ret = OB_SUCCESS;
|
||||
const ObUserDefinedType *actual_type = nullptr;
|
||||
const ObUserDefinedType *formal_type = nullptr;
|
||||
ObPLContext *pl_ctx = nullptr;
|
||||
ObPLExecState *caller = nullptr;
|
||||
CK (OB_NOT_NULL(ctx_.exec_ctx_));
|
||||
CK (OB_NOT_NULL(ctx_.exec_ctx_->get_my_session()));
|
||||
CK (OB_NOT_NULL(pl_ctx = ctx_.exec_ctx_->get_my_session()->get_pl_context()));
|
||||
CK (pl_ctx->get_exec_stack().count() >= 2);
|
||||
CK (OB_NOT_NULL(caller = pl_ctx->get_exec_stack().at(pl_ctx->get_exec_stack().count() - 2)));
|
||||
// fetch actual param type from caller
|
||||
OZ (caller->get_exec_ctx().get_user_type(actual_udt_id, actual_type));
|
||||
// fetch formal param type from callee
|
||||
OZ (get_exec_ctx().get_user_type(formal_udt_id, formal_type));
|
||||
OV (OB_NOT_NULL(actual_type) && OB_NOT_NULL(formal_type), OB_ERR_UNEXPECTED, actual_udt_id, formal_udt_id);
|
||||
OZ (ObPLResolver::check_composite_compatible(actual_type, formal_type, is_compatible));
|
||||
}
|
||||
OV (is_compatible, OB_INVALID_ARGUMENT, formal_udt_id, actual_udt_id, formal_param_type, actual_param);
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_FAIL(ret)) {
|
||||
LOG_WARN("param type not match, procedure/function could have been replaced",
|
||||
K(ret), K(actual_param), K(formal_param_type));
|
||||
ret = OB_ERR_UNEXPECTED; // replace errno, indicating that it's an internal error
|
||||
LOG_USER_ERROR(OB_ERR_UNEXPECTED, "param type not match, procedure/function could have been replaced");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObPLExecState::check_anonymous_collection_compatible(ObPLComposite &composite, const ObPLDataType &dest_type, bool &need_cast)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
@ -3415,6 +3503,7 @@ int ObPLExecState::init_params(const ParamStore *params, bool is_anonymous)
|
||||
}
|
||||
} else if (func_.get_variables().at(i).is_ref_cursor_type()) {
|
||||
OX (param.set_is_ref_cursor_type(true));
|
||||
OX (param.set_extend(0, PL_REF_CURSOR_TYPE));
|
||||
// CURSOR初始化为NULL
|
||||
} else if (func_.get_variables().at(i).is_cursor_type()) {
|
||||
// leave obj as null type, spi_init wil init it.
|
||||
@ -3482,8 +3571,11 @@ do { \
|
||||
* In Args of Anonymous, If need_to_check_type_ is true then check to convert.
|
||||
* else It will directly used by static sql, do not need to check.
|
||||
*/
|
||||
if (func_.get_in_args().has_member(i)) {
|
||||
const ObPLDataType &pl_type = func_.get_variables().at(i);
|
||||
const ObPLDataType &pl_type = func_.get_variables().at(i); // formal param type
|
||||
if (FAILEDx(defend_stored_routine_change(params->at(i), pl_type))) {
|
||||
LOG_WARN("param type not match, procedure/function could have been replaced",
|
||||
K(ret), K(i), K(params->at(i)), K(pl_type));
|
||||
} else if (func_.get_in_args().has_member(i)) {
|
||||
if (is_anonymous && !func_.get_params_info().at(i).flag_.need_to_check_type_) {
|
||||
OX (get_params().at(i) = params->at(i));
|
||||
} else if (params->at(i).is_pl_mock_default_param()) { // 使用参数默认值
|
||||
@ -3604,7 +3696,9 @@ do { \
|
||||
// same type, we already check this on resolve stage, here directly assign value to symbol.
|
||||
if (get_params().at(i).is_ref_cursor_type()) {
|
||||
get_params().at(i) = params->at(i);
|
||||
get_params().at(i).set_is_ref_cursor_type(true);
|
||||
get_params().at(i).set_is_ref_cursor_type(true); // last assignment statement could clear this flag
|
||||
get_params().at(i).set_extend(
|
||||
get_params().at(i).get_ext(), PL_REF_CURSOR_TYPE, get_params().at(i).get_val_len());
|
||||
} else if (pl_type.is_collection_type() && OB_INVALID_ID == params->at(i).get_udt_id()) {
|
||||
ObPLComposite *composite = NULL;
|
||||
get_params().at(i) = params->at(i);
|
||||
@ -3630,7 +3724,7 @@ do { \
|
||||
} else {
|
||||
CHECK_NOT_NULL_VIOLATED(i, params->at(i));
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (func_.get_variables().at(i).is_obj_type()) {
|
||||
} else if (pl_type.is_obj_type()) {
|
||||
// 纯OUT参数, 对于基础类型直接传入NULL的ObObj
|
||||
ObObj obj; // 基础类型apply一个空的OBJECT
|
||||
ObObjMeta null_meta = get_params().at(i).get_meta();
|
||||
@ -3643,8 +3737,7 @@ do { \
|
||||
}
|
||||
OX (get_params().at(i).set_param_meta(null_meta));
|
||||
} else if (is_anonymous
|
||||
&& (func_.get_variables().at(i).is_nested_table_type()
|
||||
|| func_.get_variables().at(i).is_varray_type())
|
||||
&& (pl_type.is_nested_table_type() || pl_type.is_varray_type())
|
||||
&& params->at(i).is_ext()) {
|
||||
#ifndef OB_BUILD_ORACLE_PL
|
||||
ret = OB_NOT_SUPPORTED;
|
||||
@ -3663,7 +3756,7 @@ do { \
|
||||
// 这里先copy入参的值, 由init_complex_obj函数判断是否重新分配内存
|
||||
OX (get_params().at(i) = params->at(i));
|
||||
OZ (init_complex_obj(*(get_allocator()),
|
||||
func_.get_variables().at(i),
|
||||
pl_type,
|
||||
get_params().at(i),
|
||||
!(top_call_ && ctx_.exec_ctx_->get_sql_ctx()->is_execute_call_stmt_)));
|
||||
}
|
||||
|
@ -729,10 +729,10 @@ public:
|
||||
virtual ~ObPLExecState();
|
||||
|
||||
int init(const ParamStore *params = NULL, bool is_anonymous = false);
|
||||
int defend_stored_routine_change(const ObObjParam &actual_param, const ObPLDataType &formal_param_type);
|
||||
int check_routine_param_legal(ParamStore *params = NULL);
|
||||
int check_anonymous_collection_compatible(ObPLComposite &composite, const ObPLDataType &dest_type, bool &need_cast);
|
||||
int convert_composite(ObObjParam ¶m, const ObPLDataType &dest_type);
|
||||
|
||||
int init_params(const ParamStore *params = NULL, bool is_anonymous = false);
|
||||
int execute();
|
||||
int final(int ret);
|
||||
@ -1208,7 +1208,7 @@ public:
|
||||
|
||||
static int simple_execute(ObPLExecCtx *ctx, int64_t argc, int64_t *argv);
|
||||
|
||||
static int check_trigger_arg(const ParamStore ¶ms, const ObPLFunction &func);
|
||||
static int check_trigger_arg(ParamStore ¶ms, const ObPLFunction &func);
|
||||
|
||||
std::pair<common::ObBucketLock, common::ObBucketLock>& get_jit_lock() { return jit_lock_; }
|
||||
|
||||
|
@ -7330,22 +7330,11 @@ int ObPLResolver::check_in_param_type_legal(const ObIRoutineParam *param_info,
|
||||
is_legal));
|
||||
}
|
||||
} else if (actually_type.get_user_type_id() != expected_type.get_user_type_id()) {
|
||||
#ifdef OB_BUILD_ORACLE_PL
|
||||
if (ObPlJsonUtil::is_pl_jsontype(actually_type.get_user_type_id())) {
|
||||
OZ (check_composite_compatible(current_block_->get_namespace(),
|
||||
expected_type.get_user_type_id(),
|
||||
actually_type.get_user_type_id(),
|
||||
is_legal));
|
||||
} else {
|
||||
#endif
|
||||
OZ (check_composite_compatible(current_block_->get_namespace(),
|
||||
actually_type.get_user_type_id(),
|
||||
expected_type.get_user_type_id(),
|
||||
is_legal));
|
||||
}
|
||||
#ifdef OB_BUILD_ORACLE_PL
|
||||
OZ (check_composite_compatible(current_block_->get_namespace(),
|
||||
actually_type.get_user_type_id(),
|
||||
expected_type.get_user_type_id(),
|
||||
is_legal));
|
||||
}
|
||||
#endif
|
||||
} else if (actually_type.is_composite_type() || expected_type.is_composite_type()) {
|
||||
if (actually_type.is_obj_type()
|
||||
&& ObExtendType == actually_type.get_data_type()->get_obj_type()) {
|
||||
@ -9798,67 +9787,97 @@ int ObPLResolver::build_raw_expr(const ParseNode *node,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ObPLResolver::is_json_type_compatible(const ObUserDefinedType *left, const ObUserDefinedType *right)
|
||||
{
|
||||
bool ObPLResolver::is_json_type_compatible(const ObUserDefinedType *actual_param_type,
|
||||
const ObUserDefinedType *formal_param_type) {
|
||||
#ifdef OB_BUILD_ORACLE_PL
|
||||
return (ObPlJsonUtil::is_pl_json_element_type(left->get_user_type_id())
|
||||
&& (ObPlJsonUtil::is_pl_json_object_type(right->get_user_type_id())
|
||||
|| ObPlJsonUtil::is_pl_json_array_type(right->get_user_type_id()))) ;
|
||||
// TYPE JSON_OBJECT_T UNDER JSON_ELEMENT_T
|
||||
// TYPE JSON_ARRAY_T UNDER JSON_ELEMENT_T
|
||||
return (ObPlJsonUtil::is_pl_json_object_type(actual_param_type->get_user_type_id())
|
||||
|| ObPlJsonUtil::is_pl_json_array_type(actual_param_type->get_user_type_id()))
|
||||
&& ObPlJsonUtil::is_pl_json_element_type(formal_param_type->get_user_type_id());
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ObPLResolver::check_composite_compatible(const ObPLINS &ns,
|
||||
uint64_t left_type_id,
|
||||
uint64_t right_type_id,
|
||||
uint64_t actual_param_type_id,
|
||||
uint64_t formal_param_type_id,
|
||||
bool &is_compatible)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const ObUserDefinedType *left_type = NULL;
|
||||
const ObUserDefinedType *right_type = NULL;
|
||||
const ObUserDefinedType *actual_param_type = nullptr;
|
||||
const ObUserDefinedType *formal_param_type = nullptr;
|
||||
ObArenaAllocator allocator;
|
||||
is_compatible = false;
|
||||
//NOTICE: do not call this function when left_type_id equal to right_type_id
|
||||
CK (left_type_id != right_type_id);
|
||||
OZ (ns.get_user_type(left_type_id, left_type, &allocator));
|
||||
OZ (ns.get_user_type(right_type_id, right_type, &allocator));
|
||||
CK (OB_NOT_NULL(left_type) && OB_NOT_NULL(right_type));
|
||||
// NOTICE: do not call this function when left_type_id equal to right_type_id
|
||||
CK (actual_param_type_id != formal_param_type_id);
|
||||
|
||||
// The type of the actual argument may not exist in the current function's lexical scope, an error needs to be
|
||||
// reported to the upper level to search in the caller's lexical scope. Consider case below:
|
||||
// ```
|
||||
// declare
|
||||
// cursor cur is select * from some_table;
|
||||
// begin
|
||||
// for v in cur loop
|
||||
// some_proc(v);
|
||||
// end loop;
|
||||
// end;
|
||||
// ```
|
||||
// The type of actual param V passed to SOME_PROC can not be found in SOME_PROC's scope, it is recorded in the caller
|
||||
// anonymous block's scope.
|
||||
OZ (ns.get_user_type(actual_param_type_id, actual_param_type, &allocator));
|
||||
if (OB_FAIL(ret) || OB_ISNULL(actual_param_type)) {
|
||||
LOG_WARN("failed to get user type of actual param", K(ret), K(actual_param_type_id));
|
||||
ret = OB_INVALID_ARGUMENT; // indicates that the type of the actual argument was not found
|
||||
}
|
||||
OV (OB_NOT_NULL(actual_param_type), OB_INVALID_ARGUMENT, actual_param_type_id, formal_param_type_id);
|
||||
|
||||
// The type of the formal argument must exist in the current function's lexical scope.
|
||||
OZ (ns.get_user_type(formal_param_type_id, formal_param_type, &allocator));
|
||||
CK (OB_NOT_NULL(formal_param_type));
|
||||
|
||||
OZ (check_composite_compatible(actual_param_type, formal_param_type, is_compatible));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObPLResolver::check_composite_compatible(const ObUserDefinedType *actual_param_type,
|
||||
const ObUserDefinedType *formal_param_type,
|
||||
bool &is_compatible)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
// Assigning One Record Variable to Another
|
||||
// You can assign the value of one record variable to another record variable only in these cases:
|
||||
// The two variables have the same RECORD type.
|
||||
// The target variable is declared with a RECORD type, the source variable is declared with %ROWTYPE,
|
||||
// their fields match in number and order, and corresponding fields have the same data type.
|
||||
// For record components of composite variables, the types of the composite variables need not match.
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (is_json_type_compatible(left_type, right_type)) {
|
||||
// 1. The two variables have the same RECORD type.
|
||||
// 2. The target variable is declared with a RECORD type, the source variable is declared with %ROWTYPE,
|
||||
// their fields match in number and order, and corresponding fields have the same data type.
|
||||
// 3. For record components of composite variables, the types of the composite variables need not match.
|
||||
if (is_json_type_compatible(actual_param_type, formal_param_type)) {
|
||||
is_compatible = true;
|
||||
} else if (left_type->is_cursor_type() && right_type->is_cursor_type()) {
|
||||
} else if (actual_param_type->is_cursor_type() && formal_param_type->is_cursor_type()) {
|
||||
is_compatible = true;
|
||||
} else if (right_type->is_generic_type()) {
|
||||
if ((right_type->is_generic_adt_type()
|
||||
|| right_type->is_generic_record_type())
|
||||
&& left_type->is_record_type()) {
|
||||
} else if (formal_param_type->is_generic_type()) {
|
||||
if ((formal_param_type->is_generic_adt_type() || formal_param_type->is_generic_record_type())
|
||||
&& actual_param_type->is_record_type()) {
|
||||
is_compatible = true;
|
||||
} else if ((right_type->is_generic_varray_type()
|
||||
|| right_type->is_generic_v2_table_type()
|
||||
|| right_type->is_generic_table_type()
|
||||
|| right_type->is_generic_collection_type())
|
||||
&& left_type->is_collection_type()) {
|
||||
} else if ((formal_param_type->is_generic_varray_type()
|
||||
|| formal_param_type->is_generic_v2_table_type()
|
||||
|| formal_param_type->is_generic_table_type()
|
||||
|| formal_param_type->is_generic_collection_type())
|
||||
&& actual_param_type->is_collection_type()) {
|
||||
is_compatible = true;
|
||||
} else if (right_type->is_generic_ref_cursor_type()
|
||||
&& left_type->is_cursor_type()) {
|
||||
} else if (formal_param_type->is_generic_ref_cursor_type() && actual_param_type->is_cursor_type()) {
|
||||
is_compatible = true;
|
||||
}
|
||||
} else if (left_type->is_record_type()
|
||||
&& right_type->is_record_type()
|
||||
&& !left_type->is_udt_type()
|
||||
&& !right_type->is_udt_type()
|
||||
&& (left_type->is_rowtype_type() || right_type->is_rowtype_type())) {
|
||||
const ObRecordType *left_r_type = static_cast<const ObRecordType *>(left_type);
|
||||
const ObRecordType *right_r_type = static_cast<const ObRecordType *>(right_type);
|
||||
CK (OB_NOT_NULL(left_r_type) && OB_NOT_NULL(right_r_type));
|
||||
OZ (left_r_type->is_compatble(*right_r_type, is_compatible));
|
||||
} else if (actual_param_type->is_record_type()
|
||||
&& formal_param_type->is_record_type()
|
||||
&& !actual_param_type->is_udt_type()
|
||||
&& !formal_param_type->is_udt_type()
|
||||
&& (actual_param_type->is_rowtype_type() || formal_param_type->is_rowtype_type())) {
|
||||
const ObRecordType *actual_r_type = static_cast<const ObRecordType *>(actual_param_type);
|
||||
const ObRecordType *formal_r_type = static_cast<const ObRecordType *>(formal_param_type);
|
||||
CK (OB_NOT_NULL(actual_r_type) && OB_NOT_NULL(formal_r_type));
|
||||
OZ (actual_r_type->is_compatble(*formal_r_type, is_compatible));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -10089,17 +10108,17 @@ int ObPLResolver::resolve_expr(const ParseNode *node,
|
||||
&& expr->get_expr_type() != T_FUN_SYS_PDB_GET_RUNTIME_INFO) {
|
||||
bool is_compatible = false;
|
||||
OZ (check_composite_compatible(current_block_->get_namespace(),
|
||||
expected_type->get_user_type_id(),
|
||||
expr->get_result_type().get_udt_id(),
|
||||
expected_type->get_user_type_id(),
|
||||
is_compatible));
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (!is_compatible) {
|
||||
ret = OB_ERR_INVALID_TYPE_FOR_OP;
|
||||
#ifdef OB_BUILD_ORACLE_PL
|
||||
// error code compiltable with oracle
|
||||
if (ObPlJsonUtil::is_pl_json_object_type(expected_type->get_user_type_id())
|
||||
&& ObPlJsonUtil::is_pl_json_element_type(expr->get_result_type().get_udt_id())
|
||||
&& ObPlJsonUtil::is_pl_json_array_type(expr->get_result_type().get_udt_id())) {
|
||||
if ((ObPlJsonUtil::is_pl_json_array_type(expected_type->get_user_type_id())
|
||||
|| ObPlJsonUtil::is_pl_json_object_type(expected_type->get_user_type_id()))
|
||||
&& ObPlJsonUtil::is_pl_json_element_type(expr->get_result_type().get_udt_id())) {
|
||||
ret = OB_ERR_EXPRESSION_WRONG_TYPE;
|
||||
}
|
||||
#endif
|
||||
|
@ -512,10 +512,15 @@ public:
|
||||
ObIArray<ObRawExpr*>& params,
|
||||
const ObUserDefinedType *user_type,
|
||||
ObPLDataType &pl_type);
|
||||
static bool is_json_type_compatible(
|
||||
const ObUserDefinedType *left, const ObUserDefinedType *right);
|
||||
static bool is_json_type_compatible(const ObUserDefinedType *actual_param_type,
|
||||
const ObUserDefinedType *formal_param_type);
|
||||
static int check_composite_compatible(const ObPLINS &ns,
|
||||
uint64_t left_type_id, uint64_t right_type_id, bool &is_compatible);
|
||||
uint64_t actual_param_type_id,
|
||||
uint64_t formal_param_type_id,
|
||||
bool &is_compatible);
|
||||
static int check_composite_compatible(const ObUserDefinedType *actual_param_type,
|
||||
const ObUserDefinedType *formal_param_type,
|
||||
bool &is_compatible);
|
||||
|
||||
static
|
||||
int resolve_nocopy_params(const share::schema::ObIRoutineInfo *routine_info,
|
||||
|
@ -67,7 +67,8 @@ public:
|
||||
pl::ObProcType type)
|
||||
{
|
||||
bool is_trg_routine = false;
|
||||
if (schema::ObTriggerInfo::is_trigger_body_package_id(package_id) && pl::ObProcType::PACKAGE_PROCEDURE == type) {
|
||||
if (schema::ObTriggerInfo::is_trigger_body_package_id(package_id)
|
||||
&& (pl::ObProcType::PACKAGE_PROCEDURE == type || pl::ObProcType::PACKAGE_FUNCTION == type)) {
|
||||
if (lib::is_oracle_mode()) {
|
||||
is_trg_routine = (routine_id >= ROUTINE_IDX_CALC_WHEN && routine_id <= ROUTINE_IDX_AFTER_STMT);
|
||||
} else {
|
||||
|
@ -231,7 +231,7 @@ int ObPlAggUdfFunction::build_in_params_store(ObObjParam &pl_obj,
|
||||
LOG_WARN("failed to push back param", K(ret));
|
||||
} else if (obj_params != NULL &&
|
||||
OB_FAIL(ObExprUDF::process_in_params(obj_params, param_num, params_desc,
|
||||
params_type_, *udf_params, *allocator_))) {
|
||||
params_type, *udf_params, *allocator_))) {
|
||||
LOG_WARN("failed to process in params", K(ret));
|
||||
} else {
|
||||
LOG_TRACE("succeed to build in params store", K(pl_obj), K(obj_params), K(params_desc),
|
||||
|
@ -1127,27 +1127,14 @@ int ObResolverUtils::check_type_match(const pl::ObPLResolveCtx &resolve_ctx,
|
||||
} else {
|
||||
// 复杂类型的TypeClass相同, 需要检查兼容性
|
||||
bool is_compatible = false;
|
||||
#ifdef OB_BUILD_ORACLE_PL
|
||||
if (ObPlJsonUtil::is_pl_jsontype(src_type_id)) {
|
||||
OZ (ObPLResolver::check_composite_compatible(
|
||||
NULL == resolve_ctx.params_.secondary_namespace_
|
||||
? static_cast<const ObPLINS&>(resolve_ctx)
|
||||
: static_cast<const ObPLINS&>(*resolve_ctx.params_.secondary_namespace_),
|
||||
dst_pl_type.get_user_type_id(),
|
||||
src_type_id,
|
||||
is_compatible), K(src_type_id), K(dst_pl_type), K(resolve_ctx.params_.is_execute_call_stmt_));
|
||||
} else {
|
||||
#endif
|
||||
OZ (ObPLResolver::check_composite_compatible(
|
||||
NULL == resolve_ctx.params_.secondary_namespace_
|
||||
? static_cast<const ObPLINS&>(resolve_ctx)
|
||||
: static_cast<const ObPLINS&>(*resolve_ctx.params_.secondary_namespace_),
|
||||
src_type_id,
|
||||
dst_pl_type.get_user_type_id(),
|
||||
is_compatible), K(src_type_id), K(dst_pl_type), K(resolve_ctx.params_.is_execute_call_stmt_));
|
||||
#ifdef OB_BUILD_ORACLE_PL
|
||||
}
|
||||
#endif
|
||||
OZ (ObPLResolver::check_composite_compatible(
|
||||
NULL == resolve_ctx.params_.secondary_namespace_
|
||||
? static_cast<const ObPLINS &>(resolve_ctx)
|
||||
: static_cast<const ObPLINS &>(*resolve_ctx.params_.secondary_namespace_),
|
||||
src_type_id,
|
||||
dst_pl_type.get_user_type_id(),
|
||||
is_compatible),
|
||||
K(src_type_id), K(dst_pl_type), K(resolve_ctx.params_.is_execute_call_stmt_));
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (is_compatible) {
|
||||
OX (match_info = ObRoutineMatchInfo::MatchInfo(true, src_type, dst_type));
|
||||
|
Loading…
x
Reference in New Issue
Block a user