diff --git a/src/sql/engine/expr/ob_expr_coll_pred.cpp b/src/sql/engine/expr/ob_expr_coll_pred.cpp index 9eddd9f521..b3d2626900 100644 --- a/src/sql/engine/expr/ob_expr_coll_pred.cpp +++ b/src/sql/engine/expr/ob_expr_coll_pred.cpp @@ -218,56 +218,58 @@ int ObExprCollPred::calc_is_submultiset(const ObObj &obj1, const ObExprCalcType calc_type, CollectionPredRes &result) { - int ret = OB_SUCCESS; - result = COLL_PRED_FALSE; - if (obj1.get_meta().is_ext() && obj2.get_meta().is_ext()) { - pl::ObPLCollection *c1 = reinterpret_cast(obj1.get_ext()); - pl::ObPLCollection *c2 = reinterpret_cast(obj2.get_ext()); - int64_t c1_cnt = c1->get_actual_count(); - int64_t c2_cnt = c2->get_actual_count(); - // 1) return true when: - // 1. obj1 is not null and contains no row, return true whatever obj2 is. - // for example obj nest_type := nest_type(); - // 2. obj1 and obj2 not null, obj1 does not contain any null element, obj1 elem one-to-one - // mapping to obj2 element. + int ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "SUBMULTISET expr is"); + LOG_WARN("SUBMULTISET expr is not supported"); + // result = COLL_PRED_FALSE; + // if (obj1.get_meta().is_ext() && obj2.get_meta().is_ext()) { + // pl::ObPLCollection *c1 = reinterpret_cast(obj1.get_ext()); + // pl::ObPLCollection *c2 = reinterpret_cast(obj2.get_ext()); + // int64_t c1_cnt = c1->get_actual_count(); + // int64_t c2_cnt = c2->get_actual_count(); + // // 1) return true when: + // // 1. obj1 is not null and contains no row, return true whatever obj2 is. + // // for example obj nest_type := nest_type(); + // // 2. obj1 and obj2 not null, obj1 does not contain any null element, obj1 elem one-to-one + // // mapping to obj2 element. - // 2) return null when: - // 1. obj1 is null - // 2. obj2 is null, and obj1 is not null and not empty. - // 3. obj1 contain null element, and any non null is element is one-to-one mapping to obj2 elem - // for example: nt1(1,2,3,4,5), nt2(1,2,NULL), nt3(1,7,null); nt2 submultiset of nt1 => null - // nt3 submultiset nt1 => false + // // 2) return null when: + // // 1. obj1 is null + // // 2. obj2 is null, and obj1 is not null and not empty. + // // 3. obj1 contain null element, and any non null is element is one-to-one mapping to obj2 elem + // // for example: nt1(1,2,3,4,5), nt2(1,2,NULL), nt3(1,7,null); nt2 submultiset of nt1 => null + // // nt3 submultiset nt1 => false - // 3) return false when: - // if none of above conditions occur, return false; - if (OB_ISNULL(c1) || OB_ISNULL(c2)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("union udt failed due to null udt", K(ret), K(obj1), K(obj2)); - } else if (pl::PL_NESTED_TABLE_TYPE != c1->get_type() - || pl::PL_NESTED_TABLE_TYPE != c2->get_type()) { - ret = OB_NOT_SUPPORTED; - LOG_WARN("not support udt union except nested table", K(ret), K(c1), K(c2)); - LOG_USER_ERROR(OB_NOT_SUPPORTED, "udt union except nested table"); - } else if ((c1->get_element_type().get_obj_type() != c2->get_element_type().get_obj_type())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("udt union failed due to uninited", K(ret)); - } else if (0 == c1_cnt && (c1->is_inited())) { - result = COLL_PRED_TRUE; - } else if (!c1->is_inited()) { - result = COLL_PRED_NULL; // null - } else if (!c2->is_inited()) { - result = COLL_PRED_NULL; - } else if (c1_cnt > c2_cnt) { - result = COLL_PRED_FALSE; - } else if (calc_collection_is_contained_without_null(c1, c2, tz_offset, calc_type, result)) { - LOG_WARN("faile to calc multiset without null and delete val", K(ret)); - } else { - // 去除了null和delete数据之后比较,如果是包含关系,但是c1含有null,置结果为null. - if (COLL_PRED_TRUE == result && c1->is_contain_null_val()) { - result = COLL_PRED_NULL; - } - } - } + // // 3) return false when: + // // if none of above conditions occur, return false; + // if (OB_ISNULL(c1) || OB_ISNULL(c2)) { + // ret = OB_ERR_UNEXPECTED; + // LOG_WARN("union udt failed due to null udt", K(ret), K(obj1), K(obj2)); + // } else if (pl::PL_NESTED_TABLE_TYPE != c1->get_type() + // || pl::PL_NESTED_TABLE_TYPE != c2->get_type()) { + // ret = OB_NOT_SUPPORTED; + // LOG_WARN("not support udt union except nested table", K(ret), K(c1), K(c2)); + // LOG_USER_ERROR(OB_NOT_SUPPORTED, "udt union except nested table"); + // } else if ((c1->get_element_type().get_obj_type() != c2->get_element_type().get_obj_type())) { + // ret = OB_ERR_UNEXPECTED; + // LOG_WARN("udt union failed due to uninited", K(ret)); + // } else if (0 == c1_cnt && (c1->is_inited())) { + // result = COLL_PRED_TRUE; + // } else if (!c1->is_inited()) { + // result = COLL_PRED_NULL; // null + // } else if (!c2->is_inited()) { + // result = COLL_PRED_NULL; + // } else if (c1_cnt > c2_cnt) { + // result = COLL_PRED_FALSE; + // } else if (calc_collection_is_contained_without_null(c1, c2, tz_offset, calc_type, result)) { + // LOG_WARN("faile to calc multiset without null and delete val", K(ret)); + // } else { + // // 去除了null和delete数据之后比较,如果是包含关系,但是c1含有null,置结果为null. + // if (COLL_PRED_TRUE == result && c1->is_contain_null_val()) { + // result = COLL_PRED_NULL; + // } + // } + // } return ret; } @@ -405,36 +407,42 @@ int ObExprCollPred::eval_coll_pred(const ObExpr &expr, ObEvalCtx &ctx, ObDatum & if (obj2.get_meta().is_ext()) { pl::ObPLCollection *c2 = reinterpret_cast(obj2.get_ext()); if (OB_NOT_NULL(c2) && 0 < c2->get_actual_count()) { - ObObj *elem = static_cast(c2->get_data()); - ObObj mem_cast; - const ObObj * res_obj1 = &obj1; - ObCollationType cast_coll_type = elem->get_collation_type(); - ObCastMode cp_cast_mode; - if (OB_FAIL(ObSQLUtils::get_default_cast_mode(ctx.exec_ctx_.get_my_session(), - cp_cast_mode))) { - LOG_WARN("failed to get default cast mode", K(ret)); - } - const ObDataTypeCastParams dtc_params - = ObBasicSessionInfo::create_dtc_params(ctx.exec_ctx_.get_my_session()); - ObCastCtx cast_ctx(&ctx.exec_ctx_.get_allocator(), - &dtc_params, - get_cur_time(ctx.exec_ctx_.get_physical_plan_ctx()), - cp_cast_mode, - cast_coll_type, - nullptr); - if (OB_FAIL(ret)) { - } else if (OB_FAIL(ObObjCaster::to_type(elem->get_type(), cast_ctx, - obj1, mem_cast, res_obj1))) { - LOG_WARN("failed to cast member to collection elem type", K(ret)); + if (c2->is_of_composite()) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "MEMBER OF for collections of composite types is"); + LOG_WARN("MEMBER OF for collections of composite types is not supported", K(c2->get_element_type())); } else { - LocalNTSHashMap dmap_c; - int64_t res_cnt = 0; - FILL_HASH_MAP(dmap_c, c2, res_cnt); - if (OB_SUCC(ret)) { - if (OB_NOT_NULL(dmap_c.get(*res_obj1)) ^ (MULTISET_MODIFIER_NOT == info->ms_modifier_)) { - result.set_tinyint(1); - } else { - result.set_tinyint(0); + ObObj *elem = static_cast(c2->get_data()); + ObObj mem_cast; + const ObObj * res_obj1 = &obj1; + ObCollationType cast_coll_type = elem->get_collation_type(); + ObCastMode cp_cast_mode; + if (OB_FAIL(ObSQLUtils::get_default_cast_mode(ctx.exec_ctx_.get_my_session(), + cp_cast_mode))) { + LOG_WARN("failed to get default cast mode", K(ret)); + } + const ObDataTypeCastParams dtc_params + = ObBasicSessionInfo::create_dtc_params(ctx.exec_ctx_.get_my_session()); + ObCastCtx cast_ctx(&ctx.exec_ctx_.get_allocator(), + &dtc_params, + get_cur_time(ctx.exec_ctx_.get_physical_plan_ctx()), + cp_cast_mode, + cast_coll_type, + nullptr); + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObObjCaster::to_type(elem->get_type(), cast_ctx, + obj1, mem_cast, res_obj1))) { + LOG_WARN("failed to cast member to collection elem type", K(ret)); + } else { + LocalNTSHashMap dmap_c; + int64_t res_cnt = 0; + FILL_HASH_MAP(dmap_c, c2, res_cnt); + if (OB_SUCC(ret)) { + if (OB_NOT_NULL(dmap_c.get(*res_obj1)) ^ (MULTISET_MODIFIER_NOT == info->ms_modifier_)) { + result.set_tinyint(1); + } else { + result.set_tinyint(0); + } } } } @@ -446,21 +454,27 @@ int ObExprCollPred::eval_coll_pred(const ObExpr &expr, ObEvalCtx &ctx, ObDatum & if (obj1.get_meta().is_ext()) { pl::ObPLCollection *c1 = reinterpret_cast(obj1.get_ext()); if (OB_NOT_NULL(c1)) { - LocalNTSHashMap dmap_c; - int64_t count = c1->get_actual_count(); - int res_cnt = 0; - if (0 == count) { - // empty nest table is a set - result.set_tinyint(1); - } else if (!c1->is_inited()) { - result.set_null(); + if (c1->is_of_composite()) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "IS A SET for collections of composite types is"); + LOG_WARN("IS A SET for collections of composite types is not supported", K(c1->get_element_type())); } else { - FILL_HASH_MAP(dmap_c, c1, res_cnt); - if (OB_SUCC(ret)) { - if ((count == res_cnt) ^ (MULTISET_MODIFIER_NOT == info->ms_modifier_)) { - result.set_tinyint(1); - } else { - result.set_tinyint(0); + LocalNTSHashMap dmap_c; + int64_t count = c1->get_actual_count(); + int res_cnt = 0; + if (0 == count) { + // empty nest table is a set + result.set_tinyint(1); + } else if (!c1->is_inited()) { + result.set_null(); + } else { + FILL_HASH_MAP(dmap_c, c1, res_cnt); + if (OB_SUCC(ret)) { + if ((count == res_cnt) ^ (MULTISET_MODIFIER_NOT == info->ms_modifier_)) { + result.set_tinyint(1); + } else { + result.set_tinyint(0); + } } } } diff --git a/src/sql/engine/expr/ob_expr_collection_construct.cpp b/src/sql/engine/expr/ob_expr_collection_construct.cpp index 2f17fd0356..90c0f26c81 100644 --- a/src/sql/engine/expr/ob_expr_collection_construct.cpp +++ b/src/sql/engine/expr/ob_expr_collection_construct.cpp @@ -80,6 +80,7 @@ int ObExprCollectionConstruct::calc_result_typeN(ObExprResType &type, } } OX (type.set_type(ObExtendType)); + OX (type.set_extend_type(type_)); OX (type.set_udt_id(udt_id_)); return ret; } diff --git a/src/sql/engine/expr/ob_expr_in.cpp b/src/sql/engine/expr/ob_expr_in.cpp index c30ad1d27e..7329c5a6d7 100644 --- a/src/sql/engine/expr/ob_expr_in.cpp +++ b/src/sql/engine/expr/ob_expr_in.cpp @@ -487,61 +487,63 @@ int ObExprInOrNotIn::calc_result_typeN(ObExprResType &type, } /* 比较规则: - * 1、去除null之后相等,但是c1或c2包含null,结果是null - * 2、c2未初始化,结果是null - * 3、c1未初始化,结果是null - * 4、c1 in (c2,c3,c4), 如果其中某个结果是null,则整体结果是null - * 5、除上面情况,不相等,false - * 6、其它情况,true - * 7、nt1 in nt1, true, 但是,两个未初始化集合比较,结果为null,空集和空集比较,true + * Oracle document: + * Two nested table variables are equal if and only if they have the same set of elements (in any order). + + * the problem is how to define "the same set of elements", which is not documented by Oracle. + * the rules we follow here are: + * 1. if the elements are of an uncomparable type, such as Record, return an error + * 2. when NULL (NULL can be a nested table itself or its element) is compared with any other element, return NULL + * 3. nt in (nt1, nt2, ...) returns: + * a. TRUE if any of nt=nt1, nt=nt2, ... is TRUE + * b. NULL if none of them is TRUE, and at least one of them is NULL + * c. FALSE if all of them are FALSE */ +// forbid composite types in IN expr before composite types comparison is refactored int ObExprInOrNotIn::eval_pl_udt_in(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) { - int ret = OB_SUCCESS; - CollectionPredRes res = CollectionPredRes::COLL_PRED_INVALID; - ObDatum *left = NULL; - ObDatum *right = NULL; - pl::ObPLCollection *coll = NULL; - OZ(expr.args_[0]->eval(ctx, left)); - if (OB_SUCC(ret)) { - coll = reinterpret_cast(left->get_ext()); - if (OB_NOT_NULL(coll) && coll->is_contain_null_val()) { - set_datum_result(T_OP_IN == expr.type_, false, true, expr_datum); - } else { - const ObExpr *row = expr.args_[1]; - for (int64_t i = 0; OB_SUCC(ret) && i < row->arg_cnt_; ++i) { - OZ(row->args_[i]->eval(ctx, right)); - CollectionPredRes eq_cmp_res = COLL_PRED_INVALID; - if (OB_SUCC(ret)) { - if (OB_FAIL(ObRelationalExprOperator::pl_udt_compare2( - eq_cmp_res, *left->extend_obj_, *right->extend_obj_, - ctx.exec_ctx_, CO_EQ))) { - LOG_WARN("failed to compare to nest table", K(ret)); - } else { - res = static_cast(eq_cmp_res); - if (COLL_PRED_TRUE == res) { - break; - } else if (COLL_PRED_NULL == res) { - break; - } - } - } - } - if (OB_SUCC(ret)) { - if (COLL_PRED_NULL == res) { - set_datum_result(T_OP_IN == expr.type_, false, true, expr_datum); - } else if (COLL_PRED_TRUE == res) { - set_datum_result(T_OP_IN == expr.type_, true, false, expr_datum); - } else if (COLL_PRED_FALSE == res) { - set_datum_result(T_OP_IN == expr.type_, false, false, expr_datum); - } else { - set_datum_result(T_OP_IN == expr.type_, false, false, expr_datum); - } - } - } - } + int ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "IN expr for composite types is"); + LOG_WARN("IN expr for composite types is not supported", K(expr)); + // CollectionPredRes res = CollectionPredRes::COLL_PRED_INVALID; + // ObDatum *left = NULL; + // ObDatum *right = NULL; + // pl::ObPLCollection *coll = NULL; + // bool is_any_result_null = false; + // OZ(expr.args_[0]->eval(ctx, left)); + // if (OB_SUCC(ret)) { + // coll = reinterpret_cast(left->get_ext()); + // const ObExpr *row = expr.args_[1]; + // for (int64_t i = 0; OB_SUCC(ret) && i < row->arg_cnt_; ++i) { + // OZ(row->args_[i]->eval(ctx, right)); + // CollectionPredRes eq_cmp_res = COLL_PRED_INVALID; + // if (OB_SUCC(ret)) { + // if (OB_FAIL(ObRelationalExprOperator::pl_udt_compare2( + // eq_cmp_res, *left->extend_obj_, *right->extend_obj_, + // ctx.exec_ctx_, CO_EQ))) { + // LOG_WARN("failed to compare to nest table", K(ret)); + // } else { + // res = static_cast(eq_cmp_res); + // if (COLL_PRED_TRUE == res) { + // break; + // } else if (COLL_PRED_NULL == res) { + // is_any_result_null = true; + // } + // } + // } + // if (OB_SUCC(ret)) { + // if (COLL_PRED_TRUE == res) { + // set_datum_result(T_OP_IN == expr.type_, true, false, expr_datum); + // } else if (is_any_result_null) { + // set_datum_result(T_OP_IN == expr.type_, false, true, expr_datum); + // } else { + // set_datum_result(T_OP_IN == expr.type_, false, false, expr_datum); + // } + // } + // } + // } return ret; } diff --git a/src/sql/engine/expr/ob_expr_multiset.cpp b/src/sql/engine/expr/ob_expr_multiset.cpp index 20ebbe1cd8..ac968d809c 100644 --- a/src/sql/engine/expr/ob_expr_multiset.cpp +++ b/src/sql/engine/expr/ob_expr_multiset.cpp @@ -529,6 +529,10 @@ int ObExprMultiSet::eval_multiset(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &r } else if (c1->get_element_type().get_obj_type() != c2->get_element_type().get_obj_type()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("udt union failed due to uninited", K(ret), KPC(c1), KPC(c2)); + } else if (c1->is_of_composite()) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "MULTISET expr for collections of composite types is"); + LOG_WARN("MULTISET expr for collections of composite types is not supported", K(c1->get_element_type()), K(c2->get_element_type())); } else if (!c1->is_inited() || !c2->is_inited()) { // if has uninit collection, result is uninit, so do nothing ... } else { diff --git a/src/sql/engine/expr/ob_expr_operator.cpp b/src/sql/engine/expr/ob_expr_operator.cpp index 4ff2d8d7ff..ad6e172b03 100644 --- a/src/sql/engine/expr/ob_expr_operator.cpp +++ b/src/sql/engine/expr/ob_expr_operator.cpp @@ -2889,6 +2889,12 @@ int ObRelationalExprOperator::pl_udt_compare2(CollectionPredRes &cmp_result, } else if (c1->get_element_type().get_obj_type() != c2->get_element_type().get_obj_type()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("not support udt compare with different elem type", K(ret), K(c1), K(c2)); + } else if (c1->is_of_composite()) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "comparison of composite types is"); + LOG_WARN("comparison of composite types is not supported", + K(c1->get_element_type()), + K(c2->get_element_type())); } else if (!c1->is_inited() || !c2->is_inited()) { cmp_result = CollectionPredRes::COLL_PRED_NULL; } else if ((c1->get_actual_count() != c2->get_actual_count())) { diff --git a/src/sql/engine/expr/ob_expr_set.cpp b/src/sql/engine/expr/ob_expr_set.cpp index 4730adb4aa..0a01d66133 100644 --- a/src/sql/engine/expr/ob_expr_set.cpp +++ b/src/sql/engine/expr/ob_expr_set.cpp @@ -99,6 +99,10 @@ int ObExprSet::eval_coll(const ObObj &obj, ObExecContext &ctx, pl::ObPLNestedTab } else if (0 > c1->get_count() || !(c1->is_inited())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("union udt failed due to null udt", K(ret), K(c1->get_count()), K(c1->is_inited())); + } else if (c1->is_of_composite()) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "SET for collections of composite types is"); + LOG_WARN("SET for collections of composite types is not supported", K(c1->get_element_type())); } else { coll = static_cast(allocator.alloc(sizeof(pl::ObPLNestedTable))); if (OB_ISNULL(coll)) {