diff --git a/deps/oblib/src/common/object/ob_object.h b/deps/oblib/src/common/object/ob_object.h index 55a5f5e424..934063c01a 100644 --- a/deps/oblib/src/common/object/ob_object.h +++ b/deps/oblib/src/common/object/ob_object.h @@ -4293,6 +4293,7 @@ public: inline ObCharsetType get_charset_type() const { return charset_; } inline ObCollationType get_collation_type() const { return meta_.get_collation_type(); } inline ObCollationLevel get_collation_level() const { return meta_.get_collation_level(); } + inline uint16_t get_subschema_id() { return meta_.get_subschema_id(); } inline bool is_binary_collation() const { return is_binary_collation_; } inline bool is_zero_fill() const { return is_zero_fill_; } inline void set_obj_type(const ObObjType &type) { return meta_.set_type(type); } diff --git a/deps/oblib/src/lib/CMakeLists.txt b/deps/oblib/src/lib/CMakeLists.txt index 8504701cd1..3be1b9a64f 100644 --- a/deps/oblib/src/lib/CMakeLists.txt +++ b/deps/oblib/src/lib/CMakeLists.txt @@ -235,6 +235,7 @@ ob_set_subtarget(oblib_lib common_mixed udt/ob_udt_type.cpp udt/ob_collection_type.cpp udt/ob_array_type.cpp + udt/ob_array_utils.cpp xml/ob_mul_mode_reader.cpp xml/ob_xml.cpp xml/ob_xml_parser.cpp diff --git a/deps/oblib/src/lib/ob_name_def.h b/deps/oblib/src/lib/ob_name_def.h index 1c2c8c0e59..a03dc590ab 100644 --- a/deps/oblib/src/lib/ob_name_def.h +++ b/deps/oblib/src/lib/ob_name_def.h @@ -1118,6 +1118,16 @@ #define N_ALIGN_DATE4CMP "align_date4cmp" #define N_ARRAY "array" #define N_ARRAY_CONTAINS "array_contains" +#define N_ARRAY_OVERLAPS "array_overlaps" +#define N_ARRAY_CONTAINS_ALL "array_contains_all" +#define N_ARRAY_DISTINCT "array_distinct" +#define N_ARRAY_REMOVE "array_remove" +#define N_ARRAY_MAP "array_map" +#define N_ARRAY_TO_STRING "array_to_string" +#define N_STRING_TO_ARRAY "string_to_array" +#define N_ARRAY_APPEND "array_append" +#define N_ELEMENT_AT "element_at" +#define N_ARRAY_CARDINALITY "cardinality" // for lock function #define N_GET_LOCK "get_lock" @@ -1190,6 +1200,7 @@ #define N_SPLIT_PART "split_part" #define N_RB_ITERATE "rb_iterate" #define N_RB_SELECT "rb_select" +#define N_RB_BUILD "rb_build" #define N_GET_MYSQL_ROUTINE_PARAMETER_TYPE_STR "get_mysql_routine_parameter_type_str" #define N_ORA_LOGIN_USER "ora_login_user" #define N_PRIV_ST_GEOHASH "_st_geohash" diff --git a/deps/oblib/src/lib/udt/ob_array_type.cpp b/deps/oblib/src/lib/udt/ob_array_type.cpp index 27bf0943bc..7b083ce04e 100644 --- a/deps/oblib/src/lib/udt/ob_array_type.cpp +++ b/deps/oblib/src/lib/udt/ob_array_type.cpp @@ -166,169 +166,6 @@ int ObArrayTypeObjFactory::construct(common::ObIAllocator &alloc, const ObCollec return ret; } -int ObArrayUtil::get_type_name(const ObDataType &elem_type, char *buf, int buf_len, uint32_t depth) -{ - int ret = OB_SUCCESS; - int64_t pos = 0; - for (uint32_t i = 0; OB_SUCC(ret) && i < depth; i++) { - if (OB_FAIL(databuff_printf(buf, buf_len, pos, "ARRAY("))) { - LOG_WARN("failed to convert len to string", K(ret)); - } - } - if (OB_FAIL(ret)) { - } else if (OB_FAIL(databuff_printf(buf, buf_len, pos, "%s", ob_sql_type_str(elem_type.get_obj_type())))) { - LOG_WARN("failed to convert len to string", K(ret)); - } else if (elem_type.get_obj_type() == ObDecimalIntType - && OB_FAIL(databuff_printf(buf, buf_len, pos, "(%d,%d)", elem_type.get_precision(), elem_type.get_scale()))) { - LOG_WARN("failed to add deciaml precision to string", K(ret)); - } else if (ob_is_string_tc(elem_type.get_obj_type()) - && OB_FAIL(databuff_printf(buf, buf_len, pos, "(%d)", elem_type.get_length()))) { - LOG_WARN("failed to add string len to string", K(ret)); - } - for (uint32_t i = 0; OB_SUCC(ret) && i < depth; i++) { - if (OB_FAIL(databuff_printf(buf, buf_len, pos, ")"))) { - LOG_WARN("failed to add ) to string", K(ret)); - } - } - return ret; -} - -int ObArrayUtil::push_back_decimal_int(const ObPrecision prec, const ObDecimalInt *dec_val, bool is_null, ObIArrayType *arr_obj) -{ - int ret = OB_SUCCESS; - if (get_decimalint_type(prec) == DECIMAL_INT_32) { - ObArrayFixedSize *arr = static_cast *>(arr_obj); - if (is_null) { - if (OB_FAIL(arr->push_back(0, true))) { - LOG_WARN("failed to push back null value", K(ret)); - } - } else if (OB_FAIL(arr->push_back(dec_val->int32_v_[0]))) { - LOG_WARN("failed to push back decimal int32 value", K(ret), K(dec_val->int32_v_[0])); - } - } else if (get_decimalint_type(prec) == DECIMAL_INT_64) { - ObArrayFixedSize *arr = static_cast *>(arr_obj); - if (is_null) { - if (OB_FAIL(arr->push_back(0, true))) { - LOG_WARN("failed to push back null value", K(ret)); - } - } else if (OB_FAIL(arr->push_back(dec_val->int64_v_[0]))) { - LOG_WARN("failed to push back decimal int64 value", K(ret), K(dec_val->int64_v_[0])); - } - } else if (get_decimalint_type(prec) == DECIMAL_INT_128) { - ObArrayFixedSize *arr = static_cast *>(arr_obj); - if (is_null) { - if (OB_FAIL(arr->push_back(0, true))) { - LOG_WARN("failed to push back null value", K(ret)); - } - } else if (OB_FAIL(arr->push_back(dec_val->int128_v_[0]))) { - LOG_WARN("failed to push back decimal int128 value", K(ret), K(dec_val->int128_v_[0])); - } - } else if (get_decimalint_type(prec) == DECIMAL_INT_256) { - ObArrayFixedSize *arr = static_cast *>(arr_obj); - if (is_null) { - if (OB_FAIL(arr->push_back(0, true))) { - LOG_WARN("failed to push back null value", K(ret)); - } - } else if (OB_FAIL(arr->push_back(dec_val->int256_v_[0]))) { - LOG_WARN("failed to push back decimal int256 value", K(ret), K(dec_val->int256_v_[0])); - } - } else if (get_decimalint_type(prec) == DECIMAL_INT_512) { - ObArrayFixedSize *arr = static_cast *>(arr_obj); - if (is_null) { - if (OB_FAIL(arr->push_back(0, true))) { - LOG_WARN("failed to push back null value", K(ret)); - } - } else if (OB_FAIL(arr->push_back(dec_val->int512_v_[0]))) { - LOG_WARN("failed to push back decimal int512 value", K(ret), K(dec_val->int512_v_[0])); - } - } else { - ret = OB_ERR_UNEXPECTED; - OB_LOG(WARN, "unexpected precision", K(ret), K(prec)); - } - return ret; -} - -// convert collection bin to string (for liboblog) -int ObArrayUtil::convert_collection_bin_to_string(const ObString &collection_bin, - const common::ObIArray &extended_type_info, - common::ObIAllocator &allocator, - ObString &res_str) -{ - int ret = OB_SUCCESS; - if (OB_UNLIKELY(extended_type_info.count() != 1)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid extended type info for collection type", K(ret), K(extended_type_info.count())); - } else { - ObSqlCollectionInfo type_info_parse(allocator); - ObString collection_type_name = extended_type_info.at(0); - type_info_parse.set_name(collection_type_name); - if (OB_FAIL(type_info_parse.parse_type_info())) { - LOG_WARN("fail to parse type info", K(ret), K(collection_type_name)); - } else if (OB_ISNULL(type_info_parse.collection_meta_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("collection meta is null", K(ret), K(collection_type_name)); - } else { - ObCollectionArrayType *arr_type = nullptr; - ObIArrayType *arr_obj = nullptr; - ObStringBuffer buf(&allocator); - if (OB_ISNULL(arr_type = static_cast(type_info_parse.collection_meta_))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("collection meta is null", K(ret), K(collection_type_name)); - } else if (OB_FAIL(ObArrayTypeObjFactory::construct(allocator, *arr_type, arr_obj, true))) { - LOG_WARN("construct array obj failed", K(ret), K(type_info_parse)); - } else if (OB_ISNULL(arr_obj)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("arr_obj is null", K(ret), K(collection_type_name)); - } else { - ObString raw_binary = collection_bin; - if (OB_FAIL(arr_obj->init(raw_binary))) { - LOG_WARN("failed to init array", K(ret)); - } else if (OB_FAIL(arr_obj->print(arr_type->element_type_, buf))) { - LOG_WARN("failed to format array", K(ret)); - } else { - res_str.assign_ptr(buf.ptr(), buf.length()); - } - } - } - } - return ret; -} - -// determine a collection type is vector or array -int ObArrayUtil::get_mysql_type(const common::ObIArray &extended_type_info, - obmysql::EMySQLFieldType &type) -{ - int ret = OB_SUCCESS; - type = obmysql::MYSQL_TYPE_NOT_DEFINED; - ObArenaAllocator tmp_allocator("OB_ARRAY_UTIL"); - if (OB_UNLIKELY(extended_type_info.count() != 1)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid extended type info for collection type", K(ret), K(extended_type_info.count())); - } else { - ObSqlCollectionInfo type_info_parse(tmp_allocator); - ObString collection_type_name = extended_type_info.at(0); - type_info_parse.set_name(collection_type_name); - if (OB_FAIL(type_info_parse.parse_type_info())) { - LOG_WARN("fail to parse type info", K(ret), K(collection_type_name)); - } else if (OB_ISNULL(type_info_parse.collection_meta_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("collection meta is null", K(ret), K(collection_type_name)); - } else { - uint16_t detail_type = type_info_parse.collection_meta_->type_id_; - if (detail_type == OB_ARRAY_TYPE) { - type = obmysql::MYSQL_TYPE_OB_ARRAY; - } else if (detail_type == OB_VECTOR_TYPE) { - type = obmysql::MYSQL_TYPE_OB_VECTOR; - } else { - ret = OB_ERR_UNEXPECTED; - OB_LOG(WARN, "unexpected collection type", K(ret), K(detail_type)); - } - } - } - tmp_allocator.reset(); - return ret; -} - int ObVectorData::push_back(float value) { int ret = OB_SUCCESS; @@ -355,31 +192,42 @@ int ObVectorData::print(const ObCollectionTypeBase *elem_type, ObStringBuffer &f UNUSED(elem_type); if (OB_FAIL(format_str.append("["))) { OB_LOG(WARN, "fail to append [", K(ret)); - } else { - if (print_size == 0) { - // print whole array - print_size = length_; - } - for (int i = begin; i < begin + print_size && OB_SUCC(ret); i++) { - if (i > begin && OB_FAIL(format_str.append(","))) { - OB_LOG(WARN, "fail to append \",\" to buffer", K(ret)); + } else if (OB_FAIL(print_element(elem_type, format_str, begin, print_size))) { + OB_LOG(WARN, "fail to print vector element", K(ret)); + } else if (OB_SUCC(ret) && OB_FAIL(format_str.append("]"))) { + OB_LOG(WARN, "fail to append ]", K(ret)); + } + return ret; +} + +int ObVectorData::print_element(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, + uint32_t begin, uint32_t print_size, + ObString delimiter, bool has_null_str, ObString null_str) const +{ + int ret = OB_SUCCESS; + UNUSED(elem_type); + if (print_size == 0) { + // print whole array + print_size = length_; + } + bool is_first_elem = true; + for (int i = begin; i < begin + print_size && OB_SUCC(ret); i++) { + if (!is_first_elem && OB_FAIL(format_str.append(delimiter))) { + OB_LOG(WARN, "fail to append delimiter to buffer", K(ret), K(delimiter)); + } else { + is_first_elem = false; + int buf_size = FLOAT_TO_STRING_CONVERSION_BUFFER_SIZE; + if (OB_FAIL(format_str.reserve(buf_size + 1))) { + OB_LOG(WARN, "fail to reserve memory for format_str", K(ret)); } else { - int buf_size = FLOAT_TO_STRING_CONVERSION_BUFFER_SIZE; - if (OB_FAIL(format_str.reserve(buf_size + 1))) { - OB_LOG(WARN, "fail to reserve memory for format_str", K(ret)); - } else { - char *start = format_str.ptr() + format_str.length(); - uint64_t len = ob_gcvt(data_[i], ob_gcvt_arg_type::OB_GCVT_ARG_FLOAT, buf_size, start, NULL); - if (OB_FAIL(format_str.set_length(format_str.length() + len))) { - OB_LOG(WARN, "fail to set format_str len", K(ret), K(format_str.length()), K(len)); - } + char *start = format_str.ptr() + format_str.length(); + uint64_t len = ob_gcvt(data_[i], ob_gcvt_arg_type::OB_GCVT_ARG_FLOAT, buf_size, start, NULL); + if (OB_FAIL(format_str.set_length(format_str.length() + len))) { + OB_LOG(WARN, "fail to set format_str len", K(ret), K(format_str.length()), K(len)); } } } } - if (OB_SUCC(ret) && OB_FAIL(format_str.append("]"))) { - OB_LOG(WARN, "fail to append ]", K(ret)); - } return ret; } @@ -399,6 +247,17 @@ int ObVectorData::get_raw_binary(char *res_buf, int64_t buf_len) return ret; } +int ObVectorData::hash(uint64_t &hash_val) const +{ + float *data = this->data_; + if (this->data_container_ != NULL) { + data = this->data_container_->raw_data_.get_data(); + } + hash_val = common::murmurhash(&this->length_, sizeof(this->length_), hash_val); + hash_val = common::murmurhash(data, sizeof(float) * this->length_, hash_val); + return OB_SUCCESS; +} + int ObVectorData::init() { int ret = OB_SUCCESS; @@ -506,7 +365,7 @@ int ObVectorData::flatten(ObArrayAttr *attrs, uint32_t attr_count, uint32_t &att } int ObVectorData::compare_at(uint32_t left_begin, uint32_t left_len, uint32_t right_begin, uint32_t right_len, - const ObIArrayType &right, int &cmp_ret) + const ObIArrayType &right, int &cmp_ret) const { int ret = OB_SUCCESS; const ObVectorData *right_data = dynamic_cast(&right); @@ -528,11 +387,120 @@ int ObVectorData::compare_at(uint32_t left_begin, uint32_t left_len, uint32_t ri return ret; } -int ObVectorData::compare(const ObIArrayType &right, int &cmp_ret) +int ObVectorData::compare(const ObIArrayType &right, int &cmp_ret) const { return compare_at(0, this->length_, 0, right.size(), right, cmp_ret); } +int ObVectorData::contains_all(const ObIArrayType &other, bool &bret) const +{ + int ret = OB_SUCCESS; + const ObVectorData *right_data = dynamic_cast(&other); + if (OB_ISNULL(right_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(other.get_format()), K(this->get_format())); + } else { + bret = true; + for (uint32_t i = 0; i < other.size() && bret && OB_SUCC(ret); ++i) { + int pos = -1; + if (OB_FAIL(this->contains((*right_data)[i], pos))) { + OB_LOG(WARN, "check element contains failed", K(ret), K(i), K((*right_data)[i])); + } else if (pos < 0) { + bret = false; + } + } + } + return ret; +} + +int ObVectorData::overlaps(const ObIArrayType &other, bool &bret) const +{ + int ret = OB_SUCCESS; + const ObVectorData *right_data = dynamic_cast(&other); + if (OB_ISNULL(right_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(other.get_format()), K(this->get_format())); + } else { + bret = false; + for (uint32_t i = 0; i < other.size() && !bret && OB_SUCC(ret); ++i) { + int pos = -1; + if (OB_FAIL(this->contains((*right_data)[i], pos))) { + OB_LOG(WARN, "check element contains failed", K(ret), K(i), K((*right_data)[i])); + } else if (pos >= 0) { + bret = true; + } + } + } + return ret; +} + +int ObVectorData::clone_empty(ObIAllocator &alloc, ObIArrayType *&output, bool read_only) const +{ + int ret = OB_SUCCESS; + void *buf = alloc.alloc(sizeof(ObVectorData)); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "alloc memory failed", K(ret)); + } else { + ObVectorData *arr_ptr = new (buf) ObVectorData(); + if (read_only) { + } else if (OB_ISNULL(buf = alloc.alloc(sizeof(ObArrayData)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "alloc memory failed", K(ret)); + } else { + ObArrayData *arr_data = new (buf) ObArrayData(alloc); + arr_ptr->set_array_data(arr_data); + arr_ptr->set_element_type(this->element_type_); + } + if (OB_SUCC(ret)) { + output = arr_ptr; + } + } + return ret; +} + +int ObVectorData::distinct(ObIAllocator &alloc, ObIArrayType *&output) const +{ + int ret = OB_SUCCESS; + ObIArrayType *arr_ptr = NULL; + if (OB_FAIL(clone_empty(alloc, arr_ptr, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else { + hash::ObHashSet elem_set; + ObVectorData *vec_ptr = dynamic_cast(arr_ptr); + if (OB_ISNULL(vec_ptr)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(arr_ptr->get_format())); + } else if (OB_FAIL(elem_set.create(this->length_, ObMemAttr(common::OB_SERVER_TENANT_ID, "ArrayDistSet")))) { + OB_LOG(WARN, "failed to create cellid set", K(ret), K(this->length_)); + } else { + for (uint32_t i = 0; i < this->length_ && OB_SUCC(ret); ++i) { + ObString val(sizeof(data_[i]), reinterpret_cast(&data_[i])); + if (OB_FAIL(elem_set.exist_refactored(val))) { + if (ret == OB_HASH_NOT_EXIST) { + if (OB_FAIL(vec_ptr->push_back(data_[i]))) { + OB_LOG(WARN, "failed to add elemen", K(ret)); + } else if (OB_FAIL(elem_set.set_refactored(val))) { + OB_LOG(WARN, "failed to add elemen into set", K(ret)); + } + } else if (ret == OB_HASH_EXIST) { + // duplicate element, do nothing + ret = OB_SUCCESS; + } else { + OB_LOG(WARN, "failed to check element exist", K(ret)); + } + } else { + // do nothing + } + } + } + if (OB_SUCC(ret)) { + output = arr_ptr; + } + } + return ret; +} + int ObArrayBinary::push_back(const ObString &value, bool is_null) { int ret = OB_SUCCESS; @@ -670,6 +638,24 @@ int ObArrayBinary::get_raw_binary(char *res_buf, int64_t buf_len) return ret; } +int ObArrayBinary::hash(uint64_t &hash_val) const +{ + uint8_t *null_bitmaps = this->null_bitmaps_; + uint32_t *offsets = offsets_; + char *data = this->data_; + uint32_t last_idx = length_ > 0 ? length_ - 1 : 0; + if (this->data_container_ != NULL) { + null_bitmaps = this->data_container_->null_bitmaps_.get_data(); + offsets = data_container_->offsets_.get_data(); + data = this->data_container_->raw_data_.get_data(); + } + hash_val = common::murmurhash(&length_, sizeof(length_), hash_val); + hash_val = common::murmurhash(null_bitmaps, sizeof(uint8_t) * this->length_, hash_val); + hash_val = common::murmurhash(offsets, sizeof(uint32_t) * this->length_, hash_val); + hash_val = common::murmurhash(data, offsets_[last_idx], hash_val); + return OB_SUCCESS; +} + int ObArrayBinary::init() { int ret = OB_SUCCESS; @@ -811,6 +797,38 @@ int ObArrayBinary::print(const ObCollectionTypeBase *elem_type, ObStringBuffer & return ret; } +int ObArrayBinary::print_element(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, + uint32_t begin, uint32_t print_size, + ObString delimiter, bool has_null_str, ObString null_str) const +{ + int ret = OB_SUCCESS; + UNUSED(elem_type); + if (print_size == 0) { + // print whole array + print_size = length_; + } + bool is_first_elem = true; + for (int i = begin; i < begin + print_size && OB_SUCC(ret); i++) { + if (this->null_bitmaps_[i] && !has_null_str) { + // do nothing + } else if (!is_first_elem && OB_FAIL(format_str.append(delimiter))) { + OB_LOG(WARN, "fail to append delimiter to buffer", K(ret), K(delimiter)); + } else if (this->null_bitmaps_[i]) { + // value is null + is_first_elem = false; + if (OB_FAIL(format_str.append(null_str))) { + OB_LOG(WARN, "fail to append null string to buffer", K(ret), K(null_str)); + } + } else { + is_first_elem = false; + if (OB_FAIL(format_str.append((*this)[i]))) { + OB_LOG(WARN, "fail to append string to format_str", K(ret)); + } + } + } + return ret; +} + void ObArrayBinary::clear() { data_ = nullptr; @@ -845,7 +863,7 @@ int ObArrayBinary::flatten(ObArrayAttr *attrs, uint32_t attr_count, uint32_t &at int ObArrayBinary::compare_at(uint32_t left_begin, uint32_t left_len, uint32_t right_begin, uint32_t right_len, - const ObIArrayType &right, int &cmp_ret) + const ObIArrayType &right, int &cmp_ret) const { int ret = OB_SUCCESS; uint32_t cmp_len = std::min(left_len, right_len); @@ -880,11 +898,131 @@ int ObArrayBinary::compare_at(uint32_t left_begin, uint32_t left_len, return ret; } -int ObArrayBinary::compare(const ObIArrayType &right, int &cmp_ret) +int ObArrayBinary::compare(const ObIArrayType &right, int &cmp_ret) const { return compare_at(0, length_, 0, right.size(), right, cmp_ret); } +int ObArrayBinary::contains_all(const ObIArrayType &other, bool &bret) const +{ + int ret = OB_SUCCESS; + const ObArrayBinary *right_data = dynamic_cast(&other); + if (OB_ISNULL(right_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(other.get_format()), K(this->get_format())); + } else if (other.contain_null() && !this->contain_null()) { + bret = false; + } else { + bret = true; + for (uint32_t i = 0; i < other.size() && bret && OB_SUCC(ret); ++i) { + int pos = -1; + if (right_data->is_null(i)) { + // do nothings, checked already + } else if (OB_FAIL(this->contains((*right_data)[i], pos))) { + OB_LOG(WARN, "check element contains failed", K(ret), K(i), K((*right_data)[i])); + } else if (pos < 0) { + bret = false; + } + } + } + return ret; +} + +int ObArrayBinary::overlaps(const ObIArrayType &other, bool &bret) const +{ + int ret = OB_SUCCESS; + const ObArrayBinary *right_data = dynamic_cast(&other); + if (OB_ISNULL(right_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(other.get_format()), K(this->get_format())); + } else if (other.contain_null() && this->contain_null()) { + bret = true; + } else { + bret = false; + for (uint32_t i = 0; i < other.size() && !bret && OB_SUCC(ret); ++i) { + int pos = -1; + if (right_data->is_null(i)) { + // do nothings, checked already + } else if (OB_FAIL(this->contains((*right_data)[i], pos))) { + OB_LOG(WARN, "check element contains failed", K(ret), K(i), K((*right_data)[i])); + } else if (pos >= 0) { + bret = true; + } + } + } + return ret; +} + +int ObArrayBinary::clone_empty(ObIAllocator &alloc, ObIArrayType *&output, bool read_only) const +{ + int ret = OB_SUCCESS; + void *buf = alloc.alloc(sizeof(ObArrayBinary)); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "alloc memory failed", K(ret)); + } else { + ObArrayBinary *arr_ptr = new (buf) ObArrayBinary(); + if (read_only) { + } else if (OB_ISNULL(buf = alloc.alloc(sizeof(ObArrayData)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "alloc memory failed", K(ret)); + } else { + ObArrayData *arr_data = new (buf) ObArrayData(alloc); + arr_ptr->set_array_data(arr_data); + arr_ptr->set_element_type(this->element_type_); + } + if (OB_SUCC(ret)) { + output = arr_ptr; + } + } + return ret; +} + +int ObArrayBinary::distinct(ObIAllocator &alloc, ObIArrayType *&output) const +{ + int ret = OB_SUCCESS; + ObIArrayType *arr_ptr = NULL; + if (OB_FAIL(clone_empty(alloc, arr_ptr, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else if (this->contain_null() && OB_FAIL(arr_ptr->push_null())) { + OB_LOG(WARN, "push null failed", K(ret)); + } else { + hash::ObHashSet elem_set; + ObArrayBinary *arr_bin_ptr = dynamic_cast(arr_ptr); + if (OB_ISNULL(arr_bin_ptr)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(arr_ptr->get_format())); + } else if (OB_FAIL(elem_set.create(this->length_, ObMemAttr(common::OB_SERVER_TENANT_ID, "ArrayDistSet")))) { + OB_LOG(WARN, "failed to create cellid set", K(ret), K(this->length_)); + } else { + for (uint32_t i = 0; i < this->length_ && OB_SUCC(ret); ++i) { + if (this->is_null(i)) { + // do nothing + } else if (OB_FAIL(elem_set.exist_refactored((*this)[i]))) { + if (ret == OB_HASH_NOT_EXIST) { + if (OB_FAIL(arr_bin_ptr->push_back((*this)[i]))) { + OB_LOG(WARN, "failed to add elemen", K(ret)); + } else if (OB_FAIL(elem_set.set_refactored((*this)[i]))) { + OB_LOG(WARN, "failed to add elemen into set", K(ret)); + } + } else if (ret == OB_HASH_EXIST) { + // duplicate element, do nothing + ret = OB_SUCCESS; + } else { + OB_LOG(WARN, "failed to check element exist", K(ret)); + } + } else { + // do nothing + } + } + } + if (OB_SUCC(ret)) { + output = arr_ptr; + } + } + return ret; +} + int ObArrayNested::get_data_binary(char *res_buf, int64_t buf_len) { int ret = OB_SUCCESS; @@ -927,6 +1065,21 @@ int ObArrayNested::get_raw_binary(char *res_buf, int64_t buf_len) return ret; } +int ObArrayNested::hash(uint64_t &hash_val) const +{ + uint8_t *null_bitmaps = this->null_bitmaps_; + uint32_t *offsets = offsets_; + if (this->data_container_ != NULL) { + null_bitmaps = this->data_container_->null_bitmaps_.get_data(); + offsets = data_container_->offsets_.get_data(); + } + hash_val = common::murmurhash(&length_, sizeof(length_), hash_val); + hash_val = common::murmurhash(null_bitmaps, sizeof(uint8_t) * length_, hash_val); + hash_val = common::murmurhash(offsets, sizeof(uint32_t) * length_, hash_val); + data_->hash(hash_val); + return OB_SUCCESS; +} + int ObArrayNested::insert_from(const ObIArrayType &src, uint32_t begin, uint32_t len) { int ret = OB_SUCCESS; @@ -1092,6 +1245,45 @@ int ObArrayNested::print(const ObCollectionTypeBase *elem_type, ObStringBuffer & return ret; } +int ObArrayNested::print_element(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, + uint32_t begin, uint32_t print_size, + ObString delimiter, bool has_null_str, ObString null_str) const +{ + int ret = OB_SUCCESS; + const ObCollectionArrayType *array_type = dynamic_cast(elem_type); + if (OB_ISNULL(array_type)) { + ret = OB_INVALID_ARGUMENT; + OB_LOG(WARN, "invalid argument", K(ret)); + } else { + if (print_size == 0) { + // print whole array + print_size = length_; + } + bool is_first_elem = true; + for (int i = begin; i < begin + print_size && OB_SUCC(ret); i++) { + if (this->null_bitmaps_[i] && !has_null_str) { + // do nothing + } else if (!is_first_elem && OB_FAIL(format_str.append(delimiter))) { + OB_LOG(WARN, "fail to append delimiter to buffer", K(ret), K(delimiter)); + } else if (this->null_bitmaps_[i]) { + // value is null + is_first_elem = false; + if (OB_FAIL(format_str.append(null_str))) { + OB_LOG(WARN, "fail to append null string to buffer", K(ret), K(null_str)); + } + } else { + is_first_elem = false; + uint32_t start = offset_at(i, offsets_); + uint32_t elem_cnt = offsets_[i] - start; + if (OB_FAIL(data_->print_element(array_type->element_type_, format_str, start, elem_cnt, delimiter, null_str))) { + OB_LOG(WARN, "fail to append string to format_str", K(ret)); + } + } + } + } + return ret; +} + int ObArrayNested::push_back(const ObIArrayType &src, bool is_null) { int ret = OB_SUCCESS; @@ -1168,7 +1360,7 @@ void ObArrayNested::clear() } } -int ObArrayNested::at(uint32_t idx, ObIArrayType &dest) +int ObArrayNested::at(uint32_t idx, ObIArrayType &dest) const { int ret = OB_SUCCESS; uint32_t start = offset_at(idx, get_offsets()); @@ -1205,7 +1397,7 @@ int ObArrayNested::flatten(ObArrayAttr *attrs, uint32_t attr_count, uint32_t &at int ObArrayNested::compare_at(uint32_t left_begin, uint32_t left_len, uint32_t right_begin, uint32_t right_len, - const ObIArrayType &right, int &cmp_ret) + const ObIArrayType &right, int &cmp_ret) const { int ret = OB_SUCCESS; uint32_t cmp_len = std::min(left_len, right_len); @@ -1236,11 +1428,177 @@ int ObArrayNested::compare_at(uint32_t left_begin, uint32_t left_len, return ret; } -int ObArrayNested::compare(const ObIArrayType &right, int &cmp_ret) +int ObArrayNested::compare(const ObIArrayType &right, int &cmp_ret) const { return compare_at(0, length_, 0, right.size(), right, cmp_ret); } +int ObArrayNested::contains_all(const ObIArrayType &other, bool &bret) const +{ + int ret = OB_SUCCESS; + if (other.contain_null() && !this->contain_null()) { + bret = false; + } else { + bret = true; + for (uint32_t i = 0; i < other.size() && bret && OB_SUCC(ret); ++i) { + if (other.is_null(i)) { + // do nothings, checked already + } else { + const ObArrayNested *right_data = dynamic_cast(&other); + uint32_t r_start = right_data->offset_at(i, right_data->get_offsets()); + uint32_t r_child_len = right_data->get_offsets()[i] - r_start; + bool found = false; + for (uint32_t j = 0; j < length_ && !found && OB_SUCC(ret); ++j) { + uint32_t l_start = offset_at(j, get_offsets()); + uint32_t l_child_len = get_offsets()[j] - l_start; + int cmp_ret = 0; + if (OB_FAIL(get_child_array()->compare_at(l_start, l_child_len, r_start, r_child_len, + *right_data->get_child_array(), + cmp_ret))) { + OB_LOG(WARN, "failed to do nested array contains", K(ret)); + } else if (cmp_ret == 0) { + found = true; + } + } + if (OB_SUCC(ret) && !found) { + bret = false; + } + } + } + } + return ret; +} + +int ObArrayNested::overlaps(const ObIArrayType &other, bool &bret) const +{ + int ret = OB_SUCCESS; + if (other.contain_null() && this->contain_null()) { + bret = true; + } else { + bret = false; + for (uint32_t i = 0; i < other.size() && !bret && OB_SUCC(ret); ++i) { + if (other.is_null(i)) { + // do nothings, checked already + } else { + const ObArrayNested *right_data = dynamic_cast(&other); + uint32_t r_start = right_data->offset_at(i, right_data->get_offsets()); + uint32_t r_child_len = right_data->get_offsets()[i] - r_start; + for (uint32_t j = 0; j < length_ && !bret; ++j) { + uint32_t l_start = offset_at(j, get_offsets()); + uint32_t l_child_len = get_offsets()[j] - l_start; + int cmp_ret = 0; + if (OB_FAIL(get_child_array()->compare_at(l_start, l_child_len, r_start, r_child_len, + *right_data->get_child_array(), + cmp_ret))) { + OB_LOG(WARN, "failed to do nested array contains", K(ret)); + } else if (cmp_ret == 0) { + bret = true; + } + } + } + } + } + return ret; +} + +int ObArrayNested::clone_empty(ObIAllocator &alloc, ObIArrayType *&output, bool read_only) const +{ + int ret = OB_SUCCESS; + void *buf = alloc.alloc(sizeof(ObArrayNested)); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "alloc memory failed", K(ret)); + } else { + ObArrayNested *arr_ptr = new (buf) ObArrayNested(); + if (read_only) { + } else if (OB_ISNULL(buf = alloc.alloc(sizeof(ObArrayData)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "alloc memory failed", K(ret)); + } else { + ObArrayData *arr_data = new (buf) ObArrayData(alloc); + arr_ptr->set_array_data(arr_data); + } + if (OB_SUCC(ret)) { + ObIArrayType *arr_child = NULL; + if (OB_FAIL(get_child_array()->clone_empty(alloc, arr_child, read_only))) { + OB_LOG(WARN, "failed to clone child empty array", K(ret)); + } else { + arr_ptr->set_element_type(this->element_type_); + arr_ptr->set_child_array(arr_child); + output = arr_ptr; + } + } + } + return ret; +} + +int ObArrayNested::distinct(ObIAllocator &alloc, ObIArrayType *&output) const +{ + int ret = OB_SUCCESS; + ObIArrayType *arr_obj = NULL; + if (OB_FAIL(clone_empty(alloc, arr_obj, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else if (contain_null() && OB_FAIL(arr_obj->push_null())) { + OB_LOG(WARN, "push null failed", K(ret)); + } else { + hash::ObHashMap elem_set; + ObIArrayType *inner_arr = get_child_array(); + ObIArrayType *child_obj = NULL; + ObIArrayType *check_obj = NULL; + ObArrayNested *arr_obj_ptr = dynamic_cast(arr_obj); + if (OB_ISNULL(arr_obj_ptr)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(inner_arr->get_format())); + } else if (OB_FAIL(elem_set.create(length_, ObMemAttr(common::OB_SERVER_TENANT_ID, "ArrayDistSet")))) { + OB_LOG(WARN, "failed to create cellid set", K(ret), K(length_)); + } else if (OB_FAIL(inner_arr->clone_empty(alloc, child_obj, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else { + for (uint32_t i = 0; i < length_ && OB_SUCC(ret); ++i) { + uint32_t idx = 0; + uint64_t hash_val = 0; + if (is_null(i)) { + // do nothing + } else if (OB_FAIL(at(i, *child_obj))) { + OB_LOG(WARN, "get element failed", K(ret), K(i), K(length_)); + } else if (OB_FAIL(child_obj->hash(hash_val))) { + OB_LOG(WARN, "get element hash value failed", K(ret), K(i), K(length_)); + } else if (OB_FAIL(elem_set.get_refactored(hash_val, idx))) { + if (ret == OB_HASH_NOT_EXIST) { + if (OB_FAIL(arr_obj_ptr->push_back(*child_obj))) { + OB_LOG(WARN, "failed to add elemen", K(ret)); + } else if (OB_FAIL(elem_set.set_refactored(hash_val, i))) { + OB_LOG(WARN, "failed to add elemen into set", K(ret)); + } + } else if (ret == OB_HASH_EXIST) { + // duplicate element, double check + if (check_obj == NULL && OB_FAIL(inner_arr->clone_empty(alloc, check_obj, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else if (OB_FAIL(at(i, *check_obj))) { + OB_LOG(WARN, "get element failed", K(ret), K(i), K(length_)); + } else if ((*check_obj) == (*child_obj)) { + // do nothing + } else if (OB_FAIL(arr_obj_ptr->push_back(*child_obj))) { + OB_LOG(WARN, "failed to add elemen", K(ret)); + } else { + check_obj->clear(); + } + } else { + OB_LOG(WARN, "failed to check element exist", K(ret)); + } + } + if (child_obj != NULL) { + child_obj->clear(); + } + } + } + if (OB_SUCC(ret)) { + output = arr_obj; + } + } + return ret; +} + #undef CONSTRUCT_ARRAY_OBJ #undef CONSTRUCT_FIXED_ARRAY_OBJ diff --git a/deps/oblib/src/lib/udt/ob_array_type.h b/deps/oblib/src/lib/udt/ob_array_type.h index b5adfd5015..e9f74982cb 100644 --- a/deps/oblib/src/lib/udt/ob_array_type.h +++ b/deps/oblib/src/lib/udt/ob_array_type.h @@ -17,6 +17,7 @@ #include "lib/string/ob_string.h" #include "lib/container/ob_vector.h" #include "lib/container/ob_array_iterator.h" +#include "lib/hash/ob_hashset.h" #include "lib/udt/ob_collection_type.h" #include "lib/string/ob_string_buffer.h" #include "lib/wide_integer/ob_wide_integer_str_funcs.h" @@ -25,7 +26,6 @@ #include "rpc/obmysql/ob_mysql_global.h" // DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE #include "src/share/datum/ob_datum.h" - namespace oceanbase { namespace common { @@ -43,6 +43,11 @@ struct ObArrayAttr { uint32_t length_; }; +OB_INLINE bool ob_is_array_supported_type(ObObjType type) +{ + return ObUNumberType >= type || ObVarcharType == type || ObCharType == type || ObDecimalIntType == type; +} + template class ObArrayData { public : @@ -77,6 +82,9 @@ class ObIArrayType { public: virtual int print(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, uint32_t begin = 0, uint32_t print_size = 0) const = 0; + virtual int print_element(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, + uint32_t begin = 0, uint32_t print_size = 0, + ObString delimiter = ObString(","), bool has_null_str = true, ObString null_str = ObString("NULL")) const = 0; virtual int32_t get_raw_binary_len() = 0; virtual int get_raw_binary(char *res_buf, int64_t buf_len) = 0; // without length_ @@ -88,6 +96,7 @@ public: virtual void set_scale(ObScale scale) = 0; // only for decimalint array virtual ArrayFormat get_format() const = 0; virtual uint32_t size() const = 0; + virtual uint32_t cardinality() const = 0; virtual int check_validity(const ObCollectionArrayType &arr_type, const ObIArrayType &array) const = 0; virtual bool is_null(uint32_t idx) const = 0; // check if the idx-th element is null or not, idx validity is guaranteed by caller virtual int push_null() = 0; @@ -98,15 +107,21 @@ public: virtual uint32_t *get_offsets() const = 0; virtual uint8_t *get_nullbitmap() const = 0; virtual void set_element_type(int32_t type) = 0; - virtual int at(uint32_t idx, ObIArrayType &dest) = 0; + virtual int at(uint32_t idx, ObIArrayType &dest) const = 0; virtual void clear() = 0; virtual int flatten(ObArrayAttr *attrs, uint32_t attr_count, uint32_t &attr_idx) = 0; virtual int set_null_bitmaps(uint8_t *nulls, int64_t length) = 0; virtual int set_offsets(uint32_t *offsets, int64_t length) = 0; - virtual int compare(const ObIArrayType &right, int &cmp_ret) = 0; + virtual int compare(const ObIArrayType &right, int &cmp_ret) const = 0; virtual int compare_at(uint32_t left_begin, uint32_t left_len, uint32_t right_begin, uint32_t right_len, - const ObIArrayType &right, int &cmp_ret) = 0; + const ObIArrayType &right, int &cmp_ret) const = 0; + virtual int contains_all(const ObIArrayType &other, bool &bret) const = 0; + virtual int overlaps(const ObIArrayType &other, bool &bret) const = 0; + virtual int hash(uint64_t &hash_val) const = 0; + virtual bool operator ==(const ObIArrayType &other) const = 0; + virtual int clone_empty(ObIAllocator &alloc, ObIArrayType *&output, bool read_only = true) const = 0; + virtual int distinct(ObIAllocator &alloc, ObIArrayType *&output) const = 0; }; template @@ -189,6 +204,17 @@ public : return ret; } + bool operator ==(const ObIArrayType &other) const + { + bool b_ret = false; + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (OB_SUCC(compare(other, cmp_ret))) { + b_ret = (cmp_ret == 0); + } + return b_ret; + } + protected : uint32_t length_; int32_t element_type_; @@ -207,6 +233,7 @@ public : inline int16_t get_scale() { return scale_; } void set_scale(ObScale scale) { scale_ = scale; } // only for decimalint array T operator[](const int64_t i) const { return data_[i]; } + uint32_t cardinality() const { return this->length_; } ObDecimalInt *get_decimal_int(const int64_t i) { return (ObDecimalInt *)(data_ + i); } ArrayFormat get_format() const { return ArrayFormat::Fixed_Size; } uint32_t *get_offsets() const { return nullptr; } @@ -266,29 +293,47 @@ public : int print(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, uint32_t begin = 0, uint32_t print_size = 0) const + { + int ret = OB_SUCCESS; + if (OB_FAIL(format_str.append("["))) { + OB_LOG(WARN, "fail to append [", K(ret)); + } else if (OB_FAIL(print_element(elem_type, format_str, begin, print_size))) { + OB_LOG(WARN, "fail to print element", K(ret)); + } else if (OB_FAIL(format_str.append("]"))) { + OB_LOG(WARN, "fail to append ]", K(ret)); + } + return ret; + } + int print_element(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, + uint32_t begin = 0, uint32_t print_size = 0, + ObString delimiter = ObString(","), + bool has_null_str = true, ObString null_str = ObString("NULL")) const { int ret = OB_SUCCESS; const ObCollectionBasicType *basic_type = dynamic_cast(elem_type); if (OB_ISNULL(basic_type)) { ret = OB_INVALID_ARGUMENT; OB_LOG(WARN, "invalid argument", K(ret)); - } else if (OB_FAIL(format_str.append("["))) { - OB_LOG(WARN, "fail to append [", K(ret)); } else { if (print_size == 0) { // print whole element print_size = this->length_; } ObObjType obj_type = basic_type->basic_meta_.get_obj_type(); + bool is_first_elem = true; for (int i = begin; i < begin + print_size && OB_SUCC(ret); i++) { - if (i > begin && OB_FAIL(format_str.append(","))) { - OB_LOG(WARN, "fail to append \",\" to buffer", K(ret)); + if (this->null_bitmaps_[i] && !has_null_str) { + // do nothing + } else if (!is_first_elem && OB_FAIL(format_str.append(delimiter))) { + OB_LOG(WARN, "fail to append delimiter to buffer", K(ret), K(delimiter)); } else if (this->null_bitmaps_[i]) { // value is null - if (OB_FAIL(format_str.append("NULL"))) { - OB_LOG(WARN, "fail to append NULL to buffer", K(ret)); + is_first_elem = false; + if (OB_FAIL(format_str.append(null_str))) { + OB_LOG(WARN, "fail to append null string to buffer", K(ret), K(null_str)); } } else { + is_first_elem = false; switch (obj_type) { case ObTinyIntType: case ObSmallIntType: @@ -312,8 +357,8 @@ public : } break; } - case ObFloatType : - case ObDoubleType : { + case ObFloatType: + case ObDoubleType: { int buf_size = obj_type == ObFloatType ? FLOAT_TO_STRING_CONVERSION_BUFFER_SIZE : DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE; if (OB_FAIL(format_str.reserve(buf_size + 1))) { OB_LOG(WARN, "fail to reserve memory for format_str", K(ret)); @@ -328,7 +373,7 @@ public : } break; } - case ObDecimalIntType : { + case ObDecimalIntType: { int64_t pos = 0; char tmp_buf[ObFastFormatInt::MAX_DIGITS10_STR_SIZE] = {0}; if (OB_FAIL(wide::to_string(reinterpret_cast(&data_[i]), sizeof(data_[i]), scale_, @@ -347,13 +392,9 @@ public : } } } - if (OB_SUCC(ret) && OB_FAIL(format_str.append("]"))) { - OB_LOG(WARN, "fail to append ]", K(ret)); - } return ret; } - int32_t get_data_binary_len() { if (this->data_container_ == NULL) { @@ -398,6 +439,20 @@ public : return ret; } + int hash(uint64_t &hash_val) const + { + uint8_t *null_bitmaps = this->null_bitmaps_; + T *data = this->data_; + if (this->data_container_ != NULL) { + null_bitmaps = this->data_container_->null_bitmaps_.get_data(); + data = this->data_container_->raw_data_.get_data(); + } + hash_val = common::murmurhash(&this->length_, sizeof(this->length_), hash_val); + hash_val = common::murmurhash(null_bitmaps, sizeof(uint8_t) * this->length_, hash_val); + hash_val = common::murmurhash(data, sizeof(T) * this->length_, hash_val); + return OB_SUCCESS; + } + int init() { int ret = OB_SUCCESS; @@ -498,7 +553,7 @@ public : } return ret; } - int at(uint32_t idx, ObIArrayType &dest) { return OB_NOT_SUPPORTED; } + int at(uint32_t idx, ObIArrayType &dest) const { return OB_NOT_SUPPORTED; } void clear() { data_ = nullptr; @@ -527,7 +582,7 @@ public : } int compare_at(uint32_t left_begin, uint32_t left_len, uint32_t right_begin, uint32_t right_len, - const ObIArrayType &right, int &cmp_ret) + const ObIArrayType &right, int &cmp_ret) const { int ret = OB_SUCCESS; const ObArrayFixedSize *right_data = dynamic_cast *>(&right); @@ -554,34 +609,197 @@ public : return ret; } - int compare(const ObIArrayType &right, int &cmp_ret) + int compare(const ObIArrayType &right, int &cmp_ret) const { return compare_at(0, this->length_, 0, right.size(), right, cmp_ret); } template - int contains(const Elem_Type &elem, bool &bret) const + int contains(const Elem_Type &elem, int &pos) const { int ret = OB_SUCCESS; - bret = false; - for (uint32_t i = 0; i < this->length_ && !bret; ++i) { + pos = -1; + for (uint32_t i = 0; i < this->length_ && pos < 0; ++i) { if (this->is_null(i)) { } else if (static_cast(this->data_[i]) == elem) { - bret = true; + pos = i; } } return ret; } template <> - int contains(const ObString &elem, bool &bret) const + int contains(const ObString &elem, int &pos) const { return OB_INVALID_ARGUMENT; } template <> - int contains(const ObIArrayType &elem, bool &bret) const + int contains(const ObIArrayType &elem, int &pos) const { return OB_INVALID_ARGUMENT; } + int contains_all(const ObIArrayType &other, bool &bret) const + { + int ret = OB_SUCCESS; + const ObArrayFixedSize *right_data = dynamic_cast *>(&other); + if (OB_ISNULL(right_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(other.get_format()), K(this->get_format())); + } else if (other.contain_null() && !this->contain_null()) { + bret = false; + } else { + bret = true; + for (uint32_t i = 0; i < other.size() && bret && OB_SUCC(ret); ++i) { + int pos = -1; + if (right_data->is_null(i)) { + // do nothings, checked already + } else if (OB_FAIL(this->contains((*right_data)[i], pos))) { + OB_LOG(WARN, "check element contains failed", K(ret), K(i), K((*right_data)[i])); + } else if (pos < 0) { + bret = false; + } + } + } + return ret; + } + + int overlaps(const ObIArrayType &other, bool &bret) const + { + int ret = OB_SUCCESS; + const ObArrayFixedSize *right_data = dynamic_cast *>(&other); + if (OB_ISNULL(right_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(other.get_format()), K(this->get_format())); + } else if (other.contain_null() && this->contain_null()) { + bret = true; + } else { + bret = false; + for (uint32_t i = 0; i < other.size() && !bret && OB_SUCC(ret); ++i) { + int pos = -1; + if (right_data->is_null(i)) { + // do nothings, checked already + } else if (OB_FAIL(this->contains((*right_data)[i], pos))) { + OB_LOG(WARN, "check element contains failed", K(ret), K(i), K((*right_data)[i])); + } else if (pos >= 0) { + bret = true; + } + } + } + return ret; + } + + int clone_empty(ObIAllocator &alloc, ObIArrayType *&output, bool read_only = true) const + { + int ret = OB_SUCCESS; + void *buf = alloc.alloc(sizeof(ObArrayFixedSize)); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "alloc memory failed", K(ret)); + } else { + ObArrayFixedSize *arr_ptr = new (buf) ObArrayFixedSize(); + if (read_only) { + } else if (OB_ISNULL(buf = alloc.alloc(sizeof(ObArrayData)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "alloc memory failed", K(ret)); + } else { + ObArrayData *arr_data = new (buf) ObArrayData(alloc); + arr_ptr->set_array_data(arr_data); + arr_ptr->set_element_type(this->element_type_); + } + if (OB_SUCC(ret)) { + output = arr_ptr; + } + } + return ret; + } + + template + int clone_except(ObIAllocator &alloc, const Elem_Type *elem_except, bool is_null, ObIArrayType *&output) const + { + int ret = OB_SUCCESS; + if (OB_FAIL(clone_empty(alloc, output, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else { + ObArrayFixedSize *arr_data = dynamic_cast *>(output); + if (OB_ISNULL(arr_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(this->get_format())); + } + for (uint32_t i = 0; i < this->length_ && OB_SUCC(ret); ++i) { + if (is_null) { + if (this->is_null(i)) { + // do nothing + } else if (OB_FAIL(arr_data->push_back((*this)[i]))) { + OB_LOG(WARN, "push null failed", K(ret)); + } + } else if (this->is_null(i)) { + if (OB_FAIL(arr_data->push_null())) { + OB_LOG(WARN, "push null failed", K(ret)); + } + } else if ((*this)[i] != *elem_except && OB_FAIL(arr_data->push_back((*this)[i]))) { + OB_LOG(WARN, "failed to add element", K(ret)); + } + } + } + return ret; + } + template <> + int clone_except(ObIAllocator &alloc, const ObString *elem_except, bool is_null, ObIArrayType *&output) const + { + return OB_INVALID_ARGUMENT; + } + template <> + int clone_except(ObIAllocator &alloc, const ObIArrayType *elem_except, bool is_null, ObIArrayType *&output) const + { + return OB_INVALID_ARGUMENT; + } + + int distinct(ObIAllocator &alloc, ObIArrayType *&output) const + { + int ret = OB_SUCCESS; + ObIArrayType *arr_ptr = NULL; + if (OB_FAIL(clone_empty(alloc, arr_ptr, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else if (this->contain_null() && OB_FAIL(arr_ptr->push_null())) { + OB_LOG(WARN, "push null failed", K(ret)); + } else { + hash::ObHashSet elem_set; + ObArrayFixedSize *arr_data = dynamic_cast *>(arr_ptr); + if (OB_ISNULL(arr_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(this->get_format())); + } else if (OB_FAIL(elem_set.create(this->length_, ObMemAttr(common::OB_SERVER_TENANT_ID, "ArrayDistSet")))) { + OB_LOG(WARN, "failed to create cellid set", K(ret)); + } else { + for (uint32_t i = 0; i < this->length_ && OB_SUCC(ret); ++i) { + ObString val; + if (this->is_null(i)) { + // do nothing + } else if (FALSE_IT(val.assign_ptr(reinterpret_cast(&data_[i]), sizeof(T)))) { + } else if (OB_FAIL(elem_set.exist_refactored(val))) { + if (ret == OB_HASH_NOT_EXIST) { + if (OB_FAIL(arr_data->push_back((*this)[i]))) { + OB_LOG(WARN, "failed to add element", K(ret)); + } else if (OB_FAIL(elem_set.set_refactored(val))) { + OB_LOG(WARN, "failed to add element into set", K(ret)); + } + } else if (ret == OB_HASH_EXIST) { + // duplicate element, do nothing + ret = OB_SUCCESS; + } else { + OB_LOG(WARN, "failed to check element exist", K(ret)); + } + } else { + // do nothing + } + } + } + if (OB_SUCC(ret)) { + output = arr_ptr; + } + } + return ret; + } + private : T *data_; int16_t scale_; // only for decimalint type @@ -594,11 +812,16 @@ public : : ObArrayBase(length, ObFloatType, nullptr), data_(data) {} float operator[](const int64_t i) const { return data_[i]; } + uint32_t cardinality() const { return this->length_; } ArrayFormat get_format() const { return ArrayFormat::Vector; } int push_back(float value); void set_scale(ObScale scale) { UNUSED(scale); } int print(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, uint32_t begin = 0, uint32_t print_size = 0) const; + int print_element(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, + uint32_t begin = 0, uint32_t print_size = 0, + ObString delimiter = ObString(","), + bool has_null_str = true, ObString null_str = ObString("NULL")) const; uint32_t *get_offsets() const { return nullptr; } char *get_data() const { return reinterpret_cast(data_);} int32_t get_raw_binary_len() @@ -608,37 +831,73 @@ public : int get_raw_binary(char *res_buf, int64_t buf_len); int32_t get_data_binary_len() { return get_raw_binary_len(); } int get_data_binary(char *res_buf, int64_t buf_len) { return get_raw_binary(res_buf, buf_len); } + int hash(uint64_t &hash_val) const; int init (); int init(ObString &raw_data); int init(ObDatum *attrs, uint32_t attr_count, bool with_length = true); int check_validity(const ObCollectionArrayType &arr_type, const ObIArrayType &array) const; int push_null() { return OB_ERR_NULL_VALUE; } int insert_from(const ObIArrayType &src, uint32_t begin, uint32_t len); - int at(uint32_t idx, ObIArrayType &dest) { return OB_NOT_SUPPORTED; } + int at(uint32_t idx, ObIArrayType &dest) const { return OB_NOT_SUPPORTED; } void clear(); int flatten(ObArrayAttr *attrs, uint32_t attr_count, uint32_t &attr_idx); int compare_at(uint32_t left_begin, uint32_t left_len, uint32_t right_begin, uint32_t right_len, - const ObIArrayType &right, int &cmp_ret); - int compare(const ObIArrayType &right, int &cmp_ret); + const ObIArrayType &right, int &cmp_ret) const; + int compare(const ObIArrayType &right, int &cmp_ret) const; template - int contains(const Elem_Type &elem, bool &bret) const + int contains(const Elem_Type &elem, int &pos) const { int ret = OB_SUCCESS; - bret = false; - for (uint32_t i = 0; i < length_ && !bret; ++i) { + pos = -1; + for (uint32_t i = 0; i < length_ && pos < 0; ++i) { if (static_cast(data_[i]) == elem) { - bret = true; + pos = i; } } return ret; } template <> - int contains(const ObString &elem, bool &bret) const + int contains(const ObString &elem, int &pos) const { return OB_INVALID_ARGUMENT; } template <> - int contains(const ObIArrayType &elem, bool &bret) const + int contains(const ObIArrayType &elem, int &pos) const + { + return OB_INVALID_ARGUMENT; + } + int contains_all(const ObIArrayType &other, bool &bret) const; + int overlaps(const ObIArrayType &other, bool &bret) const; + int clone_empty(ObIAllocator &alloc, ObIArrayType *&output, bool read_only = true) const; + int distinct(ObIAllocator &alloc, ObIArrayType *&output) const; + + template + int clone_except(ObIAllocator &alloc, const Elem_Type *elem_except, bool is_null, ObIArrayType *&output) const + { + int ret = OB_SUCCESS; + if (OB_FAIL(clone_empty(alloc, output, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else { + ObVectorData *arr_data = dynamic_cast(output); + if (OB_ISNULL(arr_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(this->get_format())); + } + for (uint32_t i = 0; i < length_ && OB_SUCC(ret); ++i) { + if (static_cast(data_[i]) != *elem_except && OB_FAIL(arr_data->push_back(data_[i]))) { + OB_LOG(WARN, "failed to add element", K(ret)); + } + } + } + return ret; + } + template <> + int clone_except(ObIAllocator &alloc, const ObString *elem_except, bool is_null, ObIArrayType *&output) const + { + return OB_INVALID_ARGUMENT; + } + template <> + int clone_except(ObIAllocator &alloc, const ObIArrayType *elem_except, bool is_null, ObIArrayType *&output) const { return OB_INVALID_ARGUMENT; } @@ -654,6 +913,7 @@ public : : ObArrayBase(length, elem_type, null_bitmaps), offsets_(offsets), data_(data) {} ObString operator[](const int64_t i) const; + uint32_t cardinality() const { return this->length_; } ArrayFormat get_format() const { return ArrayFormat::Binary_Varlen; } uint32_t *get_offsets() const { return offsets_; } char *get_data() const { return data_;} @@ -661,6 +921,10 @@ public : void set_scale(ObScale scale) { UNUSED(scale); } int print(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, uint32_t begin = 0, uint32_t print_size = 0) const; + int print_element(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, + uint32_t begin = 0, uint32_t print_size = 0, + ObString delimiter = ObString(","), + bool has_null_str = true, ObString null_str = ObString("NULL")) const; int32_t get_data_binary_len() { @@ -678,32 +942,73 @@ public : int get_data_binary(char *res_buf, int64_t buf_len); int32_t get_raw_binary_len() { return sizeof(length_) + get_data_binary_len(); } int get_raw_binary(char *res_buf, int64_t buf_len); + int hash(uint64_t &hash_val) const; int init(); int init(ObString &raw_data); int init(ObDatum *attrs, uint32_t attr_count, bool with_length = true); int check_validity(const ObCollectionArrayType &arr_type, const ObIArrayType &array) const { return OB_SUCCESS; } int push_null(); int insert_from(const ObIArrayType &src, uint32_t begin, uint32_t len); - int at(uint32_t idx, ObIArrayType &dest) { return OB_NOT_SUPPORTED; } + int at(uint32_t idx, ObIArrayType &dest) const { return OB_NOT_SUPPORTED; } void clear(); int flatten(ObArrayAttr *attrs, uint32_t attr_count, uint32_t &attr_idx); - int compare(const ObIArrayType &right, int &cmp_ret); + int compare(const ObIArrayType &right, int &cmp_ret) const; int compare_at(uint32_t left_begin, uint32_t left_len, uint32_t right_begin, uint32_t right_len, - const ObIArrayType &right, int &cmp_ret); + const ObIArrayType &right, int &cmp_ret) const; template - int contains(const T &elem, bool &bret) const + int contains(const T &elem, int &pos) const { int ret = OB_SUCCESS; - bret = false; + pos = -1; const ObString *str = nullptr; if (typeid(T) != typeid(ObString)) { ret = OB_ERR_UNEXPECTED; OB_LOG(WARN, "invalid data type", K(ret)); } else { str = reinterpret_cast(&elem); - for (int i = 0; i < length_ && !bret; i++) { + for (int i = 0; i < length_ && pos < 0; i++) { if ((*this)[i].compare(*str) == 0) { - bret = true; + pos = i; + } + } + } + return ret; + } + int contains_all(const ObIArrayType &other, bool &bret) const; + int overlaps(const ObIArrayType &other, bool &bret) const; + int clone_empty(ObIAllocator &alloc, ObIArrayType *&output, bool read_only = true) const; + int distinct(ObIAllocator &alloc, ObIArrayType *&output) const; + + template + int clone_except(ObIAllocator &alloc, const T *elem_except, bool is_null, ObIArrayType *&output) const + { + int ret = OB_SUCCESS; + if (typeid(T) != typeid(ObString)) { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "invalid data type", K(ret)); + } else if (OB_FAIL(clone_empty(alloc, output, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else { + ObArrayBinary *arr_data = dynamic_cast(output); + if (OB_ISNULL(arr_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(this->get_format())); + } + const ObString *str = reinterpret_cast(elem_except); + for (uint32_t i = 0; i < this->length_ && OB_SUCC(ret); ++i) { + if (is_null) { + // remove null + if (this->is_null(i)) { + // do nothing + } else if (OB_FAIL(arr_data->push_back((*this)[i]))) { + OB_LOG(WARN, "push null failed", K(ret)); + } + } else if (this->is_null(i)) { + if (OB_FAIL(arr_data->push_null())) { + OB_LOG(WARN, "push null failed", K(ret)); + } + } else if ((*this)[i] != *str && OB_FAIL(arr_data->push_back((*this)[i]))) { + OB_LOG(WARN, "failed to add element", K(ret)); } } } @@ -721,12 +1026,17 @@ public : ObArrayNested(uint32_t length, int32_t elem_type, uint8_t *null_bitmaps, uint32_t *offsets, ObArrayBase *data) : ObArrayBase(length, elem_type, null_bitmaps), offsets_(offsets), data_(data) {} + uint32_t cardinality() const { return data_->cardinality(); }; ArrayFormat get_format() const { return ArrayFormat::Nested_Array; } uint32_t *get_offsets() const { return offsets_; } char *get_data() const { return data_->get_data();} void set_scale(ObScale scale) { UNUSED(scale); } int print(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, uint32_t begin = 0, uint32_t print_size = 0) const; + int print_element(const ObCollectionTypeBase *elem_type, ObStringBuffer &format_str, + uint32_t begin = 0, uint32_t print_size = 0, + ObString delimiter = ObString(","), + bool has_null_str = true, ObString null_str = ObString("NULL")) const; int32_t get_data_binary_len() { @@ -739,6 +1049,7 @@ public : int32_t get_raw_binary_len() { return sizeof(length_) + get_data_binary_len(); } int get_raw_binary(char *res_buf, int64_t buf_len); + int hash(uint64_t &hash_val) const; int init(); int init(ObString &raw_data); int init(ObDatum *attrs, uint32_t attr_count, bool with_length = true); @@ -748,17 +1059,17 @@ public : inline ObIArrayType *get_child_array() const { return static_cast(data_);} int insert_from(const ObIArrayType &src, uint32_t begin, uint32_t len); int push_back(const ObIArrayType &src, bool is_null = false); - int at(uint32_t idx, ObIArrayType &dest); + int at(uint32_t idx, ObIArrayType &dest) const; void clear(); int flatten(ObArrayAttr *attrs, uint32_t attr_count, uint32_t &attr_idx); int compare_at(uint32_t left_begin, uint32_t left_len, uint32_t right_begin, uint32_t right_len, - const ObIArrayType &right, int &cmp_ret); - int compare(const ObIArrayType &right, int &cmp_ret); + const ObIArrayType &right, int &cmp_ret) const; + int compare(const ObIArrayType &right, int &cmp_ret) const; template - int contains(const T &elem, bool &bret) const + int contains(const T &elem, int &pos) const { int ret = OB_SUCCESS; - bret = false; + pos = -1; const ObIArrayType *elem_ptr = NULL; if (typeid(T) != typeid(ObIArrayType)) { ret = OB_ERR_UNEXPECTED; @@ -766,7 +1077,7 @@ public : } else { elem_ptr = reinterpret_cast(&elem); } - for (uint32_t i = 0; i < length_ && !bret && OB_SUCC(ret); ++i) { + for (uint32_t i = 0; i < length_ && pos < 0 && OB_SUCC(ret); ++i) { if (this->is_null(i)) { } else { uint32_t l_start = offset_at(i, get_offsets()); @@ -775,7 +1086,67 @@ public : if (OB_FAIL(get_child_array()->compare_at(l_start, l_child_len, 0, elem_ptr->size(), *elem_ptr, cmp_ret))) { OB_LOG(WARN, "failed to do nested array contains", K(ret)); } else if (cmp_ret == 0) { - bret = true; + pos = i; + } + } + } + return ret; + } + int contains_all(const ObIArrayType &other, bool &bret) const; + int overlaps(const ObIArrayType &other, bool &bret) const; + int clone_empty(ObIAllocator &alloc, ObIArrayType *&output, bool read_only = true) const; + int distinct(ObIAllocator &alloc, ObIArrayType *&output) const; + + template + int clone_except(ObIAllocator &alloc, const T *elem_except, bool is_null, ObIArrayType *&output) const + { + int ret = OB_SUCCESS; + const ObIArrayType *elem_ptr = NULL; + if (!is_null && typeid(T) != typeid(ObIArrayType)) { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "invalid data type", K(ret)); + } else { + if (OB_FAIL(clone_empty(alloc, output, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } else { + ObArrayNested *arr_data = dynamic_cast(output); + if (OB_ISNULL(arr_data)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + OB_LOG(WARN, "invalid array type", K(ret), K(this->get_format())); + } else { + ObIArrayType *inner_arr = get_child_array(); + ObIArrayType *child_obj = NULL; + if (OB_FAIL(inner_arr->clone_empty(alloc, child_obj, false))) { + OB_LOG(WARN, "clone empty failed", K(ret)); + } + for (uint32_t i = 0; i < this->length_ && OB_SUCC(ret); ++i) { + if (is_null) { + // remove null + if (this->is_null(i)) { + // do nothing + } else if (OB_FAIL(at(i, *child_obj))) { + OB_LOG(WARN, "get element failed", K(ret), K(i), K(length_)); + } else if (OB_FAIL(arr_data->push_back(*child_obj))) { + OB_LOG(WARN, "push null failed", K(ret)); + } else { + child_obj->clear(); + } + } else if (this->is_null(i)) { + if (OB_FAIL(arr_data->push_null())) { + OB_LOG(WARN, "push null failed", K(ret)); + } + } else if (OB_FAIL(at(i, *child_obj))) { + OB_LOG(WARN, "get element failed", K(ret), K(i), K(length_)); + } else if (FALSE_IT(elem_ptr = reinterpret_cast(elem_except))) { + } else if (*child_obj == *elem_ptr) { + // do nothing + child_obj->clear(); + } else if (OB_FAIL(arr_data->push_back(*child_obj))) { + OB_LOG(WARN, "failed to add element", K(ret)); + } else { + child_obj->clear(); + } + } } } } @@ -798,79 +1169,6 @@ private: DISALLOW_COPY_AND_ASSIGN(ObArrayTypeObjFactory); }; - -#define FIXED_ARRAY_OBJ_CONTAINS(Element_Type) \ - const ObArrayFixedSize *arr_ptr = static_cast *>(&array); \ - if (OB_FAIL(arr_ptr->contains(elem, bret))) { \ - OB_LOG(WARN, "array contains failed", K(ret)); \ - } -class ObArrayUtil -{ -public : - static int get_type_name(const ObDataType &elem_type, char *buf, int buf_len, uint32_t depth = 1); - static int push_back_decimal_int(const ObPrecision prec, const ObDecimalInt *dec_val, bool is_null, ObIArrayType *arr_obj); - template - static int contains(const ObIArrayType &array, const Elem_Type &elem, bool &bret) - { - int ret = OB_SUCCESS; - switch (array.get_format()) { - case ArrayFormat::Fixed_Size : - if (static_cast(array.get_element_type()) == ObTinyIntType) { - FIXED_ARRAY_OBJ_CONTAINS(int8_t); - } else if (static_cast(array.get_element_type()) == ObSmallIntType) { - FIXED_ARRAY_OBJ_CONTAINS(int16_t); - } else if (static_cast(array.get_element_type()) == ObIntType) { - FIXED_ARRAY_OBJ_CONTAINS(int64_t); - } else if (static_cast(array.get_element_type()) == ObInt32Type) { - FIXED_ARRAY_OBJ_CONTAINS(int32_t); - } else if (static_cast(array.get_element_type()) == ObUTinyIntType) { - FIXED_ARRAY_OBJ_CONTAINS(uint8_t); - } else if (static_cast(array.get_element_type()) == ObUSmallIntType) { - FIXED_ARRAY_OBJ_CONTAINS(uint16_t); - } else if (static_cast(array.get_element_type()) == ObUInt64Type) { - FIXED_ARRAY_OBJ_CONTAINS(int64_t); - } else if (static_cast(array.get_element_type()) == ObUInt32Type) { - FIXED_ARRAY_OBJ_CONTAINS(uint32_t); - } else if (static_cast(array.get_element_type()) == ObFloatType) { - FIXED_ARRAY_OBJ_CONTAINS(float); - } else if (static_cast(array.get_element_type()) == ObDoubleType) { - FIXED_ARRAY_OBJ_CONTAINS(double); - } else { - ret = OB_ERR_UNEXPECTED; - OB_LOG(WARN, "invalid array type", K(ret), K(array.get_element_type())); - } - break; - case ArrayFormat::Binary_Varlen : - if (OB_FAIL(static_cast(&array)->contains(elem, bret))) { - OB_LOG(WARN, "failed to do array contains", K(ret)); - } - break; - case ArrayFormat::Vector : - if (OB_FAIL(static_cast(&array)->contains(elem, bret))) { - OB_LOG(WARN, "failed to do array contains", K(ret)); - } - break; - case ArrayFormat::Nested_Array : - if (OB_FAIL(static_cast(&array)->contains(elem, bret))) { - OB_LOG(WARN, "failed to do array contains", K(ret)); - } - break; - default: - ret = OB_ERR_UNEXPECTED; - OB_LOG(WARN, "invalid array type", K(ret), K(array.get_format())); - break; - } - return ret; - } - static int convert_collection_bin_to_string(const ObString &collection_bin, - const common::ObIArray &extended_type_info, - common::ObIAllocator &allocator, - ObString &res_str); - static int get_mysql_type(const common::ObIArray &extended_type_info, - obmysql::EMySQLFieldType &type); -}; -#undef FIXED_ARRAY_OBJ_CONTAINS - } // namespace common } // namespace oceanbase #endif // OCEANBASE_OB_ARRAY_TYPE_ diff --git a/deps/oblib/src/lib/udt/ob_array_utils.cpp b/deps/oblib/src/lib/udt/ob_array_utils.cpp new file mode 100644 index 0000000000..fea92e7fe1 --- /dev/null +++ b/deps/oblib/src/lib/udt/ob_array_utils.cpp @@ -0,0 +1,275 @@ +/** + * Copyright (c) 2021 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 LIB +#include "ob_array_utils.h" + +namespace oceanbase { +namespace common { + +int ObArrayUtil::get_type_name(const ObDataType &elem_type, char *buf, int buf_len, uint32_t depth) +{ + int ret = OB_SUCCESS; + int64_t pos = 0; + for (uint32_t i = 0; OB_SUCC(ret) && i < depth; i++) { + if (OB_FAIL(databuff_printf(buf, buf_len, pos, "ARRAY("))) { + LOG_WARN("failed to convert len to string", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(databuff_printf(buf, buf_len, pos, "%s", ob_sql_type_str(elem_type.get_obj_type())))) { + LOG_WARN("failed to convert len to string", K(ret)); + } else if (elem_type.get_obj_type() == ObDecimalIntType + && OB_FAIL(databuff_printf(buf, buf_len, pos, "(%d,%d)", elem_type.get_precision(), elem_type.get_scale()))) { + LOG_WARN("failed to add deciaml precision to string", K(ret)); + } else if (ob_is_string_tc(elem_type.get_obj_type()) + && OB_FAIL(databuff_printf(buf, buf_len, pos, "(%d)", elem_type.get_length()))) { + LOG_WARN("failed to add string len to string", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < depth; i++) { + if (OB_FAIL(databuff_printf(buf, buf_len, pos, ")"))) { + LOG_WARN("failed to add ) to string", K(ret)); + } + } + return ret; +} + +int ObArrayUtil::push_back_decimal_int(const ObPrecision prec, const ObDecimalInt *dec_val, bool is_null, ObIArrayType *arr_obj) +{ + int ret = OB_SUCCESS; + if (get_decimalint_type(prec) == DECIMAL_INT_32) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + if (is_null) { + if (OB_FAIL(arr->push_back(0, true))) { + LOG_WARN("failed to push back null value", K(ret)); + } + } else if (OB_FAIL(arr->push_back(dec_val->int32_v_[0]))) { + LOG_WARN("failed to push back decimal int32 value", K(ret), K(dec_val->int32_v_[0])); + } + } else if (get_decimalint_type(prec) == DECIMAL_INT_64) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + if (is_null) { + if (OB_FAIL(arr->push_back(0, true))) { + LOG_WARN("failed to push back null value", K(ret)); + } + } else if (OB_FAIL(arr->push_back(dec_val->int64_v_[0]))) { + LOG_WARN("failed to push back decimal int64 value", K(ret), K(dec_val->int64_v_[0])); + } + } else if (get_decimalint_type(prec) == DECIMAL_INT_128) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + if (is_null) { + if (OB_FAIL(arr->push_back(0, true))) { + LOG_WARN("failed to push back null value", K(ret)); + } + } else if (OB_FAIL(arr->push_back(dec_val->int128_v_[0]))) { + LOG_WARN("failed to push back decimal int128 value", K(ret), K(dec_val->int128_v_[0])); + } + } else if (get_decimalint_type(prec) == DECIMAL_INT_256) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + if (is_null) { + if (OB_FAIL(arr->push_back(0, true))) { + LOG_WARN("failed to push back null value", K(ret)); + } + } else if (OB_FAIL(arr->push_back(dec_val->int256_v_[0]))) { + LOG_WARN("failed to push back decimal int256 value", K(ret), K(dec_val->int256_v_[0])); + } + } else if (get_decimalint_type(prec) == DECIMAL_INT_512) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + if (is_null) { + if (OB_FAIL(arr->push_back(0, true))) { + LOG_WARN("failed to push back null value", K(ret)); + } + } else if (OB_FAIL(arr->push_back(dec_val->int512_v_[0]))) { + LOG_WARN("failed to push back decimal int512 value", K(ret), K(dec_val->int512_v_[0])); + } + } else { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "unexpected precision", K(ret), K(prec)); + } + return ret; +} + +// convert collection bin to string (for liboblog) +int ObArrayUtil::convert_collection_bin_to_string(const ObString &collection_bin, + const common::ObIArray &extended_type_info, + common::ObIAllocator &allocator, + ObString &res_str) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(extended_type_info.count() != 1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid extended type info for collection type", K(ret), K(extended_type_info.count())); + } else { + ObSqlCollectionInfo type_info_parse(allocator); + ObString collection_type_name = extended_type_info.at(0); + type_info_parse.set_name(collection_type_name); + if (OB_FAIL(type_info_parse.parse_type_info())) { + LOG_WARN("fail to parse type info", K(ret), K(collection_type_name)); + } else if (OB_ISNULL(type_info_parse.collection_meta_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("collection meta is null", K(ret), K(collection_type_name)); + } else { + ObCollectionArrayType *arr_type = nullptr; + ObIArrayType *arr_obj = nullptr; + ObStringBuffer buf(&allocator); + if (OB_ISNULL(arr_type = static_cast(type_info_parse.collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("collection meta is null", K(ret), K(collection_type_name)); + } else if (OB_FAIL(ObArrayTypeObjFactory::construct(allocator, *arr_type, arr_obj, true))) { + LOG_WARN("construct array obj failed", K(ret), K(type_info_parse)); + } else if (OB_ISNULL(arr_obj)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("arr_obj is null", K(ret), K(collection_type_name)); + } else { + ObString raw_binary = collection_bin; + if (OB_FAIL(arr_obj->init(raw_binary))) { + LOG_WARN("failed to init array", K(ret)); + } else if (OB_FAIL(arr_obj->print(arr_type->element_type_, buf))) { + LOG_WARN("failed to format array", K(ret)); + } else { + res_str.assign_ptr(buf.ptr(), buf.length()); + } + } + } + } + return ret; +} + +// determine a collection type is vector or array +int ObArrayUtil::get_mysql_type(const common::ObIArray &extended_type_info, + obmysql::EMySQLFieldType &type) +{ + int ret = OB_SUCCESS; + type = obmysql::MYSQL_TYPE_NOT_DEFINED; + ObArenaAllocator tmp_allocator("OB_ARRAY_UTIL"); + if (OB_UNLIKELY(extended_type_info.count() != 1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid extended type info for collection type", K(ret), K(extended_type_info.count())); + } else { + ObSqlCollectionInfo type_info_parse(tmp_allocator); + ObString collection_type_name = extended_type_info.at(0); + type_info_parse.set_name(collection_type_name); + if (OB_FAIL(type_info_parse.parse_type_info())) { + LOG_WARN("fail to parse type info", K(ret), K(collection_type_name)); + } else if (OB_ISNULL(type_info_parse.collection_meta_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("collection meta is null", K(ret), K(collection_type_name)); + } else { + uint16_t detail_type = type_info_parse.collection_meta_->type_id_; + if (detail_type == OB_ARRAY_TYPE) { + type = obmysql::MYSQL_TYPE_OB_ARRAY; + } else if (detail_type == OB_VECTOR_TYPE) { + type = obmysql::MYSQL_TYPE_OB_VECTOR; + } else { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "unexpected collection type", K(ret), K(detail_type)); + } + } + } + tmp_allocator.reset(); + return ret; +} + +#define FIXED_SIZE_ARRAY_APPEND(Element_Type, Get_Func) \ + ObArrayFixedSize *array_obj = static_cast *>(&array); \ + if (OB_FAIL(array_obj->push_back(datum->Get_Func()))) { \ + LOG_WARN("failed to push back value", K(ret)); \ + } + +int ObArrayUtil::append(ObIArrayType &array, const ObObjType elem_type, const ObDatum *datum) +{ + int ret = OB_SUCCESS; + if (datum->is_null()) { + if (OB_FAIL(array.push_null())) { + LOG_WARN("failed to push back null value", K(ret)); + } + } else { + switch (elem_type) { + case ObNullType: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expect null value", K(ret)); + break; + } + case ObTinyIntType: { + FIXED_SIZE_ARRAY_APPEND(int8_t, get_tinyint); + break; + } + case ObSmallIntType: { + FIXED_SIZE_ARRAY_APPEND(int16_t, get_smallint); + break; + } + case ObInt32Type: { + FIXED_SIZE_ARRAY_APPEND(int32_t, get_int32); + break; + } + case ObIntType: { + FIXED_SIZE_ARRAY_APPEND(int64_t, get_int); + break; + } + case ObUTinyIntType: { + FIXED_SIZE_ARRAY_APPEND(uint8_t, get_utinyint); + break; + } + case ObUSmallIntType: { + FIXED_SIZE_ARRAY_APPEND(uint16_t, get_usmallint); + break; + } + case ObUInt32Type: { + FIXED_SIZE_ARRAY_APPEND(uint32_t, get_uint32); + break; + } + case ObUInt64Type: { + FIXED_SIZE_ARRAY_APPEND(uint64_t, get_uint64); + break; + } + case ObFloatType: { + FIXED_SIZE_ARRAY_APPEND(float, get_float); + break; + } + case ObDoubleType: { + FIXED_SIZE_ARRAY_APPEND(double, get_double); + break; + } + case ObVarcharType: { + ObArrayBinary *binary_array = static_cast(&array); + if (OB_FAIL(binary_array->push_back(datum->get_string()))) { + LOG_WARN("failed to push back null value", K(ret)); + } + break; + } + default: + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported element type", K(ret), K(elem_type)); + } + } + return ret; +} + +int ObArrayUtil::append_array(ObIArrayType &array, ObIArrayType &elem_arr, bool is_null) +{ + int ret = OB_SUCCESS; + ObArrayNested *array_obj = dynamic_cast(&array); + if (OB_ISNULL(array_obj)) { + ret = OB_ERR_ARRAY_TYPE_MISMATCH; + LOG_WARN("invalid array type", K(ret), K(array.get_format())); + } else if (is_null) { + if (OB_FAIL(array_obj->push_null())) { + LOG_WARN("failed to push null", K(ret)); + } + } else if (OB_FAIL(array_obj->push_back(elem_arr))) { + LOG_WARN("failed to push back value", K(ret)); + } + return ret; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/udt/ob_array_utils.h b/deps/oblib/src/lib/udt/ob_array_utils.h new file mode 100644 index 0000000000..dcf9242ab8 --- /dev/null +++ b/deps/oblib/src/lib/udt/ob_array_utils.h @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2021 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_OB_ARRAY_UTILS_ +#define OCEANBASE_OB_ARRAY_UTILS_ + +#include "lib/udt/ob_array_type.h" +#include "src/share/vector/ob_vector_base.h" + +namespace oceanbase { +namespace common { + +#define FIXED_ARRAY_OBJ_CONTAINS(Element_Type) \ + const ObArrayFixedSize *arr_ptr = static_cast *>(&array); \ + if (OB_FAIL(arr_ptr->contains(elem, pos))) { \ + OB_LOG(WARN, "array contains failed", K(ret)); \ + } + +#define FIXED_ARRAY_OBJ_CLONE_EXCEPT(Element_Type) \ + const ObArrayFixedSize *arr_ptr = static_cast *>(&src_array); \ + if (OB_FAIL(arr_ptr->clone_except(alloc, elem, is_null, dst_array))) { \ + OB_LOG(WARN, "array clone_except failed", K(ret)); \ + } +class ObArrayUtil +{ +public : + static int get_type_name(const ObDataType &elem_type, char *buf, int buf_len, uint32_t depth = 1); + static int push_back_decimal_int(const ObPrecision prec, const ObDecimalInt *dec_val, bool is_null, ObIArrayType *arr_obj); + template + static int contains(const ObIArrayType &array, const Elem_Type &elem, bool &bret) + { + int ret = OB_SUCCESS; + int pos = -1; + bret = false; + if (OB_FAIL(position(array, elem, pos))) { + OB_LOG(WARN, "array position failed", K(ret)); + } else if (pos >= 0) { + bret = true; + } + return ret; + } + template + static int position(const ObIArrayType &array, const Elem_Type &elem, int &pos) + { + int ret = OB_SUCCESS; + switch (array.get_format()) { + case ArrayFormat::Fixed_Size : + if (static_cast(array.get_element_type()) == ObTinyIntType) { + FIXED_ARRAY_OBJ_CONTAINS(int8_t); + } else if (static_cast(array.get_element_type()) == ObSmallIntType) { + FIXED_ARRAY_OBJ_CONTAINS(int16_t); + } else if (static_cast(array.get_element_type()) == ObIntType) { + FIXED_ARRAY_OBJ_CONTAINS(int64_t); + } else if (static_cast(array.get_element_type()) == ObInt32Type) { + FIXED_ARRAY_OBJ_CONTAINS(int32_t); + } else if (static_cast(array.get_element_type()) == ObUTinyIntType) { + FIXED_ARRAY_OBJ_CONTAINS(uint8_t); + } else if (static_cast(array.get_element_type()) == ObUSmallIntType) { + FIXED_ARRAY_OBJ_CONTAINS(uint16_t); + } else if (static_cast(array.get_element_type()) == ObUInt64Type) { + FIXED_ARRAY_OBJ_CONTAINS(int64_t); + } else if (static_cast(array.get_element_type()) == ObUInt32Type) { + FIXED_ARRAY_OBJ_CONTAINS(uint32_t); + } else if (static_cast(array.get_element_type()) == ObFloatType) { + FIXED_ARRAY_OBJ_CONTAINS(float); + } else if (static_cast(array.get_element_type()) == ObDoubleType) { + FIXED_ARRAY_OBJ_CONTAINS(double); + } else { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "invalid array type", K(ret), K(array.get_element_type())); + } + break; + case ArrayFormat::Binary_Varlen : + if (OB_FAIL(static_cast(&array)->contains(elem, pos))) { + OB_LOG(WARN, "failed to do array contains", K(ret)); + } + break; + case ArrayFormat::Vector : + if (OB_FAIL(static_cast(&array)->contains(elem, pos))) { + OB_LOG(WARN, "failed to do array contains", K(ret)); + } + break; + case ArrayFormat::Nested_Array : + if (OB_FAIL(static_cast(&array)->contains(elem, pos))) { + OB_LOG(WARN, "failed to do array contains", K(ret)); + } + break; + default: + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "invalid array type", K(ret), K(array.get_format())); + break; + } + return ret; + } + static int convert_collection_bin_to_string(const ObString &collection_bin, + const common::ObIArray &extended_type_info, + common::ObIAllocator &allocator, + ObString &res_str); + static int get_mysql_type(const common::ObIArray &extended_type_info, + obmysql::EMySQLFieldType &type); + + static int append(ObIArrayType &array, const ObObjType elem_type, const ObDatum *datum); + static int append_array(ObIArrayType &array, ObIArrayType &elem_arr, bool is_null = false); + + template + static int clone_except(ObIAllocator &alloc, const ObIArrayType &src_array, const Elem_Type *elem, bool is_null, ObIArrayType *&dst_array) + { + int ret = OB_SUCCESS; + switch (src_array.get_format()) { + case ArrayFormat::Fixed_Size : + if (static_cast(src_array.get_element_type()) == ObTinyIntType) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(int8_t); + } else if (static_cast(src_array.get_element_type()) == ObSmallIntType) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(int16_t); + } else if (static_cast(src_array.get_element_type()) == ObIntType) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(int64_t); + } else if (static_cast(src_array.get_element_type()) == ObInt32Type) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(int32_t); + } else if (static_cast(src_array.get_element_type()) == ObUTinyIntType) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(uint8_t); + } else if (static_cast(src_array.get_element_type()) == ObUSmallIntType) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(uint16_t); + } else if (static_cast(src_array.get_element_type()) == ObUInt64Type) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(int64_t); + } else if (static_cast(src_array.get_element_type()) == ObUInt32Type) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(uint32_t); + } else if (static_cast(src_array.get_element_type()) == ObFloatType) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(float); + } else if (static_cast(src_array.get_element_type()) == ObDoubleType) { + FIXED_ARRAY_OBJ_CLONE_EXCEPT(double); + } else { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "invalid src_array type", K(ret), K(src_array.get_element_type())); + } + break; + case ArrayFormat::Binary_Varlen : + if (OB_FAIL(static_cast(&src_array)->clone_except(alloc, elem, is_null, dst_array))) { + OB_LOG(WARN, "failed to do src_array contains", K(ret)); + } + break; + case ArrayFormat::Vector : + if (OB_FAIL(static_cast(&src_array)->clone_except(alloc, elem, is_null, dst_array))) { + OB_LOG(WARN, "failed to do src_array contains", K(ret)); + } + break; + case ArrayFormat::Nested_Array : + if (OB_FAIL(static_cast(&src_array)->clone_except(alloc, elem, is_null, dst_array))) { + OB_LOG(WARN, "failed to do src_array contains", K(ret)); + } + break; + default: + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "invalid src_array type", K(ret), K(src_array.get_format())); + break; + } + return ret; + } + + static int get_basic_elem_obj(ObIArrayType *src, ObCollectionTypeBase *elem_type, uint32_t idx, ObObj &elem_obj); + +}; + +#undef FIXED_ARRAY_OBJ_CLONE_EXCEPT +#undef FIXED_ARRAY_OBJ_CONTAINS + +} // namespace common +} // namespace oceanbase +#endif // OCEANBASE_OB_ARRAY_UTILS_ \ No newline at end of file diff --git a/deps/oblib/src/lib/udt/ob_collection_type.cpp b/deps/oblib/src/lib/udt/ob_collection_type.cpp index ea9cc01a01..f1277f4acd 100644 --- a/deps/oblib/src/lib/udt/ob_collection_type.cpp +++ b/deps/oblib/src/lib/udt/ob_collection_type.cpp @@ -65,12 +65,6 @@ bool ObCollectionBasicType::has_same_super_type(const ObCollectionBasicType &oth { bool bret = false; if (get_compatiable_type_id() != other.get_compatiable_type_id()) { - } else if (basic_meta_.meta_ != other.basic_meta_.meta_) { - if (ob_is_null(basic_meta_.meta_.get_type()) || ob_is_null(other.basic_meta_.meta_.get_type())) { - bret = true; - } else if (ob_is_numeric_type(basic_meta_.meta_.get_type()) && ob_is_numeric_type(other.basic_meta_.meta_.get_type())) { - bret = true; - } } else { bret = true; } @@ -352,58 +346,71 @@ int ObSqlCollectionInfo::create_meta_info_by_name(const std::string &name, ObCol } } + ObDataType &basic_meta = static_cast(meta_info)->basic_meta_; if (OB_FAIL(ret)) { } else if (0 == name.compare("NULL")) { - static_cast(meta_info)->basic_meta_.meta_.set_null(); + basic_meta.meta_.set_null(); } else if (0 == name.compare("TINYINT")) { - static_cast(meta_info)->basic_meta_.meta_.set_tinyint(); + basic_meta.meta_.set_tinyint(); + basic_meta.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObTinyIntType].scale_); + basic_meta.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObTinyIntType].precision_); } else if (0 == name.compare("SMALLINT")) { - static_cast(meta_info)->basic_meta_.meta_.set_smallint(); + basic_meta.meta_.set_smallint(); + basic_meta.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObSmallIntType].scale_); + basic_meta.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObSmallIntType].precision_); } else if (0 == name.compare("MEDIUMINT")) { - static_cast(meta_info)->basic_meta_.meta_.set_mediumint(); + basic_meta.meta_.set_mediumint(); + basic_meta.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObMediumIntType].scale_); + basic_meta.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObMediumIntType].precision_); } else if (0 == name.compare("INT")) { - static_cast(meta_info)->basic_meta_.meta_.set_int32(); + basic_meta.meta_.set_int32(); + basic_meta.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObInt32Type].scale_); + basic_meta.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObInt32Type].precision_); } else if (0 == name.compare("BIGINT")) { - static_cast(meta_info)->basic_meta_.meta_.set_int(); + basic_meta.meta_.set_int(); + basic_meta.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + basic_meta.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); } else if (0 == name.compare("FLOAT")) { - static_cast(meta_info)->basic_meta_.meta_.set_float(); + basic_meta.meta_.set_float(); } else if (0 == name.compare("DOUBLE")) { - static_cast(meta_info)->basic_meta_.meta_.set_double(); + basic_meta.meta_.set_double(); } else if (0 == name.compare("DECIMAL")) { - static_cast(meta_info)->basic_meta_.meta_.set_number(); + basic_meta.meta_.set_number(); + basic_meta.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObNumberType].scale_); + basic_meta.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObNumberType].precision_); } else if (0 == name.compare("DATETIME")) { - static_cast(meta_info)->basic_meta_.meta_.set_datetime(); + basic_meta.meta_.set_datetime(); } else if (0 == name.compare("TIMESTAMP")) { - static_cast(meta_info)->basic_meta_.meta_.set_timestamp(); + basic_meta.meta_.set_timestamp(); } else if (0 == name.compare("DATE")) { - static_cast(meta_info)->basic_meta_.meta_.set_date(); + basic_meta.meta_.set_date(); } else if (0 == name.compare("TIME")) { - static_cast(meta_info)->basic_meta_.meta_.set_time(); + basic_meta.meta_.set_time(); } else if (0 == name.compare("YEAR")) { - static_cast(meta_info)->basic_meta_.meta_.set_year(); + basic_meta.meta_.set_year(); } else if (0 == name.compare("VARCHAR")) { - static_cast(meta_info)->basic_meta_.meta_.set_varchar(); + basic_meta.meta_.set_varchar(); // use default CS - static_cast(meta_info)->basic_meta_.set_collation_type(CS_TYPE_UTF8MB4_BIN); - static_cast(meta_info)->basic_meta_.set_collation_level(CS_LEVEL_COERCIBLE); + basic_meta.set_collation_type(CS_TYPE_UTF8MB4_BIN); + basic_meta.set_collation_level(CS_LEVEL_COERCIBLE); } else if (0 == name.compare("VARBINARY")) { - static_cast(meta_info)->basic_meta_.meta_.set_varbinary(); + basic_meta.meta_.set_varbinary(); } else if (0 == name.compare("CHAR")) { - static_cast(meta_info)->basic_meta_.meta_.set_char(); + basic_meta.meta_.set_char(); } else if (0 == name.compare("BINARY")) { - static_cast(meta_info)->basic_meta_.meta_.set_binary(); + basic_meta.meta_.set_binary(); } else if (0 == name.compare("BIT")) { - static_cast(meta_info)->basic_meta_.meta_.set_bit(); + basic_meta.meta_.set_bit(); } else if (0 == name.compare("JSON")) { - static_cast(meta_info)->basic_meta_.meta_.set_json(); + basic_meta.meta_.set_json(); } else if (0 == name.compare("GEOMETRY")) { - static_cast(meta_info)->basic_meta_.meta_.set_geometry(); + basic_meta.meta_.set_geometry(); } else if (0 == name.compare("DECIMAL_INT")) { - static_cast(meta_info)->basic_meta_.meta_.set_decimal_int(); + basic_meta.meta_.set_decimal_int(); } else if (0 == name.compare("ARRAY") || 0 == name.compare("VECTOR")) { } else { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("get type by name failed", K(ret)); + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported element type", K(ret), K(ObString(name.length(), name.c_str()))); } return ret; diff --git a/src/logservice/libobcdc/src/ob_log_meta_manager.cpp b/src/logservice/libobcdc/src/ob_log_meta_manager.cpp index 9edfa7b935..267c0ef1fc 100644 --- a/src/logservice/libobcdc/src/ob_log_meta_manager.cpp +++ b/src/logservice/libobcdc/src/ob_log_meta_manager.cpp @@ -22,6 +22,7 @@ #include "share/schema/ob_table_schema.h" // ObTableSchema, ObSimpleTableSchemaV2 #include "share/schema/ob_column_schema.h" // ObColumnSchemaV2 #include "logservice/data_dictionary/ob_data_dict_struct.h" +#include "lib/udt/ob_array_utils.h" // ObArrayUtil #include "ob_log_schema_getter.h" // ObLogSchemaGuard, DBSchemaInfo, TenantSchemaInfo #include "ob_log_utils.h" // print_mysql_type, ob_cdc_malloc diff --git a/src/logservice/libobcdc/src/ob_obj2str_helper.cpp b/src/logservice/libobcdc/src/ob_obj2str_helper.cpp index d9a9000bca..dfaa369df1 100644 --- a/src/logservice/libobcdc/src/ob_obj2str_helper.cpp +++ b/src/logservice/libobcdc/src/ob_obj2str_helper.cpp @@ -23,7 +23,7 @@ #include "lib/geo/ob_geo_utils.h" #include "lib/roaringbitmap/ob_rb_utils.h" #include "lib/xml/ob_xml_util.h" -#include "lib/udt/ob_array_type.h" +#include "lib/udt/ob_array_utils.h" #include "sql/engine/expr/ob_expr_uuid.h" #include "sql/engine/expr/ob_expr_operator.h" #include "sql/engine/expr/ob_expr_res_type_map.h" diff --git a/src/objit/include/objit/common/ob_item_type.h b/src/objit/include/objit/common/ob_item_type.h index 0b659f8fa6..345045be00 100644 --- a/src/objit/include/objit/common/ob_item_type.h +++ b/src/objit/include/objit/common/ob_item_type.h @@ -2805,6 +2805,7 @@ extern const char *get_type_name(int type); (op) == T_FUN_SYS_RB_BUILD_AGG ||\ (op) == T_FUN_SYS_RB_OR_AGG ||\ (op) == T_FUN_SYS_RB_AND_AGG ||\ + (op) == T_FUNC_SYS_ARRAY_AGG ||\ ((op) >= T_FUN_SYS_BIT_AND && (op) <= T_FUN_SYS_BIT_XOR)) #define MAYBE_ROW_OP(op) ((op) >= T_OP_EQ && (op) <= T_OP_NE) #define IS_PSEUDO_COLUMN_TYPE(op) \ diff --git a/src/share/aggregate/iaggregate.h b/src/share/aggregate/iaggregate.h index a84aff182d..7575c27518 100644 --- a/src/share/aggregate/iaggregate.h +++ b/src/share/aggregate/iaggregate.h @@ -70,6 +70,7 @@ inline bool has_extra_info(ObAggrInfo &info) case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: + case T_FUNC_SYS_ARRAY_AGG: case T_FUN_HYBRID_HIST: case T_FUN_TOP_FRE_HIST: case T_FUN_AGG_UDF: { diff --git a/src/share/aggregate/processor.cpp b/src/share/aggregate/processor.cpp index 0ba8ac1c8f..054d156177 100644 --- a/src/share/aggregate/processor.cpp +++ b/src/share/aggregate/processor.cpp @@ -572,7 +572,8 @@ int Processor::init_aggr_row_extra_info(RuntimeContext &agg_ctx, char *extra_arr case T_FUN_ORA_XMLAGG: case T_FUN_HYBRID_HIST: case T_FUN_TOP_FRE_HIST: - case T_FUN_AGG_UDF: { + case T_FUN_AGG_UDF: + case T_FUNC_SYS_ARRAY_AGG: { agg_ctx.need_advance_collect_ = true; ret = OB_NOT_SUPPORTED; LOG_WARN("unsupported aggregate type", K(ret), K(aggr_info.get_expr_type())); diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index 86431e1733..489f8e48dc 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -517,9 +517,20 @@ ob_set_subtarget(ob_sql engine_expr engine/expr/ob_expr_rb_to_string.cpp engine/expr/ob_expr_rb_from_string.cpp engine/expr/ob_expr_rb_select.cpp + engine/expr/ob_expr_rb_build.cpp engine/expr/ob_expr_array_contains.cpp + engine/expr/ob_expr_array_to_string.cpp + engine/expr/ob_expr_string_to_array.cpp + engine/expr/ob_expr_array_append.cpp + engine/expr/ob_expr_element_at.cpp + engine/expr/ob_expr_array_cardinality.cpp engine/expr/ob_expr_decode_trace_id.cpp engine/expr/ob_expr_split_part.cpp + engine/expr/ob_expr_array_overlaps.cpp + engine/expr/ob_expr_array_contains_all.cpp + engine/expr/ob_expr_array_distinct.cpp + engine/expr/ob_expr_array_map.cpp + engine/expr/ob_expr_array_remove.cpp engine/expr/ob_expr_extract_cert_expired_time.cpp engine/expr/ob_expr_transaction_id.cpp engine/expr/ob_expr_inner_row_cmp_val.cpp diff --git a/src/sql/code_generator/ob_expr_generator_impl.cpp b/src/sql/code_generator/ob_expr_generator_impl.cpp index b848fa1599..1b54a347f5 100644 --- a/src/sql/code_generator/ob_expr_generator_impl.cpp +++ b/src/sql/code_generator/ob_expr_generator_impl.cpp @@ -1781,6 +1781,7 @@ int ObExprGeneratorImpl::visit(ObAggFunRawExpr &expr) || T_FUN_PL_AGG_UDF == expr.get_expr_type() || T_FUN_HYBRID_HIST == expr.get_expr_type() || T_FUN_ORA_XMLAGG == expr.get_expr_type() + || T_FUNC_SYS_ARRAY_AGG == expr.get_expr_type() || (T_FUN_JSON_OBJECTAGG == expr.get_expr_type() && expr.get_real_param_count() > 1) || (T_FUN_ORA_JSON_OBJECTAGG == expr.get_expr_type() && expr.get_real_param_count() > 1)) { ObExprOperator *op = NULL; @@ -1817,7 +1818,8 @@ int ObExprGeneratorImpl::visit(ObAggFunRawExpr &expr) T_FUN_KEEP_COUNT == expr.get_expr_type() || T_FUN_KEEP_WM_CONCAT == expr.get_expr_type() || T_FUN_HYBRID_HIST == expr.get_expr_type() || - T_FUN_ORA_XMLAGG == expr.get_expr_type())) { + T_FUN_ORA_XMLAGG == expr.get_expr_type() || + T_FUNC_SYS_ARRAY_AGG == expr.get_expr_type())) { ObConstRawExpr *sep_expr = static_cast(expr.get_separator_param_expr()); // set separator if (NULL != sep_expr) { diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index b9c84e436d..9490261bc9 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -428,7 +428,8 @@ int ObStaticEngineCG::check_expr_columnlized(const ObRawExpr *expr) || expr->is_query_ref_expr() || expr->is_udf_expr() || (expr->is_column_ref_expr() && static_cast(expr)->is_virtual_generated_column()) - || (expr->is_column_ref_expr() && is_shadow_column(static_cast(expr)->get_column_id()))) { + || (expr->is_column_ref_expr() && is_shadow_column(static_cast(expr)->get_column_id())) + || expr->is_var_expr()) { // skip } else if ((expr->is_aggr_expr() || (expr->is_win_func_expr()) || expr->is_match_against_expr()) && !expr->has_flag(IS_COLUMNLIZED)) { @@ -7572,7 +7573,8 @@ int ObStaticEngineCG::fill_aggr_info(ObAggFunRawExpr &raw_expr, T_FUN_KEEP_WM_CONCAT == raw_expr.get_expr_type() || T_FUN_HYBRID_HIST == raw_expr.get_expr_type() || T_FUN_ORA_JSON_ARRAYAGG == raw_expr.get_expr_type() || - T_FUN_ORA_XMLAGG == raw_expr.get_expr_type())) { + T_FUN_ORA_XMLAGG == raw_expr.get_expr_type() || + T_FUNC_SYS_ARRAY_AGG == raw_expr.get_expr_type())) { const ObRawExpr *param_raw_expr = (is_oracle_mode() && T_FUN_GROUP_CONCAT == raw_expr.get_expr_type() && raw_expr.get_real_param_count() > 1) diff --git a/src/sql/engine/aggregate/ob_aggregate_processor.cpp b/src/sql/engine/aggregate/ob_aggregate_processor.cpp index 52ba9bbdb2..de8a8659f6 100644 --- a/src/sql/engine/aggregate/ob_aggregate_processor.cpp +++ b/src/sql/engine/aggregate/ob_aggregate_processor.cpp @@ -30,6 +30,7 @@ #include "sql/engine/expr/ob_expr_lob_utils.h" #include "sql/engine/aggregate/ob_aggregate_util.h" #include "sql/engine/basic/ob_material_op_impl.h" +#include "sql/engine/expr/ob_array_expr_utils.h" #include "share/stat/ob_hybrid_hist_estimator.h" #include "share/stat/ob_dbms_stats_utils.h" #include "sql/engine/expr/ob_expr_sys_op_opnsize.h" @@ -2481,6 +2482,7 @@ int ObAggregateProcessor::generate_group_row(GroupRow *&new_group_row, case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { void *tmp_buf = NULL; set_need_advance_collect(); @@ -2695,6 +2697,7 @@ int ObAggregateProcessor::fill_group_row(GroupRow *new_group_row, case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { void *tmp_buf = NULL; set_need_advance_collect(); @@ -3146,6 +3149,7 @@ int ObAggregateProcessor::rollup_aggregation(AggrCell &aggr_cell, AggrCell &roll case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { GroupConcatExtraResult *aggr_extra = NULL; GroupConcatExtraResult *rollup_extra = NULL; @@ -3467,6 +3471,7 @@ int ObAggregateProcessor::prepare_aggr_result(const ObChunkDatumStore::StoredRow case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { GroupConcatExtraResult *extra = NULL; if (OB_ISNULL(extra = static_cast(aggr_cell.get_extra()))) { @@ -3784,6 +3789,7 @@ int ObAggregateProcessor::process_aggr_batch_result( case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { GroupConcatExtraResult *extra_info = NULL; if (OB_ISNULL(extra_info = static_cast(aggr_cell.get_extra()))) { @@ -4050,6 +4056,7 @@ int ObAggregateProcessor::process_aggr_result(const ObChunkDatumStore::StoredRow case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { GroupConcatExtraResult *extra = NULL; if (OB_ISNULL(extra = static_cast(aggr_cell.get_extra()))) { @@ -4473,6 +4480,14 @@ int ObAggregateProcessor::collect_aggr_result( } break; } + case T_FUNC_SYS_ARRAY_AGG: { + GroupConcatExtraResult *extra = static_cast(aggr_cell.get_extra()); + if (OB_FAIL(get_array_agg_result(aggr_info, extra, result))) { + LOG_WARN("failed to get asmvt result", K(ret)); + } else { + } + break; + } case T_FUN_GROUP_CONCAT: { GroupConcatExtraResult *extra = NULL; ObString sep_str; @@ -9244,6 +9259,69 @@ int ObAggregateProcessor::get_rb_calc_agg_result(const ObAggrInfo &aggr_info, return ret; } +int ObAggregateProcessor::get_array_agg_result(const ObAggrInfo &aggr_info, + GroupConcatExtraResult *&extra, + ObDatum &concat_result) +{ + int ret = OB_SUCCESS; + ObIArrayType *arr_obj = NULL; + const uint16_t meta_id = aggr_info.expr_->obj_meta_.get_subschema_id(); + common::ObArenaAllocator tmp_alloc(ObModIds::OB_SQL_AGGR_FUNC, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + lib::ObMallocHookAttrGuard malloc_guard(lib::ObMemAttr(ObRbExprHelper::get_tenant_id(eval_ctx_.exec_ctx_.get_my_session()), "ARRAY_AGG")); + if (OB_ISNULL(extra) || OB_UNLIKELY(extra->empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unpexcted null", K(ret), K(extra)); + } else if (extra->is_iterated() && OB_FAIL(extra->rewind())) { + // Group concat row may be iterated in rollup_process(), rewind here. + LOG_WARN("rewind failed", KPC(extra), K(ret)); + } else if (!extra->is_iterated() && OB_FAIL(extra->finish_add_row())) { + LOG_WARN("finish_add_row failed", KPC(extra), K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_alloc, eval_ctx_, meta_id, arr_obj, false))) { + LOG_WARN("construct array obj failed", K(ret)); + } else { + const ObChunkDatumStore::StoredRow *storted_row = NULL; + ObObjMeta elem_meta = aggr_info.param_exprs_.at(0)->obj_meta_; + ObObjType elem_type = elem_meta.get_type(); + bool inited_tmp_obj = false; + ObObj *tmp_obj = NULL; + while (OB_SUCC(ret) && OB_SUCC(extra->get_next_row(storted_row))) { + if (OB_ISNULL(storted_row)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(storted_row)); + } else { + const ObDatum& datum_val = storted_row->cells()[0]; + if (datum_val.is_null()) { + if (OB_FAIL(arr_obj->push_null())) { + LOG_WARN("failed to push back null value", K(ret)); + } + } else if (ob_is_collection_sql_type(elem_type)) { + common::ObArenaAllocator single_row_alloc(ObModIds::OB_SQL_AGGR_FUNC, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObArrayNested *nest_array = static_cast(arr_obj); + if (OB_FAIL(ObArrayExprUtils::add_elem_to_nested_array(single_row_alloc, eval_ctx_, elem_meta.get_subschema_id(), + datum_val, nest_array))) { + LOG_WARN("failed to push back value", K(ret)); + } + } else if (OB_FAIL(ObArrayUtil::append(*arr_obj, elem_type, &datum_val))) { + LOG_WARN("failed to append array value", K(ret)); + } + } + }//end of while + + if (ret != OB_ITER_END && ret != OB_SUCCESS) { + LOG_WARN("fail to get next row", K(ret)); + } else { + ret = OB_SUCCESS; + ObString res_str; + if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_obj, arr_obj->get_raw_binary_len(), *aggr_info.expr_, eval_ctx_, res_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + concat_result.set_string(res_str); + } + } + } + return ret; +} + int ObAggregateProcessor::check_rows_prefix_str_equal_for_hybrid_hist(const ObChunkDatumStore::LastStoredRow &prev_row, const ObChunkDatumStore::StoredRow &cur_row, diff --git a/src/sql/engine/aggregate/ob_aggregate_processor.h b/src/sql/engine/aggregate/ob_aggregate_processor.h index 95caf8f847..01faaefed7 100644 --- a/src/sql/engine/aggregate/ob_aggregate_processor.h +++ b/src/sql/engine/aggregate/ob_aggregate_processor.h @@ -1093,6 +1093,9 @@ private: GroupConcatExtraResult *&extra, ObDatum &concat_result, ObRbOperation calc_op); + int get_array_agg_result(const ObAggrInfo &aggr_info, + GroupConcatExtraResult *&extra, + ObDatum &concat_result); int check_key_valid(common::hash::ObHashSet &view_key_names, const ObString& key); int shadow_truncate_string_for_hist(const ObObjMeta obj_meta, @@ -1218,6 +1221,7 @@ public: case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { need_id = true; break; @@ -1374,6 +1378,7 @@ OB_INLINE bool ObAggregateProcessor::need_extra_info(const ObExprOperatorType ex case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { need_extra = true; break; diff --git a/src/sql/engine/basic/ob_json_table_op.cpp b/src/sql/engine/basic/ob_json_table_op.cpp index 5aba0916ac..432cf0549a 100644 --- a/src/sql/engine/basic/ob_json_table_op.cpp +++ b/src/sql/engine/basic/ob_json_table_op.cpp @@ -29,6 +29,7 @@ #include "lib/xml/ob_binary_aggregate.h" #include "lib/xml/ob_xpath.h" #include "sql/engine/expr/ob_expr_rb_func_helper.h" +#include "sql/engine/expr/ob_array_expr_utils.h" #include "lib/roaringbitmap/ob_rb_utils.h" namespace oceanbase @@ -342,7 +343,8 @@ OB_DEF_SERIALIZE(ObJsonTableSpec) } else if (table_type_ == MulModeTableType::OB_ORA_XML_TABLE_TYPE) { OB_UNIS_ENCODE(table_type_); OB_UNIS_ENCODE(namespace_def_); - } else if (table_type_ == MulModeTableType::OB_RB_ITERATE_TABLE_TYPE) { + } else if (table_type_ == MulModeTableType::OB_RB_ITERATE_TABLE_TYPE + || table_type_ == MulModeTableType::OB_UNNEST_TABLE_TYPE) { OB_UNIS_ENCODE(table_type_); int32_t value_exprs_count = value_exprs_.count() - 1; OB_UNIS_ENCODE(value_exprs_count); @@ -373,7 +375,8 @@ OB_DEF_SERIALIZE_SIZE(ObJsonTableSpec) if (table_type_ == MulModeTableType::OB_ORA_XML_TABLE_TYPE) { OB_UNIS_ADD_LEN(table_type_); OB_UNIS_ADD_LEN(namespace_def_); - } else if (table_type_ == MulModeTableType::OB_RB_ITERATE_TABLE_TYPE) { + } else if (table_type_ == MulModeTableType::OB_RB_ITERATE_TABLE_TYPE + || table_type_ == MulModeTableType::OB_UNNEST_TABLE_TYPE) { OB_UNIS_ADD_LEN(table_type_); int32_t value_exprs_count = value_exprs_.count() - 1; OB_UNIS_ADD_LEN(value_exprs_count); @@ -427,6 +430,8 @@ OB_DEF_DESERIALIZE(ObJsonTableSpec) table_type_flag = OB_XML_TABLE; } else if (col_info->col_type_ == COL_TYPE_RB_ITERATE) { table_type_flag = OB_RB_ITERATE_TABLE; + } else if (col_info->col_type_ == COL_TYPE_UNNEST) { + table_type_flag = OB_UNNEST_TABLE; } } } @@ -748,6 +753,15 @@ int ObJsonTableOp::init() ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to new rb iterate node", K(ret)); } + } else if (jt_ctx_.is_unnest_table_func()) { + table_func_buf = jt_ctx_.op_exec_alloc_->alloc(sizeof(UnnestTableFunc)); + if (OB_ISNULL(table_func_buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate table func buf", K(ret)); + } else if (OB_ISNULL(jt_ctx_.table_func_ = new (table_func_buf) UnnestTableFunc())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to new unnest node", K(ret)); + } } else if (OB_FAIL(ObXmlUtil::create_mulmode_tree_context(jt_ctx_.op_exec_alloc_, jt_ctx_.xpath_ctx_))) { LOG_WARN("fail to create xpath memory context", K(ret)); } else if (jt_ctx_.is_xml_table_func()) { @@ -981,6 +995,134 @@ int RegularCol::eval_xml_type_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* co return ret; } +int RegularCol::eval_unnest_col(ObRegCol &col_node, void* in, JtScanCtx* ctx, ObExpr* col_expr) +{ + INIT_SUCC(ret); + col_node.cur_pos_++; + ObIArrayType **arr_stucts = reinterpret_cast(in); + ObDataType data_type = col_node.col_info_.data_type_; + ObIArrayType *arr_obj = arr_stucts[col_node.col_info_.output_column_idx_]; + ObObjType obj_type = data_type.get_obj_type(); + int32_t idx = col_node.cur_pos_; + ObExpr* expr = ctx->spec_ptr_->column_exprs_.at(col_node.col_info_.output_column_idx_); + ObDatum& res_datum = expr->locate_datum_for_write(*ctx->eval_ctx_); + + if (OB_ISNULL(arr_obj) || (arr_obj->get_format() != ArrayFormat::Vector && arr_obj->is_null(idx))) { + col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); + } else { + switch (obj_type) { + case ObTinyIntType: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_int(static_cast((*arr)[idx])); + break; + } + case ObSmallIntType: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_int(static_cast((*arr)[idx])); + break; + } + case ObIntType: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_int((*arr)[idx]); + break; + } + case ObInt32Type: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_int32((*arr)[idx]); + break; + } + case ObUTinyIntType: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_uint(static_cast((*arr)[idx])); + break; + } + case ObUSmallIntType: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_uint(static_cast((*arr)[idx])); + break; + } + case ObUInt64Type: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_uint((*arr)[idx]); + break; + } + case ObUInt32Type: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_uint32((*arr)[idx]); + break; + } + case ObDecimalIntType: { + ObPrecision prec = data_type.get_precision(); + if (get_decimalint_type(prec) == DECIMAL_INT_32) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_decimal_int(arr->get_decimal_int(idx), sizeof(int32_t)); + } else if (get_decimalint_type(prec) == DECIMAL_INT_64) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_decimal_int(arr->get_decimal_int(idx), sizeof(int64_t)); + } else if (get_decimalint_type(prec) == DECIMAL_INT_128) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_decimal_int(arr->get_decimal_int(idx), sizeof(int128_t)); + } else if (get_decimalint_type(prec) == DECIMAL_INT_256) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_decimal_int(arr->get_decimal_int(idx), sizeof(int256_t)); + } else if (get_decimalint_type(prec) == DECIMAL_INT_512) { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_decimal_int(arr->get_decimal_int(idx), sizeof(int512_t)); + } else { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "unexpected precision", K(ret), K(prec)); + } + break; + } + case ObVarcharType : { + ObArrayBinary *arr = static_cast(arr_obj); + res_datum.set_string((*arr)[idx]); + break; + } + case ObDoubleType: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_double((*arr)[idx]); + break; + } + case ObFloatType: { + ObArrayFixedSize *arr = static_cast *>(arr_obj); + res_datum.set_float((*arr)[idx]); + break; + } + case ObCollectionSQLType: { + ObArrayNested *arr = static_cast(arr_obj); + uint16_t subschema_id = data_type.get_subschema_id(); + ObSubSchemaValue value; + ObSqlCollectionInfo *coll_info = NULL; + ObIArrayType* child_arr = NULL; + ObString res_str; + if (OB_FAIL(ctx->exec_ctx_->get_sqludt_meta_by_subschema_id(subschema_id, value))) { + LOG_WARN("failed to get subschema ctx", K(ret)); + } else if (value.type_ >= OB_SUBSCHEMA_MAX_TYPE) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema type", K(ret), K(value)); + } else if (OB_FALSE_IT(coll_info = reinterpret_cast(value.value_))) { + } else if (OB_FAIL(ObArrayTypeObjFactory::construct(*ctx->op_exec_alloc_, *coll_info->collection_meta_, child_arr))) { + LOG_WARN("failed to add null to array", K(ret)); + } else if (OB_FAIL(arr->at(idx, *child_arr))) { + LOG_WARN("failed to get elem", K(ret), K(idx)); + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(child_arr, child_arr->get_raw_binary_len(), *expr, *ctx->eval_ctx_, res_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + res_datum.set_string(res_str); + } + break; + } + default: { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "unexpected element type", K(ret), K(data_type.get_obj_type())); + } + } + } + + return ret; +} + int RbIterateTableFunc::eval_input(ObJsonTableOp &jt, JtScanCtx &ctx, ObEvalCtx &eval_ctx) { INIT_SUCC(ret); @@ -1089,7 +1231,7 @@ int RbIterateTableFunc::get_iter_value(ObRegCol &col_node, JtScanCtx* ctx, bool INIT_SUCC(ret); bool all_iter_end = true; ObRoaringBitmapIter **rb_iters = reinterpret_cast(col_node.iter_); - int col_num = ctx->spec_ptr_->value_exprs_.count(); + int64_t col_num = ctx->spec_ptr_->value_exprs_.count(); for (int64_t i = 0; OB_SUCC(ret) && i < col_num; ++i) { ObRoaringBitmapIter* rb_iter = rb_iters[i]; if (OB_ISNULL(rb_iter)) { @@ -1115,6 +1257,102 @@ int RbIterateTableFunc::get_iter_value(ObRegCol &col_node, JtScanCtx* ctx, bool return ret; } +int UnnestTableFunc::eval_input(ObJsonTableOp &jt, JtScanCtx &ctx, ObEvalCtx &eval_ctx) +{ + INIT_SUCC(ret); + ObIArrayType **arr_objs = NULL; + int64_t col_num = ctx.spec_ptr_->value_exprs_.count(); + bool is_all_null = true; + if (!ctx.is_unnest_table_func()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid table func", K(ret)); + } else if (OB_ISNULL(arr_objs = static_cast(ctx.row_alloc_.alloc(col_num * sizeof(ObIArrayType*))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc memory for array objects", K(ret)); + } else { + jt.reset_columns(); + } + for (int64_t i = 0; OB_SUCC(ret) && i < col_num; ++i) { + ObExpr *value_expr = ctx.spec_ptr_->value_exprs_.at(i); + ObDataType data_type = ctx.spec_ptr_->cols_def_.at(i)->data_type_; + ObObjType obj_type = value_expr->datum_meta_.type_; + ObDatum *datum = NULL; + const uint16_t meta_id = value_expr->obj_meta_.get_subschema_id(); + ObIArrayType *arr_obj = NULL; + bool is_null = false; + if (obj_type == ObNullType) { + is_null = true; + } else if (!ob_is_collection_sql_type(obj_type)) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid array data type provided.", K(ret), K(i), K(obj_type)); + } else if (OB_FAIL(value_expr->eval(eval_ctx, datum))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (datum->is_null()) { + is_null = true; + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(ctx.row_alloc_, eval_ctx, meta_id, datum->get_string(), arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_SUCC(ret)) { + arr_objs[i] = arr_obj; + is_all_null &= is_null; + } + } + if (OB_FAIL(ret)) { + } else if (is_all_null) { + ret = OB_ITER_END; + } else { + jt.input_ = arr_objs; + } + return ret; +} + +int UnnestTableFunc::reset_ctx(ObRegCol &scan_node, JtScanCtx*& ctx) +{ + INIT_SUCC(ret); + return ret; +} + +int UnnestTableFunc::init_ctx(ObRegCol &scan_node, JtScanCtx*& ctx) +{ + INIT_SUCC(ret); + scan_node.tab_type_ = MulModeTableType::OB_UNNEST_TABLE_TYPE; + return ret; +} + +int UnnestTableFunc::reset_path_iter(ObRegCol &scan_node, void* in, JtScanCtx*& ctx, ScanType init_flag, bool &is_null_value) +{ + INIT_SUCC(ret); + scan_node.iter_ = in; + if (OB_FAIL(get_iter_value(scan_node, ctx, is_null_value))) { + LOG_WARN("failed to get iter value", K(ret)); + } + return ret; +} + +int UnnestTableFunc::get_iter_value(ObRegCol &col_node, JtScanCtx* ctx, bool &is_null_value) +{ + UNUSED(is_null_value); + INIT_SUCC(ret); + bool all_iter_end = true; + col_node.cur_pos_++; + ObIArrayType **arr_objs = reinterpret_cast(col_node.iter_); + int64_t col_num = ctx->spec_ptr_->value_exprs_.count(); + for (int64_t i = 0; OB_SUCC(ret) && i < col_num; ++i) { + ObIArrayType *arr_obj = arr_objs[i]; + if (OB_ISNULL(arr_obj)) { + // do nothing + } else if (col_node.cur_pos_ < arr_obj->size()) { + all_iter_end = false; + } else { + arr_objs[i] = NULL; + } + } + if (OB_SUCC(ret) && all_iter_end) { + ret = OB_ITER_END; + } + return ret; +} + // xmltable expr function int XmlTableFunc::container_at(void* in, void *&out, int32_t pos) { @@ -1889,18 +2127,18 @@ int ObRegCol::eval_regular_col(void *in, JtScanCtx* ctx, bool& is_null_value) need_cast_res = false; curr_ = nullptr; col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); - } else if (this->tab_type_ == OB_RB_ITERATE_TABLE_TYPE) { + } else if (col_type == COL_TYPE_RB_ITERATE) { this->cur_pos_++; - if (OB_ISNULL(in)) { + ObRoaringBitmapIter **rb_iters = reinterpret_cast(in); + ObRoaringBitmapIter *rb_iter = rb_iters[this->col_info_.output_column_idx_]; + if (OB_ISNULL(rb_iter) || rb_iter->get_val_idx() != this->cur_pos_) { col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); } else { - ObRoaringBitmapIter **rb_iters = reinterpret_cast(in); - ObRoaringBitmapIter *rb_iter = rb_iters[this->col_info_.output_column_idx_]; - if (OB_ISNULL(rb_iter) || rb_iter->get_val_idx() != this->cur_pos_) { - col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); - } else { - col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_uint(rb_iter->get_curr_value()); - } + col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_uint(rb_iter->get_curr_value()); + } + } else if (col_type == COL_TYPE_UNNEST) { + if (OB_FAIL(RegularCol::eval_unnest_col(*this, in, ctx, col_expr))) { + LOG_WARN("fail to eval unnest col", K(ret), K(col_type), K(cur_pos_), K(col_info_.output_column_idx_)); } } else if (col_type == COL_TYPE_ORDINALITY || col_type == COL_TYPE_ORDINALITY_XML) { @@ -2243,7 +2481,8 @@ int ObJsonTableOp::inner_get_next_row() bool is_root_null = false; if (!(jt_ctx_.is_xml_table_func() || jt_ctx_.is_json_table_func() - || jt_ctx_.is_rb_iterate_table_func())) { + || jt_ctx_.is_rb_iterate_table_func() + || jt_ctx_.is_unnest_table_func())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unsupport table function", K(ret)); } else if (is_evaled_) { diff --git a/src/sql/engine/basic/ob_json_table_op.h b/src/sql/engine/basic/ob_json_table_op.h index b5e5e76337..9b8f2c879b 100644 --- a/src/sql/engine/basic/ob_json_table_op.h +++ b/src/sql/engine/basic/ob_json_table_op.h @@ -168,6 +168,10 @@ struct JtScanCtx { return spec_ptr_->table_type_ == OB_RB_ITERATE_TABLE_TYPE; } + bool is_unnest_table_func() { + return spec_ptr_->table_type_ == OB_UNNEST_TABLE_TYPE; + } + ObJsonTableSpec* spec_ptr_; ObEvalCtx* eval_ctx_; ObExecContext* exec_ctx_; @@ -335,6 +339,19 @@ public: int reset_ctx(ObRegCol &scan_node, JtScanCtx*& ctx); }; +class UnnestTableFunc : public MulModeTableFunc { +public: + UnnestTableFunc() + : MulModeTableFunc() {} + ~UnnestTableFunc() {} + + int init_ctx(ObRegCol &scan_node, JtScanCtx*& ctx); + int eval_input(ObJsonTableOp &jt, JtScanCtx& ctx, ObEvalCtx &eval_ctx); + int reset_path_iter(ObRegCol &scan_node, void* in, JtScanCtx*& ctx, ScanType init_flag, bool &is_null_value); + int get_iter_value(ObRegCol &col_node, JtScanCtx* ctx, bool &is_null_value); + int reset_ctx(ObRegCol &scan_node, JtScanCtx*& ctx); +}; + class ObMultiModeTableNode { public: ObMultiModeTableNode() @@ -519,7 +536,7 @@ public: static int eval_exist_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr, bool& is_null); static int eval_xml_scalar_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr); static int eval_xml_type_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr); - static int eval_rb_iterate_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr, bool& is_null); + static int eval_unnest_col(ObRegCol &col_node, void* in, JtScanCtx* ctx, ObExpr* col_expr); static void proc_query_on_error(JtScanCtx* ctx, ObRegCol &col_node, int& ret, bool& is_null); static int check_default_val_cast_allowed(JtScanCtx* ctx, ObMultiModeTableNode &col_node, ObExpr* expr) { return 0; } // check type of default value static int set_val_on_empty(JtScanCtx* ctx, ObRegCol &col_node, bool& need_cast_res, bool& is_null); diff --git a/src/sql/engine/expr/ob_array_cast.cpp b/src/sql/engine/expr/ob_array_cast.cpp index 39410d3387..dfb064138e 100644 --- a/src/sql/engine/expr/ob_array_cast.cpp +++ b/src/sql/engine/expr/ob_array_cast.cpp @@ -179,7 +179,14 @@ int ObArrayCastUtils::cast_add_element(common::ObIAllocator &alloc, ObObj &src_e ObCastCtx cast_ctx(&alloc, NULL, mode, ObCharset::get_system_collation()); ObObjType dst_obj_type = dst_elem_type->basic_meta_.get_obj_type(); ObObj res; - if (OB_FAIL(ObObjCaster::to_type(dst_obj_type, cast_ctx, src_elem, res))) { + ObAccuracy out_acc = dst_elem_type->basic_meta_.get_accuracy(); + const ObCollationType cs_type = dst_elem_type->basic_meta_.meta_.get_collation_type(); + ObObj buf_obj; + const ObObj *res_obj = &src_elem; + if (dst_obj_type == ObVarcharType && + OB_FAIL(obj_accuracy_check(cast_ctx, out_acc, cs_type, src_elem, buf_obj, res_obj))) { + LOG_WARN("varchar type length is too long", K(ret), K(src_elem.get_string_len())); + } else if (OB_FAIL(ObObjCaster::to_type(dst_obj_type, cast_ctx, src_elem, res))) { LOG_WARN("failed to cast number to double type", K(ret)); } else { switch (dst_obj_type) { @@ -464,9 +471,6 @@ int ObArrayBinaryCast::cast(common::ObIAllocator &alloc, ObIArrayType *src, cons LOG_WARN("failed to get cast element", K(ret), K(i)); } else if (FALSE_IT(src_elem.set_collation_type(elem_cs_type))) { } else if (FALSE_IT(src_elem.set_collation_level(elem_ncl_type))) { - }else if (elem_len_max < src_elem.get_string_len()) { - ret = OB_ERR_DATA_TOO_LONG; - LOG_WARN("varchar type length is too long", K(ret), K(i), K(elem_len_max), K(src_elem.get_string_len())); } else if (OB_FAIL(ObArrayCastUtils::cast_add_element(alloc, src_elem, dst, dst_type, mode))) { LOG_WARN("failed to cast and add element", K(ret)); } diff --git a/src/sql/engine/expr/ob_array_expr_utils.cpp b/src/sql/engine/expr/ob_array_expr_utils.cpp index 62d9c4f916..5b9da23f6d 100644 --- a/src/sql/engine/expr/ob_array_expr_utils.cpp +++ b/src/sql/engine/expr/ob_array_expr_utils.cpp @@ -14,6 +14,7 @@ #define USING_LOG_PREFIX SQL_ENG #include "sql/engine/expr/ob_array_expr_utils.h" #include "sql/engine/expr/ob_expr_result_type_util.h" +#include "sql/engine/expr/ob_array_cast.h" #include "sql/session/ob_sql_session_info.h" #include "sql/engine/ob_exec_context.h" @@ -355,32 +356,6 @@ int ObArrayExprUtils::set_array_res(ObIArrayType *arr_obj, const int32_t res_siz return ret; } -template -int ObArrayExprUtils::set_array_res(ObIArrayType *arr_obj, const ObExpr &expr, ObEvalCtx &ctx, - ResVec *res_vec, int64_t batch_idx) -{ - int ret = OB_SUCCESS; - int32_t res_size = arr_obj->get_raw_binary_len(); - char *res_buf = nullptr; - int64_t res_buf_len = 0; - ObTextStringVectorResult str_result(expr.datum_meta_.type_, &expr, &ctx, res_vec, batch_idx); - if (OB_FAIL(str_result.init_with_batch_idx(res_size, batch_idx))) { - LOG_WARN("fail to init result", K(ret), K(res_size)); - } else if (OB_FAIL(str_result.get_reserved_buffer(res_buf, res_buf_len))) { - LOG_WARN("fail to get reserver buffer", K(ret)); - } else if (res_buf_len < res_size) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); - } else if (OB_FAIL(arr_obj->get_raw_binary(res_buf, res_buf_len))) { - LOG_WARN("get array raw binary failed", K(ret), K(res_buf_len), K(res_size)); - } else if (OB_FAIL(str_result.lseek(res_size, 0))) { - LOG_WARN("failed to lseek res.", K(ret), K(str_result), K(res_size)); - } else { - str_result.set_result(); - } - return ret; -} - template int ObArrayExprUtils::set_array_res>( ObIArrayType* arr_obj, const ObExpr& expr, ObEvalCtx& ctx, ObUniformFormat* res_vec, int64_t batch_idx); @@ -478,34 +453,11 @@ int ObArrayExprUtils::deduce_array_element_type(ObExecContext *exec_ctx, ObExprR int ret = OB_SUCCESS; uint16_t last_subschema_id = ObInvalidSqlType; ObExprResType coll_calc_type; - ObLength str_len = 0; - bool is_decimal_exist = false; - bool is_bigint_signed_exsit = false; - bool is_all_num_tc = true; - bool is_all_same_type = true; - // scale is zero - bool is_all_int_type = true; - ObObjType last_type = ObNullType; - int64_t elem_idx = 0; + elem_type.meta_.set_utinyint(); // default type + // calculate array element type for (int64_t i = 0; i < param_num && OB_SUCC(ret); i++) { - if (!types_stack[i].is_null()) { - elem_idx = i; - } - if (types_stack[i].get_type() == ObDecimalIntType - || types_stack[i].get_type() == ObNumberType - || types_stack[i].get_type() == ObUNumberType) { - is_decimal_exist = true; - if (types_stack[i].get_scale() != 0) { - is_all_int_type = false; - } - } - if (!ob_is_numeric_tc(types_stack[i].get_type_class()) && !types_stack[i].is_null()) { - is_all_num_tc = false; - } - if (types_stack[i].get_type() == ObIntType) { - is_bigint_signed_exsit = true; - } - if (ob_is_collection_sql_type(types_stack[i].get_type())) { + if (types_stack[i].is_null()) { + } else if (ob_is_collection_sql_type(types_stack[i].get_type())) { // check subschmea id if (last_subschema_id == ObInvalidSqlType) { coll_calc_type = types_stack[i]; @@ -521,73 +473,25 @@ int ObArrayExprUtils::deduce_array_element_type(ObExecContext *exec_ctx, ObExprR elem_type.meta_.set_collection(last_subschema_id); } } - } else if (i == 0) { - // do nothing - } else if (types_stack[i - 1].get_type() != types_stack[i].get_type() - && !types_stack[i].is_null()) { // null is legal input type - for (int64_t j = i - 1; j >= 0 && is_all_same_type; j--) { - if (!types_stack[j].is_null() && types_stack[j].get_type() != types_stack[i].get_type()) { - is_all_same_type = false; - } - } - if (!is_all_same_type && !is_all_num_tc) { - ret = OB_ERR_ILLEGAL_ARGUMENT_FOR_FUNCTION; - LOG_USER_ERROR(OB_ERR_ILLEGAL_ARGUMENT_FOR_FUNCTION); - } - } - if (OB_SUCC(ret)) { - if (ob_is_string_tc(types_stack[i].get_type())) { - str_len = MAX(str_len, types_stack[i].get_length()); - } - } - } - if (OB_SUCC(ret) && last_subschema_id == ObInvalidSqlType) { - if (is_all_same_type && !is_decimal_exist) { - if (param_num == 0) { - // default type - elem_type.meta_.set_tinyint(); - } else { - elem_type.set_meta_type(types_stack[elem_idx].get_obj_meta()); - elem_type.set_accuracy(types_stack[elem_idx].get_accuracy()); - if (ob_is_string_tc(types_stack[elem_idx].get_type())) { - elem_type.set_length(str_len); - for (int64_t i = 0; i < param_num; i++) { - if (!types_stack[i].is_null()) { - if (types_stack[i].get_length() != str_len) { - types_stack[i].set_calc_length(str_len); - } - } - } - } - } - } else if (is_decimal_exist) { - is_all_int_type ? elem_type.meta_.set_int() : elem_type.meta_.set_double(); - ObObjType target_type = is_all_int_type ? ObIntType : ObDoubleType; - for (int64_t i = 0; i < param_num; i++) { - if (!types_stack[i].is_null()) { - if (types_stack[i].get_type() != target_type) { - types_stack[i].set_calc_type(target_type); - } - } - } - } else if (is_all_num_tc) { - ObObjType calc_type = ObUInt64Type; - if (is_bigint_signed_exsit) { - elem_type.meta_.set_int(); - calc_type = ObIntType; - } else { - elem_type.meta_.set_uint64(); - } - for (int64_t i = 0; i < param_num; i++) { - if (!types_stack[i].is_null()) { - if (types_stack[i].get_type() != calc_type) { - types_stack[i].set_calc_type(calc_type); - } - } - } + } else if (!ob_is_array_supported_type(types_stack[i].get_type())) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported element type", K(ret), K(types_stack[i].get_type())); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "array element type"); + } else if (OB_FAIL(ObExprResultTypeUtil::get_deduce_element_type(types_stack[i], elem_type))) { + LOG_WARN("get deduce type failed", K(ret), K(types_stack[i].get_type()), K(elem_type.get_obj_type()), K(i)); } } + // set params calculate type + if (last_subschema_id == ObInvalidSqlType) { + for (int64_t i = 0; i < param_num && OB_SUCC(ret); i++) { + if (types_stack[i].is_null()) { + } else if (types_stack[i].get_type() != elem_type.get_obj_type()) { + types_stack[i].set_calc_type(elem_type.get_obj_type()); + types_stack[i].set_calc_accuracy(elem_type.get_accuracy()); + } + } + } return ret; } @@ -1012,18 +916,33 @@ int ObArrayExprUtils::calc_nested_expr_data_size(const ObExpr &expr, ObEvalCtx & return ret; } -int ObArrayExprUtils::construct_array_obj(ObIAllocator &alloc, ObEvalCtx &ctx, const uint16_t subschema_id, ObIArrayType *&res, bool read_only) +int ObArrayExprUtils::get_array_type_by_subschema_id(ObEvalCtx &ctx, const uint16_t subschema_id, ObCollectionArrayType *&arr_type) { int ret = OB_SUCCESS; ObSubSchemaValue meta; - if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { - LOG_WARN("failed to get subschema meta", K(ret), K(subschema_id)); - } else { - const ObSqlCollectionInfo *src_coll_info = reinterpret_cast(meta.value_); - ObCollectionArrayType *arr_type = static_cast(src_coll_info->collection_meta_); - if (OB_FAIL(ObArrayTypeObjFactory::construct(alloc, *arr_type, res, read_only))) { - LOG_WARN("construct array obj failed", K(ret), K(src_coll_info)); - } + const ObSqlCollectionInfo *coll_info = NULL; + if (OB_NOT_NULL(arr_type)) { + // do nothing + } else if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get subschema value", K(ret), K(subschema_id)); + } else if (OB_ISNULL(coll_info = reinterpret_cast(meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection info is null", K(ret)); + } else if (OB_ISNULL(arr_type = static_cast(coll_info->collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection array type is null", K(ret), K(*coll_info)); + } + return ret; +} + +int ObArrayExprUtils::construct_array_obj(ObIAllocator &alloc, ObEvalCtx &ctx, const uint16_t subschema_id, ObIArrayType *&res, bool read_only) +{ + int ret = OB_SUCCESS; + ObCollectionArrayType *arr_type = NULL; + if (OB_FAIL(get_array_type_by_subschema_id(ctx, subschema_id, arr_type))) { + LOG_WARN("failed to get array type by subschema id", K(ret), K(subschema_id)); + } else if (OB_FAIL(ObArrayTypeObjFactory::construct(alloc, *arr_type, res, read_only))) { + LOG_WARN("construct array obj failed", K(ret)); } return ret; } @@ -1233,6 +1152,159 @@ void ObArrayExprUtils::set_expr_attrs_null(const ObExpr &expr, ObEvalCtx &ctx, c } } +int ObArrayExprUtils::add_elem_to_nested_array(ObIAllocator &tmp_allocator, ObEvalCtx &ctx, uint16_t subschema_id, + const ObDatum &datum, ObArrayNested *nest_array) +{ + int ret = OB_SUCCESS; + ObSubSchemaValue value; + if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, value))) { + LOG_WARN("failed to get subschema ctx", K(ret)); + } else if (value.type_ >= OB_SUBSCHEMA_MAX_TYPE) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema type", K(ret), K(value)); + } else { + ObIArrayType *arr_obj = NULL; + ObString raw_bin; + const ObSqlCollectionInfo *coll_info = reinterpret_cast(value.value_); + ObCollectionArrayType *arr_type = static_cast(coll_info->collection_meta_); + if (OB_ISNULL(coll_info)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("collect info is null", K(ret), K(subschema_id)); + } else if (OB_FAIL(ObArrayTypeObjFactory::construct(tmp_allocator, *arr_type, arr_obj))) { + LOG_WARN("construct array obj failed", K(ret), K(subschema_id), K(coll_info)); + } else if (FALSE_IT(raw_bin = datum.get_string())) { + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(&tmp_allocator, + ObCollectionSQLType, + CS_TYPE_BINARY, + true, + raw_bin))) { + LOG_WARN("fail to get real data.", K(ret), K(raw_bin)); + } else if (OB_FAIL(arr_obj->init(raw_bin))) { + LOG_WARN("failed to init array", K(ret)); + } else if (OB_FAIL(nest_array->push_back(*arr_obj))) { + LOG_WARN("failed to push back array", K(ret)); + } + } + return ret; +} + +int ObArrayExprUtils::deduce_array_type(ObExecContext *exec_ctx, ObExprResType &type1, + ObExprResType &type2,uint16_t &subschema_id) +{ + int ret = OB_SUCCESS; + ObSubSchemaValue arr_meta; + const ObSqlCollectionInfo *coll_info = NULL; + if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(type1.get_subschema_id(), arr_meta))) { + LOG_WARN("failed to get elem meta.", K(ret), K(type1.get_subschema_id())); + } else if (arr_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid subschema type", K(ret), K(arr_meta.type_)); + } else if (OB_ISNULL(coll_info = static_cast(arr_meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("coll info is null", K(ret)); + } else if (!ob_is_collection_sql_type(type2.get_type())) { + ObCollectionArrayType *arr_type = static_cast(coll_info->collection_meta_); + ObCollectionTypeBase *elem_type = arr_type->element_type_; + if (!ob_is_array_supported_type(type2.get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("unexpected type for operation", K(ret), K(type2.get_type())); + } else if (elem_type->type_id_ == ObNestedType::OB_BASIC_TYPE) { + if (type2.get_type() != static_cast(elem_type)->basic_meta_.get_obj_type()) { + ObObjType calc_type = type2.get_type(); + if (type2.get_type() == ObDecimalIntType || type2.get_type() == ObNumberType || type2.get_type() == ObUNumberType) { + calc_type = ObDoubleType; + if (get_decimalint_type(type2.get_precision()) == DECIMAL_INT_32) { + calc_type = ObFloatType; + } + } + if (calc_type == static_cast(elem_type)->basic_meta_.get_obj_type()) { + type2.set_calc_type(calc_type); + } else { + uint32_t depth = 0; + ObDataType coll_elem1_type; + ObDataType coll_calc_type; + ObExprResType deduce_type; + coll_calc_type.set_obj_type(calc_type); + coll_calc_type.set_accuracy(type2.get_accuracy()); + bool is_vec = false; + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObArrayExprUtils::get_array_element_type(exec_ctx, type1.get_subschema_id(), coll_elem1_type, depth, is_vec))) { + LOG_WARN("failed to get array element type", K(ret)); + } else if (OB_FAIL(ObExprResultTypeUtil::get_array_calc_type(exec_ctx, coll_elem1_type, coll_calc_type, + depth, deduce_type, calc_type))) { + LOG_WARN("failed to get array calc type", K(ret)); + } else { + type1.set_calc_meta(deduce_type); + type2.set_calc_type(calc_type); + subschema_id = deduce_type.get_subschema_id(); + } + } + } + } else { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid obj type", K(ret), K(*coll_info), K(type2.get_type())); + } + } else { + // type2.is array + ObString child_def; + uint16_t child_subschema_id; + ObExprResType child_type; + ObExprResType coll_calc_type; + if (OB_FAIL(coll_info->get_child_def_string(child_def))) { + LOG_WARN("failed to get type1 child define", K(ret), K(*coll_info)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_type_string(child_def, child_subschema_id))) { + LOG_WARN("failed to get type1 child subschema id", K(ret), K(*coll_info), K(child_def)); + } else if (child_subschema_id == type2.get_subschema_id()) { + // do nothing + } else if (FALSE_IT(child_type.set_collection(child_subschema_id))) { + } else if (OB_FAIL(ObExprResultTypeUtil::get_array_calc_type(exec_ctx, child_type, type2, coll_calc_type))) { + LOG_WARN("failed to check array compatibilty", K(ret)); + } else { + if (type2.get_subschema_id() != coll_calc_type.get_subschema_id()) { + type2.set_calc_meta(coll_calc_type); + } + if (child_type.get_subschema_id() != coll_calc_type.get_subschema_id()) { + ObDataType child_calc_type; + uint16_t type1_calc_id; + child_calc_type.meta_.set_collection(coll_calc_type.get_subschema_id()); + if (OB_FAIL(ObArrayExprUtils::deduce_nested_array_subschema_id(exec_ctx, child_calc_type, type1_calc_id))) { + LOG_WARN("failed to deduce nested array subschema id", K(ret)); + } else { + coll_calc_type.set_collection(type1_calc_id); + type1.set_calc_meta(coll_calc_type); + subschema_id = coll_calc_type.get_subschema_id(); + } + } + } + } + return ret; +} + +int ObArrayExprUtils::get_child_subschema_id(ObExecContext *exec_ctx, uint16_t subid, uint16_t &child_subid) +{ + int ret = OB_SUCCESS; + ObSubSchemaValue arr_meta; + ObString child_def; + const ObSqlCollectionInfo *coll_info = NULL; + if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(subid, arr_meta))) { + LOG_WARN("failed to get elem meta.", K(ret), K(subid)); + } else if (arr_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid subschema type", K(ret), K(arr_meta.type_)); + } else if (OB_ISNULL(coll_info = static_cast(arr_meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("coll info is null", K(ret), K(*coll_info)); + } else if (coll_info->collection_meta_->type_id_ != ObNestedType::OB_ARRAY_TYPE) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("It's not nested array", K(ret)); + } else if (OB_FAIL(coll_info->get_child_def_string(child_def))) { + LOG_WARN("failed to get type1 child define", K(ret), K(*coll_info)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_type_string(child_def, child_subid))) { + LOG_WARN("failed to get type1 child subschema id", K(ret), K(*coll_info), K(child_def)); + } + return ret; +} + int ObNestedVectorFunc::construct_attr_param(ObIAllocator &alloc, ObEvalCtx &ctx, ObExpr ¶m_expr, const uint16_t meta_id, int64_t row_idx, ObIArrayType *¶m_obj) { @@ -1272,5 +1344,30 @@ int ObNestedVectorFunc::construct_params(ObIAllocator &alloc, ObEvalCtx &ctx, co return ret; } +int ObArrayExprUtils::get_basic_elem_obj(ObIArrayType *src, ObCollectionTypeBase *elem_type, uint32_t idx, ObObj &elem_obj, bool &is_null) +{ + int ret = OB_SUCCESS; + if (elem_type->type_id_ == ObNestedType::OB_BASIC_TYPE) { + const ObCollectionBasicType *basic_type = static_cast(elem_type); + if (src->get_format() != ArrayFormat::Vector && src->is_null(idx)) { + is_null = true; + } else if (OB_FAIL(ObArrayCastUtils::cast_get_element(src, basic_type, idx, elem_obj))) { + LOG_WARN("failed to cast get element", K(ret)); + } else { + is_null = false; + } + } else if (elem_type->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + ObArrayNested *arr_nested = static_cast(src); + const ObCollectionArrayType *array_type = static_cast(elem_type); + if (OB_FAIL(get_basic_elem_obj(arr_nested->get_child_array(), array_type->element_type_, idx, elem_obj, is_null))) { + LOG_WARN("failed to cast get element", K(ret)); + } + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supported elem type", K(ret), K(elem_type->type_id_)); + } + return ret; +} + } // sql } // oceanbase diff --git a/src/sql/engine/expr/ob_array_expr_utils.h b/src/sql/engine/expr/ob_array_expr_utils.h index 00ab458dcf..4f97ac7daf 100644 --- a/src/sql/engine/expr/ob_array_expr_utils.h +++ b/src/sql/engine/expr/ob_array_expr_utils.h @@ -16,7 +16,7 @@ #include "lib/allocator/ob_allocator.h" #include "lib/string/ob_string.h" -#include "lib/udt/ob_array_type.h" +#include "lib/udt/ob_array_utils.h" #include "sql/engine/expr/ob_expr.h" // for ObExpr #include "sql/engine/expr/ob_expr_lob_utils.h" @@ -52,9 +52,32 @@ public: static int set_array_obj_res(ObIArrayType *arr_obj, ObObjCastParams *params, ObObj *obj); template static int set_array_res(ObIArrayType *arr_obj, const ObExpr &expr, ObEvalCtx &ctx, - ResVec *res_vec, int64_t batch_idx); + ResVec *res_vec, int64_t batch_idx) + { + int ret = OB_SUCCESS; + int32_t res_size = arr_obj->get_raw_binary_len(); + char *res_buf = nullptr; + int64_t res_buf_len = 0; + ObTextStringVectorResult str_result(expr.datum_meta_.type_, &expr, &ctx, res_vec, batch_idx); + if (OB_FAIL(str_result.init_with_batch_idx(res_size, batch_idx))) { + SQL_ENG_LOG(WARN, "fail to init result", K(ret), K(res_size)); + } else if (OB_FAIL(str_result.get_reserved_buffer(res_buf, res_buf_len))) { + SQL_ENG_LOG(WARN, "fail to get reserver buffer", K(ret)); + } else if (res_buf_len < res_size) { + ret = OB_ERR_UNEXPECTED; + SQL_ENG_LOG(WARN, "get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(arr_obj->get_raw_binary(res_buf, res_buf_len))) { + SQL_ENG_LOG(WARN, "get array raw binary failed", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(str_result.lseek(res_size, 0))) { + SQL_ENG_LOG(WARN, "failed to lseek res.", K(ret), K(str_result), K(res_size)); + } else { + str_result.set_result(); + } + return ret; + } static int deduce_array_element_type(ObExecContext *exec_ctx, ObExprResType* types_stack, int64_t param_num, ObDataType &elem_type); static int deduce_nested_array_subschema_id(ObExecContext *exec_ctx, ObDataType &elem_type, uint16_t &subschema_id); + static int deduce_array_type(ObExecContext *exec_ctx, ObExprResType &type1, ObExprResType &type2,uint16_t &subschema_id); static int check_array_type_compatibility(ObExecContext *exec_ctx, uint16_t l_subid, uint16_t r_subid, bool &is_compatiable); static int get_array_element_type(ObExecContext *exec_ctx, uint16_t subid, ObObjType &obj_type, uint32_t &depth, bool &is_vec); static int get_array_element_type(ObExecContext *exec_ctx, uint16_t subid, ObDataType &elem_type, uint32_t &depth, bool &is_vec); @@ -62,6 +85,7 @@ public: static int dispatch_array_attrs_inner(ObEvalCtx &ctx, ObIArrayType *arr_obj, ObExpr **attrs, uint32_t attr_count, const int64_t row_idx, bool is_shallow = true); static int batch_dispatch_array_attrs(ObEvalCtx &ctx, ObExpr &expr, int64_t begin, int64_t batch_size, const uint16_t *selector = NULL); static int transform_array_to_uniform(ObEvalCtx &ctx, const ObExpr &expr, const int64_t batch_size, const ObBitVector *skip); + static int get_array_type_by_subschema_id(ObEvalCtx &ctx, const uint16_t subschema_id, ObCollectionArrayType *&arr_type); static int construct_array_obj(ObIAllocator &alloc, ObEvalCtx &ctx, const uint16_t subschema_id, ObIArrayType *&res, bool read_only = true); static int calc_nested_expr_data_size(const ObExpr &expr, ObEvalCtx &ctx, const int64_t batch_idx, int64_t &size); static int get_array_obj(ObIAllocator &alloc, ObEvalCtx &ctx, const uint16_t subschema_id, const ObString &raw_data, ObIArrayType *&res); @@ -75,7 +99,10 @@ public: const int64_t col_offset, const uint64_t row_idx, int64_t &cell_len, const int64_t *remain_size = nullptr); static int assemble_array_attrs(ObEvalCtx &ctx, const ObExpr &expr, int64_t row_idx, ObIArrayType *arr_obj); static void set_expr_attrs_null(const ObExpr &expr, ObEvalCtx &ctx, const int64_t idx); + static int add_elem_to_nested_array(ObIAllocator &tmp_allocator, ObEvalCtx &ctx, uint16_t subschema_id, + const ObDatum &datum, ObArrayNested *nest_array); static int assign_array_to_uniform(ObEvalCtx &ctx, const ObExpr &expr, const ObExpr &dst_expr, int64_t row_idx); + static int get_child_subschema_id(ObExecContext *exec_ctx, uint16_t subid, uint16_t &child_subid); // for vector static int get_type_vector(const ObExpr &expr, @@ -95,6 +122,8 @@ public: // update inplace static int vector_datum_add(ObDatum &res, const ObDatum &data, ObIAllocator &allocator, ObDatum *tmp_res = nullptr, bool negative = false); + static int get_basic_elem_obj(ObIArrayType *src, ObCollectionTypeBase *elem_type, uint32_t idx, ObObj &elem_obj, bool &is_null); + private: static const char* DEFAULT_CAST_TYPE_NAME; static const ObString DEFAULT_CAST_TYPE_STR; diff --git a/src/sql/engine/expr/ob_expr_array.cpp b/src/sql/engine/expr/ob_expr_array.cpp index b8c85469af..fcf36b1742 100644 --- a/src/sql/engine/expr/ob_expr_array.cpp +++ b/src/sql/engine/expr/ob_expr_array.cpp @@ -14,7 +14,6 @@ #define USING_LOG_PREFIX SQL_ENG #include "sql/engine/expr/ob_expr_array.h" #include "lib/udt/ob_collection_type.h" -#include "lib/udt/ob_array_type.h" #include "sql/engine/expr/ob_expr_lob_utils.h" #include "sql/engine/expr/ob_array_expr_utils.h" #include "sql/engine/ob_exec_context.h" @@ -82,16 +81,6 @@ int ObExprArray::calc_result_typeN(ObExprResType& type, return ret; } -#define FIXED_SIZE_ARRAY_APPEND(Element_Type, Get_Func) \ - ObArrayFixedSize *array_obj = static_cast *>(arr_obj); \ - if (datum->is_null()) { \ - if (OB_FAIL(array_obj->push_back(0, true))) { \ - LOG_WARN("failed to push back null value", K(ret), K(i)); \ - } \ - } else if (OB_FAIL(array_obj->push_back(datum->Get_Func()))) { \ - LOG_WARN("failed to push back value", K(ret), K(i)); \ - } - int ObExprArray::eval_array(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) { int ret = OB_SUCCESS; @@ -124,55 +113,8 @@ int ObExprArray::eval_array(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) } else { if (arr_type->element_type_->type_id_ == ObNestedType::OB_BASIC_TYPE) { ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); - switch (elem_type->basic_meta_.get_obj_type()) { - case ObNullType: { - ObArrayFixedSize *null_array = static_cast *>(arr_obj); - if (!datum->is_null()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("expect null value", K(ret), K(*datum)); - } else if (OB_FAIL(null_array->push_null())) { - LOG_WARN("failed to push back null value", K(ret), K(i)); - } - break; - } - case ObTinyIntType: { - FIXED_SIZE_ARRAY_APPEND(int8_t, get_tinyint); - break; - } - case ObInt32Type: { - FIXED_SIZE_ARRAY_APPEND(int32_t, get_int32); - break; - } - case ObIntType: { - FIXED_SIZE_ARRAY_APPEND(int64_t, get_int); - break; - } - case ObUInt64Type: { - FIXED_SIZE_ARRAY_APPEND(uint64_t, get_uint64); - break; - } - case ObFloatType: { - FIXED_SIZE_ARRAY_APPEND(float, get_float); - break; - } - case ObDoubleType: { - FIXED_SIZE_ARRAY_APPEND(double, get_double); - break; - } - case ObVarcharType: { - ObArrayBinary *binary_array = static_cast(arr_obj); - if (datum->is_null()) { - if (OB_FAIL(binary_array->push_back(ObString(), true))) { - LOG_WARN("failed to push back null value", K(ret), K(i)); - } - } else if (OB_FAIL(binary_array->push_back(datum->get_string()))) { - LOG_WARN("failed to push back null value", K(ret), K(i)); - } - break; - } - default: - ret = OB_NOT_SUPPORTED; - LOG_WARN("unsupported element type", K(ret), K(subschema_id), K(elem_type->basic_meta_.get_obj_type())); + if (OB_FAIL(ObArrayUtil::append(*arr_obj, elem_type->basic_meta_.get_obj_type(), datum))) { + LOG_WARN("failed to append array value", K(ret), K(i)); } } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_ARRAY_TYPE) { ObString raw_bin; diff --git a/src/sql/engine/expr/ob_expr_array_append.cpp b/src/sql/engine/expr/ob_expr_array_append.cpp new file mode 100644 index 0000000000..303a7e56c0 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_append.cpp @@ -0,0 +1,453 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_array_append.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" +#include "sql/engine/expr/ob_expr_array.h" +#include "sql/engine/expr/ob_array_cast.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ +ObExprArrayAppendCommon::ObExprArrayAppendCommon(common::ObIAllocator &alloc, ObExprOperatorType type, const char *name) + : ObFuncExprOperator(alloc, type, name, 2, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprArrayAppendCommon::ObExprArrayAppendCommon(ObIAllocator &alloc, ObExprOperatorType type, + const char *name, int32_t param_num, int32_t dimension) + : ObFuncExprOperator(alloc, type, name, param_num, VALID_FOR_GENERATED_COL, dimension) +{ +} + +ObExprArrayAppendCommon::~ObExprArrayAppendCommon() +{ +} + +int ObExprArrayAppendCommon::calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const + { + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + uint16_t subschema_id = type1.get_subschema_id(); + + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec ctx is null", K(ret)); + } else if (type1.is_null()) { + // do nothing + } else if (!ob_is_collection_sql_type(type1.get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "ARRAY", ob_obj_type_str(type1.get_type())); + } else if (type2.is_null()) { + // do nothing + } else if (OB_FAIL(ObArrayExprUtils::deduce_array_type(exec_ctx, type1, type2, subschema_id))) { + LOG_WARN("failed to get result array type subschema id", K(ret)); + } + // set result type + if (OB_SUCC(ret) && !type1.is_null()) { + type.set_collection(subschema_id); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObCollectionSQLType]).get_length()); + } + return ret; +} + +int ObExprArrayAppendCommon::eval_append(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res, bool is_prepend) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t val_subschema_id = expr.args_[1]->obj_meta_.get_subschema_id(); + const uint16_t res_subschema_id = expr.obj_meta_.get_subschema_id(); + ObCollectionArrayType *arr_type = NULL; + ObCollectionArrayType *res_arr_type = NULL; + ObCollectionBasicType *elem_type = NULL; + ObCollectionBasicType *res_elem_type = NULL; + ObIArrayType *src_arr = NULL; + ObIArrayType *val_arr = NULL; + ObIArrayType *res_arr = NULL; + ObDatum *arr_datum = NULL; + ObDatum *val_datum = NULL; + ObArrayTypeCast *arr_cast = NULL; + bool is_null_res = false; + if (OB_FAIL(expr.args_[0]->eval(ctx, arr_datum))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval(ctx, val_datum))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (arr_datum->is_null()) { + is_null_res = true; + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, arr_datum->get_string(), src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator,ctx, res_subschema_id, res_arr, false))) { + LOG_WARN("construct child array obj failed", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_type_by_subschema_id(ctx, subschema_id, arr_type))) { + LOG_WARN("failed to get array type by subschema id", K(ret), K(subschema_id)); + } else if (OB_ISNULL(elem_type = static_cast(arr_type->element_type_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection element type is null", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_type_by_subschema_id(ctx, res_subschema_id, res_arr_type))) { + LOG_WARN("failed to get array type by subschema id", K(ret), K(res_subschema_id)); + } else if (OB_ISNULL(res_elem_type = static_cast(res_arr_type->element_type_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("result array collection element type is null", K(ret)); + } else if (OB_FAIL(ObArrayTypeCastFactory::alloc(tmp_allocator, *arr_type, *res_arr_type, arr_cast))) { + LOG_WARN("alloc array cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } else if (!is_prepend) { + if (OB_FAIL(arr_cast->cast(tmp_allocator, src_arr, elem_type, res_arr, res_elem_type, expr.extra_))) { + LOG_WARN("array element cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } else if (OB_FAIL(append_elem(tmp_allocator, ctx, arr_type, val_datum, val_subschema_id, val_arr, res_arr))) { + LOG_WARN("failed to append element", K(ret)); + } + } else { + if (OB_FAIL(append_elem(tmp_allocator, ctx, arr_type, val_datum, val_subschema_id, val_arr, res_arr))) { + LOG_WARN("failed to append element", K(ret)); + } else if (OB_FAIL(arr_cast->cast(tmp_allocator, src_arr, elem_type, res_arr, res_elem_type, expr.extra_))) { + LOG_WARN("array element cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res.set_null(); + } else { + ObString res_str; + if (OB_FAIL(ObArrayExprUtils::set_array_res( + res_arr, res_arr->get_raw_binary_len(), expr, ctx, res_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + res.set_string(res_str); + } + } + return ret; +} + +int ObExprArrayAppendCommon::eval_append_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size, + bool is_prepend) +{ + int ret = OB_SUCCESS; + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t val_subschema_id = expr.args_[1]->obj_meta_.get_subschema_id(); + const uint16_t res_subschema_id = expr.obj_meta_.get_subschema_id(); + ObCollectionArrayType *arr_type = NULL; + ObCollectionArrayType *res_arr_type = NULL; + ObCollectionBasicType *elem_type = NULL; + ObCollectionBasicType *res_elem_type = NULL; + ObIArrayType *src_arr = NULL; + ObIArrayType *val_arr = NULL; + ObIArrayType* res_arr = NULL; + ObArrayTypeCast *arr_cast = NULL; + + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval index failed", K(ret)); + } else { + ObDatumVector arr_datum = expr.args_[0]->locate_expr_datumvector(ctx); + ObDatumVector val_datum = expr.args_[1]->locate_expr_datumvector(ctx); + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { + bool is_null_res = false; + int64_t idx = 0; + if (skip.at(j) || eval_flags.at(j)) { + continue; + } + eval_flags.set(j); + if (arr_datum.at(j)->is_null()) { + is_null_res = true; + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, + arr_datum.at(j)->get_string(), src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_NOT_NULL(res_arr) && OB_FALSE_IT(res_arr->clear())) { + } else if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator,ctx, res_subschema_id, res_arr, false))) { + LOG_WARN("construct child array obj failed", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_type_by_subschema_id(ctx, subschema_id, arr_type))) { + LOG_WARN("failed to get array type by subschema id", K(ret), K(subschema_id)); + } else if (OB_ISNULL(elem_type = static_cast(arr_type->element_type_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection element type is null", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_type_by_subschema_id(ctx, res_subschema_id, res_arr_type))) { + LOG_WARN("failed to get array type by subschema id", K(ret), K(res_subschema_id)); + } else if (OB_ISNULL(res_elem_type = static_cast(res_arr_type->element_type_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ressult array collection element type is null", K(ret)); + } else if (OB_ISNULL(arr_cast) && OB_FAIL(ObArrayTypeCastFactory::alloc(tmp_allocator, *arr_type, *res_arr_type, arr_cast))) { + LOG_WARN("alloc array cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } else if (!is_prepend) { + if (OB_FAIL(arr_cast->cast(tmp_allocator, src_arr, elem_type, res_arr, res_elem_type, expr.extra_))) { + LOG_WARN("array element cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } else if (OB_FAIL(append_elem(tmp_allocator, ctx, arr_type, val_datum.at(j), val_subschema_id, val_arr, res_arr))) { + LOG_WARN("failed to append element", K(ret)); + } + } else { + if (OB_FAIL(append_elem(tmp_allocator, ctx, arr_type, val_datum.at(j), val_subschema_id, val_arr, res_arr))) { + LOG_WARN("failed to append element", K(ret)); + } else if (OB_FAIL(arr_cast->cast(tmp_allocator, src_arr, elem_type, res_arr, res_elem_type, expr.extra_))) { + LOG_WARN("array element cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_datum.at(j)->set_null(); + } else { + int32_t res_size = res_arr->get_raw_binary_len(); + char *res_buf = nullptr; + int64_t res_buf_len = 0; + ObTextStringDatumResult output_result(expr.datum_meta_.type_, &expr, &ctx, res_datum.at(j)); + if (OB_FAIL(output_result.init_with_batch_idx(res_size, j))) { + LOG_WARN("fail to init result", K(ret), K(res_size)); + } else if (OB_FAIL(output_result.get_reserved_buffer(res_buf, res_buf_len))) { + LOG_WARN("fail to get reserver buffer", K(ret)); + } else if (res_buf_len < res_size) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(res_arr->get_raw_binary(res_buf, res_buf_len))) { + LOG_WARN("get array raw binary failed", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(output_result.lseek(res_size, 0))) { + LOG_WARN("failed to lseek res.", K(ret), K(output_result), K(res_size)); + } else { + output_result.set_result(); + } + } + } // end for + } + return ret; +} + +int ObExprArrayAppendCommon::eval_append_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound, + bool is_prepend) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t val_subschema_id = expr.args_[1]->obj_meta_.get_subschema_id(); + const uint16_t res_subschema_id = expr.obj_meta_.get_subschema_id(); + ObCollectionArrayType *arr_type = NULL; + ObCollectionArrayType *res_arr_type = NULL; + ObCollectionBasicType *elem_type = NULL; + ObCollectionBasicType *res_elem_type = NULL; + ObIArrayType *src_arr = NULL; + ObIArrayType *val_arr = NULL; + ObIArrayType* res_arr = NULL; + ObArrayTypeCast *arr_cast = NULL; + + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval index failed", K(ret)); + } else { + ObIVector *arr_vec = expr.args_[0]->get_vector(ctx); + ObIVector *val_vec = expr.args_[1]->get_vector(ctx); + ObIVector *res_vec = expr.get_vector(ctx); + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + VectorFormat res_format = expr.get_format(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { + bool is_null_res = false; + int64_t arr_idx = 0; + if (skip.at(idx) || eval_flags.at(idx)) { + continue; + } + if (arr_vec->is_null(idx)) { + is_null_res = true; + } else if (arr_vec->get_format() == VEC_UNIFORM || arr_vec->get_format() == VEC_UNIFORM_CONST) { + ObString arr_str = arr_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, subschema_id, arr_str, src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( + tmp_allocator, ctx, *expr.args_[0], subschema_id, idx, src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_FAIL(ret) || is_null_res) { + } else if (OB_NOT_NULL(res_arr) && OB_FALSE_IT(res_arr->clear())) { + } else if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator,ctx, res_subschema_id, res_arr, false))) { + LOG_WARN("construct child array obj failed", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_type_by_subschema_id(ctx, subschema_id, arr_type))) { + LOG_WARN("failed to get array type by subschema id", K(ret), K(subschema_id)); + } else if (OB_ISNULL(elem_type = static_cast(arr_type->element_type_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection element type is null", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_type_by_subschema_id(ctx, res_subschema_id, res_arr_type))) { + LOG_WARN("failed to get array type by subschema id", K(ret), K(res_subschema_id)); + } else if (OB_ISNULL(res_elem_type = static_cast(res_arr_type->element_type_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("result array collection element type is null", K(ret)); + } else if (OB_ISNULL(arr_cast) && OB_FAIL(ObArrayTypeCastFactory::alloc(tmp_allocator, *arr_type, *res_arr_type, arr_cast))) { + LOG_WARN("alloc array cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } else if (!is_prepend) { + if (OB_FAIL(arr_cast->cast(tmp_allocator, src_arr, elem_type, res_arr, res_elem_type, expr.extra_))) { + LOG_WARN("array element cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } else if (OB_FAIL(append_elem_vector(tmp_allocator, ctx, arr_type, val_vec, idx, + val_subschema_id, *expr.args_[1], val_arr, res_arr))){ + LOG_WARN("append array element failed", K(ret)); + } + } else { + if (OB_FAIL(append_elem_vector(tmp_allocator, ctx, arr_type, val_vec, idx, + val_subschema_id, *expr.args_[1], val_arr, res_arr))){ + LOG_WARN("failed to append element", K(ret)); + } else if (OB_FAIL(arr_cast->cast(tmp_allocator, src_arr, elem_type, res_arr, res_elem_type, expr.extra_))) { + LOG_WARN("array element cast failed", K(ret), K(subschema_id), K(res_subschema_id)); + } + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_vec->set_null(idx); + } else if (res_format == VEC_DISCRETE) { + if (OB_FAIL(ObArrayExprUtils::set_array_res(res_arr, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (res_format == VEC_UNIFORM) { + if (OB_FAIL(ObArrayExprUtils::set_array_res>(res_arr, expr, ctx, static_cast *>(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(res_arr, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } //end for + } + return ret; +} + +int ObExprArrayAppendCommon::append_elem(ObIAllocator &tmp_allocator, ObEvalCtx &ctx, + ObCollectionArrayType *arr_type, ObDatum *val_datum, + uint16_t val_subschema_id, ObIArrayType *val_arr, + ObIArrayType *res_arr) +{ + int ret = OB_SUCCESS; + if (arr_type->element_type_->type_id_ == ObNestedType::OB_BASIC_TYPE) { + ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); + if (OB_FAIL(ObArrayUtil::append(*res_arr, elem_type->basic_meta_.get_obj_type(), val_datum))) { + LOG_WARN("failed to append array value", K(ret)); + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + bool is_null_elem = val_datum->is_null(); + if (!is_null_elem && OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, val_subschema_id, val_datum->get_string(), val_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FAIL(ObArrayUtil::append_array(*res_arr, *val_arr, is_null_elem))) { + LOG_WARN("failed to append array", K(ret)); + } + } else { + ret = OB_NOT_SUPPORTED; + OB_LOG(WARN, "invalid array type", K(ret), K(arr_type->element_type_->type_id_)); + } + return ret; +} + +int ObExprArrayAppendCommon::append_elem_vector(ObIAllocator &tmp_allocator, ObEvalCtx &ctx, + ObCollectionArrayType *arr_type, ObIVector *val_vec, int64_t idx, + uint16_t val_subschema_id, ObExpr ¶m_expr, ObIArrayType *val_arr, + ObIArrayType *res_arr) +{ + int ret = OB_SUCCESS; + if (arr_type->element_type_->type_id_ == ObNestedType::OB_BASIC_TYPE) { + ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); + ObDatum val_datum; + if (val_vec->is_null(idx)) { + val_datum.set_null(); + } else { + const char *payload = NULL; + ObLength payload_len = 0; + val_vec->get_payload(idx, payload, payload_len); + val_datum.ptr_ = payload; + val_datum.pack_ = payload_len; + } + if (OB_FAIL(ObArrayUtil::append(*res_arr, elem_type->basic_meta_.get_obj_type(), &val_datum))) { + LOG_WARN("failed to append array value", K(ret)); + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + bool is_null_elem = val_vec->is_null(idx); + if (is_null_elem) { + // do nothing + } else if (val_vec->get_format() == VEC_UNIFORM || val_vec->get_format() == VEC_UNIFORM_CONST) { + ObString val_arr_str = val_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, val_subschema_id, val_arr_str, val_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param(tmp_allocator, ctx, param_expr, val_subschema_id, idx, val_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_SUCC(ret) && OB_FAIL(ObArrayUtil::append_array(*res_arr, *val_arr, is_null_elem))) { + LOG_WARN("failed to append array", K(ret)); + } + } else { + ret = OB_NOT_SUPPORTED; + OB_LOG(WARN, "invalid array type", K(ret), K(arr_type->element_type_->type_id_)); + } + return ret; +} + +ObExprArrayAppend::ObExprArrayAppend(common::ObIAllocator &alloc) + : ObExprArrayAppendCommon(alloc, T_FUNC_SYS_ARRAY_APPEND, N_ARRAY_APPEND) +{ +} + +ObExprArrayAppend::ObExprArrayAppend(common::ObIAllocator &alloc, ObExprOperatorType type, + const char *name, int32_t param_num, int32_t dimension) + : ObExprArrayAppendCommon(alloc, type, name, param_num, dimension) +{ +} + +ObExprArrayAppend::~ObExprArrayAppend() +{ +} + +int ObExprArrayAppend::eval_array_append(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + return eval_append(expr, ctx, res, false); +} + +int ObExprArrayAppend::eval_array_append_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size) +{ + return eval_append_batch(expr, ctx, skip, batch_size, false); +} + +int ObExprArrayAppend::eval_array_append_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + return eval_append_vector(expr, ctx, skip, bound, false); +} + +int ObExprArrayAppend::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_array_append; + rt_expr.eval_batch_func_ = eval_array_append_batch; + rt_expr.eval_vector_func_ = eval_array_append_vector; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_array_append.h b/src/sql/engine/expr/ob_expr_array_append.h new file mode 100644 index 0000000000..6e942eddd3 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_append.h @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_append. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ARRAY_APPEND +#define OCEANBASE_SQL_OB_EXPR_ARRAY_APPEND + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprArrayAppendCommon : public ObFuncExprOperator +{ +public: + explicit ObExprArrayAppendCommon(common::ObIAllocator &alloc, ObExprOperatorType type, const char *name); + explicit ObExprArrayAppendCommon(common::ObIAllocator &alloc, ObExprOperatorType type, + const char *name, int32_t param_num, int32_t dimension); + virtual ~ObExprArrayAppendCommon(); + virtual int calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_append(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res, bool is_preappend = false); + static int eval_append_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size, + bool is_preappend = false); + static int eval_append_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound, + bool is_preappend = false); + + static int append_elem(ObIAllocator &tmp_allocator, ObEvalCtx &ctx, + ObCollectionArrayType *arr_type, ObDatum *val_datum, + uint16_t val_subschema_id, ObIArrayType *val_arr, + ObIArrayType *res_arr); + + static int append_elem_vector(ObIAllocator &tmp_allocator, ObEvalCtx &ctx, + ObCollectionArrayType *arr_type, ObIVector *val_vec, int64_t idx, + uint16_t val_subschema_id, ObExpr ¶m_expr, ObIArrayType *val_arr, + ObIArrayType *res_arr); +private: + DISALLOW_COPY_AND_ASSIGN(ObExprArrayAppendCommon); +}; + +class ObExprArrayAppend : public ObExprArrayAppendCommon +{ +public: + explicit ObExprArrayAppend(common::ObIAllocator &alloc); + explicit ObExprArrayAppend(common::ObIAllocator &alloc, ObExprOperatorType type, + const char *name, int32_t param_num, int32_t dimension); + virtual ~ObExprArrayAppend(); + static int eval_array_append(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_append_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size); + static int eval_array_append_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound); + + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + DISALLOW_COPY_AND_ASSIGN(ObExprArrayAppend); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ARRAY_APPEND \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_array_cardinality.cpp b/src/sql/engine/expr/ob_expr_array_cardinality.cpp new file mode 100644 index 0000000000..1a462d382e --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_cardinality.cpp @@ -0,0 +1,163 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_cardinality expression. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_array_cardinality.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ +ObExprArrayCardinality::ObExprArrayCardinality(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_ARRAY_CARDINALITY, N_ARRAY_CARDINALITY, 1, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprArrayCardinality::~ObExprArrayCardinality() +{ +} + +int ObExprArrayCardinality::calc_result_type1(ObExprResType &type, + ObExprResType &type1, + ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + if (!ob_is_collection_sql_type(type1.get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "ARRAY", ob_obj_type_str(type1.get_type())); + } else { + type.set_uint32(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObUInt32Type].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObUInt32Type].precision_); + } + return ret; +} + +int ObExprArrayCardinality::eval_array_cardinality(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + ObDatum *datum = nullptr; + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObIArrayType *src_arr = NULL; + if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) { + LOG_WARN("failed to eval source array arg", K(ret)); + } else if (datum->is_null()) { + res.set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, datum->get_string(), src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } else { + res.set_uint32(src_arr->cardinality()); + } + return ret; +} + +int ObExprArrayCardinality::eval_array_cardinality_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size) +{ + int ret = OB_SUCCESS; + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObIArrayType *src_arr = NULL; + + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval source array failed", K(ret)); + } else { + ObDatumVector arr_array = expr.args_[0]->locate_expr_datumvector(ctx); + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { + if (skip.at(j) || eval_flags.at(j)) { + continue; + } + eval_flags.set(j); + if (arr_array.at(j)->is_null()) { + res_datum.at(j)->set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, arr_array.at(j)->get_string(), src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } else { + res_datum.at(j)->set_uint32(src_arr->cardinality()); + } + } // end for + } + return ret; +} + +int ObExprArrayCardinality::eval_array_cardinality_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval source array failed", K(ret)); + } else { + ObIVector *arr_vec = expr.args_[0]->get_vector(ctx); + VectorFormat arr_format = arr_vec->get_format(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObIArrayType *src_arr = NULL; + ObIVector *res_vec = expr.get_vector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { + bool is_null_res = false; + if (skip.at(idx) || eval_flags.at(idx)) { + continue; + } else if (arr_vec->is_null(idx)) { + is_null_res = true; + } else if (arr_format == VEC_UNIFORM || arr_format == VEC_UNIFORM_CONST) { + ObString arr_str = arr_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, subschema_id, arr_str, src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( + tmp_allocator, ctx, *expr.args_[0], subschema_id, idx, src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_vec->set_null(idx); + eval_flags.set(idx); + } else { + res_vec->set_int(idx, static_cast(src_arr->cardinality())); + eval_flags.set(idx); + } + } // end for + } + return ret; +} +int ObExprArrayCardinality::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_array_cardinality; + rt_expr.eval_batch_func_ = eval_array_cardinality_batch; + rt_expr.eval_vector_func_ = eval_array_cardinality_vector; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_array_cardinality.h b/src/sql/engine/expr/ob_expr_array_cardinality.h new file mode 100644 index 0000000000..b827686f27 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_cardinality.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for cardinality expression. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ARRAY_CARDINALITY +#define OCEANBASE_SQL_OB_EXPR_ARRAY_CARDINALITY + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprArrayCardinality : public ObFuncExprOperator +{ +public: + explicit ObExprArrayCardinality(common::ObIAllocator &alloc); + + virtual ~ObExprArrayCardinality(); + + virtual int calc_result_type1(ObExprResType &type, ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_array_cardinality(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_cardinality_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size); + static int eval_array_cardinality_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + DISALLOW_COPY_AND_ASSIGN(ObExprArrayCardinality); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ARRAY_CARDINALITY \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_array_contains.cpp b/src/sql/engine/expr/ob_expr_array_contains.cpp index 7f7e7dbab8..59573958d2 100644 --- a/src/sql/engine/expr/ob_expr_array_contains.cpp +++ b/src/sql/engine/expr/ob_expr_array_contains.cpp @@ -14,7 +14,6 @@ #define USING_LOG_PREFIX SQL_ENG #include "sql/engine/expr/ob_expr_array_contains.h" #include "lib/udt/ob_collection_type.h" -#include "lib/udt/ob_array_type.h" #include "sql/engine/expr/ob_expr_lob_utils.h" #include "sql/engine/expr/ob_array_expr_utils.h" #include "sql/engine/ob_exec_context.h" @@ -78,80 +77,8 @@ int ObExprArrayContains::calc_result_type2(ObExprResType &type, LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1_ptr->get_type()), ob_obj_type_str(type2_ptr->get_type())); } else if (type2_ptr->is_null()) { // do nothing - } else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(type1_ptr->get_subschema_id(), arr_meta))) { - LOG_WARN("failed to get elem meta.", K(ret), K(type1_ptr->get_subschema_id())); - } else if (arr_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) { - ret = OB_ERR_INVALID_TYPE_FOR_OP; - LOG_WARN("invalid subschema type", K(ret), K(arr_meta.type_)); - } else if (OB_ISNULL(coll_info = static_cast(arr_meta.value_))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("coll info is null", K(ret)); - } else if (!ob_is_collection_sql_type(type2_ptr->get_type())) { - ObCollectionArrayType *arr_type = static_cast(coll_info->collection_meta_); - ObCollectionTypeBase *elem_type = arr_type->element_type_; - if (elem_type->type_id_ == ObNestedType::OB_BASIC_TYPE) { - if (ob_obj_type_class(type2_ptr->get_type()) != static_cast(elem_type)->basic_meta_.get_type_class()) { - ObObjType calc_type = type2_ptr->get_type(); - if (type2_ptr->get_type() == ObDecimalIntType || type2_ptr->get_type() == ObNumberType || type2_ptr->get_type() == ObUNumberType) { - calc_type = ObDoubleType; - if (get_decimalint_type(type2_ptr->get_precision()) == DECIMAL_INT_32) { - calc_type = ObFloatType; - } - } - if (calc_type == static_cast(elem_type)->basic_meta_.get_obj_type()) { - type2_ptr->set_calc_type(calc_type); - } else { - uint32_t depth = 0; - ObDataType coll_elem1_type; - ObExprResType deduce_type; - bool is_vec = false; - if (OB_FAIL(ret)) { - } else if (OB_FAIL(ObArrayExprUtils::get_array_element_type(exec_ctx, type1_ptr->get_subschema_id(), coll_elem1_type, depth, is_vec))) { - LOG_WARN("failed to get array element type", K(ret)); - } else if (OB_FAIL(ObExprResultTypeUtil::get_array_calc_type(exec_ctx, coll_elem1_type.get_obj_type(), calc_type, - depth, deduce_type, calc_type))) { - LOG_WARN("failed to get array calc type", K(ret)); - } else { - type1_ptr->set_calc_meta(deduce_type); - type2_ptr->set_calc_type(calc_type); - } - } - } - } else { - ret = OB_ERR_INVALID_TYPE_FOR_OP; - LOG_WARN("invalid obj type", K(ret), K(*coll_info), K(type2_ptr->get_type())); - } - } else { - // type2_ptr->is array - ObString child_def; - uint16_t child_subschema_id; - ObExprResType child_type; - ObExprResType coll_calc_type; - if (OB_FAIL(coll_info->get_child_def_string(child_def))) { - LOG_WARN("failed to get type1 child define", K(ret), K(*coll_info)); - } else if (OB_FAIL(exec_ctx->get_subschema_id_by_type_string(child_def, child_subschema_id))) { - LOG_WARN("failed to get type1 child subschema id", K(ret), K(*coll_info), K(child_def)); - } else if (child_subschema_id == type2_ptr->get_subschema_id()) { - // do nothing - } else if (FALSE_IT(child_type.set_collection(child_subschema_id))) { - } else if (OB_FAIL(ObExprResultTypeUtil::get_array_calc_type(exec_ctx, child_type, *type2_ptr, coll_calc_type))) { - LOG_WARN("failed to check array compatibilty", K(ret)); - } else { - if (type2_ptr->get_subschema_id() != coll_calc_type.get_subschema_id()) { - type2_ptr->set_calc_meta(coll_calc_type); - } - if (child_type.get_subschema_id() != coll_calc_type.get_subschema_id()) { - ObDataType child_calc_type; - uint16_t type1_calc_id; - child_calc_type.meta_.set_collection(coll_calc_type.get_subschema_id()); - if (OB_FAIL(ObArrayExprUtils::deduce_nested_array_subschema_id(exec_ctx, child_calc_type, type1_calc_id))) { - LOG_WARN("failed to deduce nested array subschema id", K(ret)); - } else { - coll_calc_type.set_collection(type1_calc_id); - type1_ptr->set_calc_meta(coll_calc_type); - } - } - } + } else if (OB_FAIL(ObArrayExprUtils::deduce_array_type(exec_ctx, *type1_ptr, *type2_ptr, subschema_id))) { + LOG_WARN("failed to get result array type subschema id", K(ret)); } if (OB_SUCC(ret)) { type.set_int32(); @@ -434,8 +361,7 @@ int ObExprArrayContains::eval_array_contains_array_vector(const ObExpr &expr, Ob } if (OB_FAIL(ret)) { } else if (is_null_res) { - res_vec->set_null(idx); - eval_flags.set(idx); + // do noting } else if (right_vec->is_null(idx)) { bool contains_null = arr_obj->contain_null(); res_vec->set_bool(idx, contains_null); @@ -451,6 +377,9 @@ int ObExprArrayContains::eval_array_contains_array_vector(const ObExpr &expr, Ob } bool bret = false; if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_vec->set_null(idx); + eval_flags.set(idx); } else if (OB_FAIL(ObArrayUtil::contains(*arr_obj, *arr_val, bret))) { LOG_WARN("array contains failed", K(ret)); } else { @@ -499,6 +428,7 @@ int ObExprArrayContains::cg_expr(ObExprCGCtx &expr_cg_ctx, } if OB_SUCC(ret) { switch (right_tc) { + case ObUIntTC: case ObIntTC: rt_expr.eval_func_ = eval_array_contains_int64_t; rt_expr.eval_batch_func_ = eval_array_contains_batch_int64_t; @@ -527,12 +457,12 @@ int ObExprArrayContains::cg_expr(ObExprCGCtx &expr_cg_ctx, break; default : ret = OB_ERR_INVALID_TYPE_FOR_OP; - LOG_WARN("invalid type", K(ret), K(right_type)); + LOG_WARN("invalid type", K(ret), K(right_type), K(right_tc)); } } } - return OB_SUCCESS; + return ret; } } // namespace sql diff --git a/src/sql/engine/expr/ob_expr_array_contains_all.cpp b/src/sql/engine/expr/ob_expr_array_contains_all.cpp new file mode 100644 index 0000000000..48998da106 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_contains_all.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_contains_all. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_array_contains_all.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" + + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ + +ObExprArrayContainsAll::ObExprArrayContainsAll(ObIAllocator &alloc) + : ObExprArrayOverlaps(alloc, T_FUNC_SYS_ARRAY_CONTAINS_ALL, N_ARRAY_CONTAINS_ALL, 2, NOT_ROW_DIMENSION) +{ +} + +ObExprArrayContainsAll::~ObExprArrayContainsAll() +{ +} + +int ObExprArrayContainsAll::eval_array_contains_all(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + return eval_array_relations(expr, ctx, CONTAINS_ALL, res); +} + +int ObExprArrayContainsAll::eval_array_contains_all_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size) +{ + return eval_array_relations_batch(expr, ctx, skip, batch_size, CONTAINS_ALL); +} + +int ObExprArrayContainsAll::eval_array_contains_all_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + return eval_array_relation_vector(expr, ctx, skip, bound, CONTAINS_ALL); +} + +int ObExprArrayContainsAll::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_array_contains_all; + rt_expr.eval_batch_func_ = eval_array_contains_all_batch; + rt_expr.eval_vector_func_ = eval_array_contains_all_vector; + + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_array_contains_all.h b/src/sql/engine/expr/ob_expr_array_contains_all.h new file mode 100644 index 0000000000..992d8d6ac7 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_contains_all.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_contains_all. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ARRAY_CONTAINS_ALL +#define OCEANBASE_SQL_OB_EXPR_ARRAY_CONTAINS_ALL + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/udt/ob_array_type.h" + + +namespace oceanbase +{ +namespace sql +{ +class ObExprArrayContainsAll : public ObExprArrayOverlaps +{ +public: + explicit ObExprArrayContainsAll(common::ObIAllocator &alloc); + virtual ~ObExprArrayContainsAll(); + static int eval_array_contains_all(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_contains_all_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size); + static int eval_array_contains_all_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + + DISALLOW_COPY_AND_ASSIGN(ObExprArrayContainsAll); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ARRAY_CONTAINS_ALL \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_array_distinct.cpp b/src/sql/engine/expr/ob_expr_array_distinct.cpp new file mode 100644 index 0000000000..46932a1cad --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_distinct.cpp @@ -0,0 +1,233 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_overlaps. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_array_distinct.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" + + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ + +ObExprArrayDistinct::ObExprArrayDistinct(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_ARRAY_DISTINCT, N_ARRAY_DISTINCT, 1, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprArrayDistinct::ObExprArrayDistinct(ObIAllocator &alloc, + ObExprOperatorType type, + const char *name, + int32_t param_num, + int32_t dimension) : ObFuncExprOperator(alloc, type, name, param_num, VALID_FOR_GENERATED_COL, dimension) +{ +} + +ObExprArrayDistinct::~ObExprArrayDistinct() +{ +} + +int ObExprArrayDistinct::calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec ctx is null", K(ret)); + } else if ((!ob_is_collection_sql_type(type1.get_type()) && !type1.is_null())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid param type", K(ret), K(type1.get_type())); + } else if (type1.is_null()) { + // do nothing + } else { + type.set_collection(type1.get_subschema_id()); + } + + return ret; +} + +int ObExprArrayDistinct::eval_array_distinct(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObIArrayType *arr_obj = NULL; + ObIArrayType *arr_res = NULL; + ObDatum *datum = NULL; + bool bret = false; + if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (datum->is_null()) { + res.set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, meta_id, datum->get_string(), arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FAIL(arr_obj->distinct(tmp_allocator, arr_res))) { + LOG_WARN("array distinct failed", K(ret)); + } else if (OB_FAIL(arr_res->init())) { + LOG_WARN("array init failed", K(ret)); + } else { + ObString res_str; + if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_res, arr_res->get_raw_binary_len(), expr, ctx, res_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + res.set_string(res_str); + } + } + return ret; +} + +int ObExprArrayDistinct::eval_array_distinct_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, + const int64_t batch_size) +{ + int ret = OB_SUCCESS; + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObIArrayType *arr_obj = NULL; + ObIArrayType *arr_res = NULL; + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval date_unit_datum failed", K(ret)); + } else { + ObDatumVector in_array = expr.args_[0]->locate_expr_datumvector(ctx); + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { + if (skip.at(j) || eval_flags.at(j)) { + continue; + } + eval_flags.set(j); + bool bret = false; + if (in_array.at(j)->is_null()) { + res_datum.at(j)->set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, meta_id, in_array.at(j)->get_string(), arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FAIL(arr_obj->distinct(tmp_allocator, arr_res))) { + LOG_WARN("array distinct failed", K(ret)); + } else if (OB_FAIL(arr_res->init())) { + LOG_WARN("array init failed", K(ret)); + } else { + int32_t res_size = arr_res->get_raw_binary_len(); + char *res_buf = nullptr; + int64_t res_buf_len = 0; + ObTextStringDatumResult output_result(expr.datum_meta_.type_, &expr, &ctx, res_datum.at(j)); + if (OB_FAIL(output_result.init_with_batch_idx(res_size, j))) { + LOG_WARN("fail to init result", K(ret), K(res_size)); + } else if (OB_FAIL(output_result.get_reserved_buffer(res_buf, res_buf_len))) { + LOG_WARN("fail to get reserver buffer", K(ret)); + } else if (res_buf_len < res_size) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(arr_res->get_raw_binary(res_buf, res_buf_len))) { + LOG_WARN("get array raw binary failed", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(output_result.lseek(res_size, 0))) { + LOG_WARN("failed to lseek res.", K(ret), K(output_result), K(res_size)); + } else { + output_result.set_result(); + arr_res->clear(); + } + } + } + } + return ret; +} + +int ObExprArrayDistinct::eval_array_distinct_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound))) { + LOG_WARN("fail to eval params", K(ret)); + } else { + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + ObIVector *left_vec = expr.args_[0]->get_vector(ctx); + VectorFormat left_format = left_vec->get_format(); + const uint16_t left_meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObIVector *res_vec = expr.get_vector(ctx); + VectorFormat res_format = expr.get_format(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObIArrayType *l_arr_obj = NULL; + ObIArrayType *res_obj = NULL; + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { + bool is_null_res = false; + if (skip.at(idx) || eval_flags.at(idx)) { + continue; + } else if (left_vec->is_null(idx)) { + is_null_res = true; + } else if (left_format == VEC_UNIFORM || left_format == VEC_UNIFORM_CONST) { + ObString left = left_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, left_meta_id, left, l_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( + tmp_allocator, ctx, *expr.args_[0], left_meta_id, idx, l_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_vec->set_null(idx); + eval_flags.set(idx); + } else if (OB_FAIL(l_arr_obj->distinct(tmp_allocator, res_obj))) { + LOG_WARN("array distinct failed", K(ret)); + } else if (OB_FAIL(res_obj->init())) { + LOG_WARN("array init failed", K(ret)); + } else if (res_format == VEC_DISCRETE) { + if (OB_FAIL(ObArrayExprUtils::set_array_res(res_obj, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (res_format == VEC_UNIFORM) { + if (OB_FAIL(ObArrayExprUtils::set_array_res>(res_obj, expr, ctx, static_cast *>(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(res_obj, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + if (OB_SUCC(ret) && !is_null_res) { + eval_flags.set(idx); + res_obj->clear(); + } + } + } + return ret; +} + +int ObExprArrayDistinct::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_array_distinct; + rt_expr.eval_batch_func_ = eval_array_distinct_batch; + rt_expr.eval_vector_func_ = eval_array_distinct_vector; + + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_array_distinct.h b/src/sql/engine/expr/ob_expr_array_distinct.h new file mode 100644 index 0000000000..c5853dc394 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_distinct.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_distinct. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ARRAY_DISTINCT +#define OCEANBASE_SQL_OB_EXPR_ARRAY_DISTINCT + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" + + +namespace oceanbase +{ +namespace sql +{ +class ObExprArrayDistinct : public ObFuncExprOperator +{ +public: + explicit ObExprArrayDistinct(common::ObIAllocator &alloc); + explicit ObExprArrayDistinct(common::ObIAllocator &alloc, ObExprOperatorType type, + const char *name, int32_t param_num, int32_t dimension); + virtual ~ObExprArrayDistinct(); + virtual int calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_array_distinct(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_distinct_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size); + static int eval_array_distinct_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + + DISALLOW_COPY_AND_ASSIGN(ObExprArrayDistinct); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ARRAY_DISTINCT \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_array_map.cpp b/src/sql/engine/expr/ob_expr_array_map.cpp new file mode 100644 index 0000000000..1fd4a0ef81 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_map.cpp @@ -0,0 +1,427 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_array_map.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "lib/udt/ob_array_utils.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" + + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ + +OB_DEF_SERIALIZE(ObExprArrayMapInfo) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_ENCODE, serialization::make_ser_carray(param_exprs_, param_num_)); + if (OB_SUCC(ret)) { + if (param_num_ > 0) { + uint32_t len = sizeof(uint32_t) * param_num_; + MEMCPY(buf + pos, param_idx_, len); + pos += len; + } + } + return ret; +} + +OB_DEF_DESERIALIZE(ObExprArrayMapInfo) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_DECODE, serialization::make_ser_carray(param_exprs_, param_num_)); + if (OB_SUCC(ret)) { + if (param_num_ > 0) { + uint32_t len = sizeof(uint32_t) * param_num_; + param_idx_ = static_cast(allocator_.alloc(len)); + if (OB_ISNULL(param_idx_)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret), K(len)); + } else { + MEMCPY(param_idx_, buf + pos, len); + pos += len; + } + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObExprArrayMapInfo) +{ + int64_t len = 0; + LST_DO_CODE(OB_UNIS_ADD_LEN, serialization::make_ser_carray(param_exprs_, param_num_)); + if (param_num_ > 0) { + len += (sizeof(uint32_t) * param_num_); + } + return len; +} + +int ObExprArrayMapInfo::deep_copy(common::ObIAllocator &allocator, + const ObExprOperatorType type, + ObIExprExtraInfo *&copied_info) const +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObExprExtraInfoFactory::alloc(allocator, type, copied_info))) { + LOG_WARN("Failed to allocate memory for ObExprArrayMapInfo", K(ret)); + } else if (OB_ISNULL(copied_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("extra_info should not be nullptr", K(ret)); + } else if (param_num_ == 0) { + // do nothing + } else { + ObExprArrayMapInfo *other = static_cast(copied_info); + int64_t alloc_size = param_num_ * (sizeof(ObExpr *) + sizeof(uint32_t)); + char *buf = static_cast(allocator.alloc(alloc_size)); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret), K(alloc_size)); + } else { + other->param_exprs_ = reinterpret_cast(buf); + other->param_idx_ = reinterpret_cast(buf + (param_num_ * sizeof(ObExpr*))); + for (int64_t i = 0; i < param_num_; i++) { + other->param_exprs_[i] = param_exprs_[i]; + other->param_idx_[i] = param_idx_[i]; + } + } + } + return ret; +} + + +ObExprArrayMap::ObExprArrayMap(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_ARRAY_MAP, N_ARRAY_MAP, MORE_THAN_ONE, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprArrayMap::ObExprArrayMap(ObIAllocator &alloc, + ObExprOperatorType type, + const char *name, + int32_t param_num, + int32_t dimension) : ObFuncExprOperator(alloc, type, name, param_num, VALID_FOR_GENERATED_COL, dimension) +{ +} + +ObExprArrayMap::~ObExprArrayMap() +{ +} + +int ObExprArrayMap::calc_result_typeN(ObExprResType& type, + ObExprResType* types_stack, + int64_t param_num, + ObExprTypeCtx& type_ctx) const +{ + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + ObDataType elem_type; + uint16_t subschema_id; + bool is_null_res = false; + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec ctx is null", K(ret)); + } + for (int64_t i = 1; i < param_num && OB_SUCC(ret) && !is_null_res; i++) { + if (types_stack[i].is_null()) { + is_null_res = true; + } else if (!ob_is_collection_sql_type(types_stack[i].get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid data type", K(ret), K(types_stack[i].get_type())); + } + } + + if (OB_FAIL(ret)) { + } else if (is_null_res) { + } else { + if (types_stack[0].get_type() == ObDecimalIntType || types_stack[0].get_type() == ObNumberType) { + // decimalint isn't supported in array, so cast to supported type + ObObjType calc_type = ObIntType; + if (types_stack[0].get_scale() != 0) { + calc_type = ObDoubleType; + } + types_stack[0].set_calc_type(calc_type); + elem_type.set_meta_type(types_stack[0].get_calc_meta()); + elem_type.set_accuracy(ObAccuracy::DDL_DEFAULT_ACCURACY[calc_type]); + } else { + elem_type.set_meta_type(types_stack[0].get_obj_meta()); + elem_type.set_accuracy(types_stack[0].get_accuracy()); + } + if (ob_is_collection_sql_type(elem_type.get_obj_type())) { + if (OB_FAIL(ObArrayExprUtils::deduce_nested_array_subschema_id(exec_ctx, elem_type, subschema_id))) { + LOG_WARN("failed to deduce nested array subschema id", K(ret)); + } else { + type.set_collection(subschema_id); + } + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_collection_elem_type(ObNestedType::OB_ARRAY_TYPE, + elem_type, subschema_id))) { + LOG_WARN("failed to get collection subschema id", K(ret)); + } else { + type.set_collection(subschema_id); + } + } + return ret; +} + +int ObExprArrayMap::eval_array_map(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t res_meta_id = expr.obj_meta_.get_subschema_id(); + ObIArrayType *arr_res = NULL; + ObDatum *datum[expr.arg_cnt_]; + ObIArrayType *arr_obj[expr.arg_cnt_]; + ObDatum *datum_val = NULL; + bool is_null_res = false; + uint32_t arr_dim = 0; + bool bret = false; + ObSubSchemaValue value; + + for (int64_t i = 1; i < expr.arg_cnt_ && OB_SUCC(ret) && !is_null_res; i++) { + const uint16_t meta_id = expr.args_[i]->obj_meta_.get_subschema_id(); + arr_obj[i - 1] = NULL; + if (OB_FAIL(expr.args_[i]->eval(ctx, datum[i]))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (datum[i]->is_null()) { + is_null_res = true; + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, meta_id, datum[i]->get_string(), arr_obj[i - 1]))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (arr_dim == 0) { + arr_dim = arr_obj[i - 1]->size(); + } else if (arr_dim != arr_obj[i - 1]->size()) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("array dimension mismatch", K(ret), K(arr_dim), K(arr_obj[i - 1]->size()), K(i)); + } + } + + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res.set_null(); + } else if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator, ctx, res_meta_id, arr_res, false))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(res_meta_id, value))) { + LOG_WARN("failed to get subschema ctx", K(ret)); + } else if (value.type_ >= OB_SUBSCHEMA_MAX_TYPE) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema type", K(ret), K(value)); + } else { + const ObSqlCollectionInfo *coll_info = reinterpret_cast(value.value_); + ObCollectionArrayType *arr_type = static_cast(coll_info->collection_meta_); + ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); + ObExprArrayMapInfo *info = static_cast(expr.extra_info_); + ObIArrayType *child_obj = NULL; + for (uint32_t i = 0; i < arr_dim && OB_SUCC(ret); i++) { + ObSQLUtils::clear_expr_eval_flags(*expr.args_[0], ctx); + for (uint32_t j = 0; j < info->param_num_ && OB_SUCC(ret); j++) { + ObExpr *lambda_para = info->param_exprs_[j]; + uint32_t para_idx = info->param_idx_[j]; + if (para_idx >= (expr.arg_cnt_ - 1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid param idx", K(ret), K(para_idx), K(expr.arg_cnt_)); + } else if (lambda_para != NULL) { + if (arr_obj[para_idx]->is_null(i)) { + lambda_para->locate_datum_for_write(ctx).set_null(); + } else { + switch (lambda_para->obj_meta_.get_type()) { + case ObTinyIntType: { + ObArrayFixedSize *arr_ptr = static_cast *>(arr_obj[para_idx]); + int8_t val = (*arr_ptr)[i]; + lambda_para->locate_datum_for_write(ctx).set_int(val); + break; + } + case ObInt32Type: { + ObArrayFixedSize *arr_ptr = static_cast *>(arr_obj[para_idx]); + int32_t val = (*arr_ptr)[i]; + lambda_para->locate_datum_for_write(ctx).set_int32(val); + break; + } + case ObIntType: { + ObArrayFixedSize *arr_ptr = static_cast *>(arr_obj[para_idx]); + int64_t val = (*arr_ptr)[i]; + lambda_para->locate_datum_for_write(ctx).set_int(val); + break; + } + case ObUInt64Type: { + ObArrayFixedSize *arr_ptr = static_cast *>(arr_obj[para_idx]); + uint64_t val = (*arr_ptr)[i]; + lambda_para->locate_datum_for_write(ctx).set_uint(val); + break; + } + case ObFloatType: { + ObArrayFixedSize *arr_ptr = static_cast *>(arr_obj[para_idx]); + float val = (*arr_ptr)[i]; + lambda_para->locate_datum_for_write(ctx).set_float(val); + break; + } + case ObDoubleType: { + ObArrayFixedSize *arr_ptr = static_cast *>(arr_obj[para_idx]); + double val = (*arr_ptr)[i]; + lambda_para->locate_datum_for_write(ctx).set_double(val); + break; + } + case ObVarcharType: { + ObArrayBinary *binary_array = static_cast(arr_obj[para_idx]); + ObString val = (*binary_array)[i]; + lambda_para->locate_datum_for_write(ctx).set_string(val); + break; + } + case ObCollectionSQLType: { + ObArrayNested *nest_array = static_cast(arr_obj[para_idx]); + ObIArrayType *child_type = nest_array->get_child_array(); + ObString elem_str; + if (child_obj == NULL && OB_FAIL(child_type->clone_empty(tmp_allocator, child_obj, false))) { + LOG_WARN("clone empty failed", K(ret)); + } else if (FALSE_IT(child_obj->clear())) { + } else if (OB_FAIL(nest_array->at(i, *child_obj))) { + LOG_WARN("get array element failed", K(ret), K(i)); + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(child_obj, child_obj->get_raw_binary_len(), *lambda_para, ctx, elem_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + lambda_para->locate_datum_for_write(ctx).set_string(elem_str); + } + break; + } + default: { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported element type", K(ret), K(lambda_para->obj_meta_.get_type())); + } + } + } + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(expr.args_[0]->eval(ctx, datum_val))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (elem_type->type_id_ == ObNestedType::OB_BASIC_TYPE) { + if (OB_FAIL(ObArrayUtil::append(*arr_res, elem_type->basic_meta_.get_obj_type(), datum_val))) { + LOG_WARN("failed to append array value", K(ret), K(i)); + } + } else if (elem_type->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + uint16_t elem_subid = expr.args_[0]->obj_meta_.get_subschema_id(); + ObArrayNested *nest_array = static_cast(arr_res); + if (OB_FAIL(ObArrayExprUtils::add_elem_to_nested_array(tmp_allocator, ctx, elem_subid, *datum_val, nest_array))) { + LOG_WARN("failed to push back value", K(ret)); + } + } + } + if (OB_SUCC(ret)) { + ObString res_str; + if (OB_FAIL(arr_res->init())) { + LOG_WARN("array init failed", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_res, arr_res->get_raw_binary_len(), expr, ctx, res_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + res.set_string(res_str); + } + } + } + return ret; +} + +int ObExprArrayMap::get_array_map_lambda_params(const ObRawExpr *raw_expr, ObArray ¶m_idx, + ObArray ¶m_exprs) const +{ + int ret = OB_SUCCESS; + if (raw_expr->get_expr_type() == T_EXEC_VAR) { + const ObVarRawExpr *var_expr = static_cast(raw_expr); + int64_t idx = var_expr->get_ref_index(); + bool found = false; + if (OB_ISNULL(get_rt_expr(*raw_expr))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("expr is null", K(ret)); + } + for (uint32_t i = 0; i < param_idx.count() && found && OB_SUCC(ret); i++) { + if (idx == param_idx[i] && get_rt_expr(*raw_expr) == param_exprs[i]) { + found = true; + } else if (get_rt_expr(*raw_expr) == param_exprs[i]) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("param idx mismatch", K(ret), K(idx), K(param_idx[i])); + } + } + if (OB_SUCC(ret) && !found) { + if (OB_FAIL(param_idx.push_back(idx))) { + LOG_WARN("param idx append failed", K(ret), K(idx)); + } else if (OB_FAIL(param_exprs.push_back(get_rt_expr(*raw_expr)))) { + LOG_WARN("param expr append failed", K(ret), K(idx)); + } + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < raw_expr->get_param_count(); i++) { + const ObRawExpr *child_expr = NULL; + if (OB_ISNULL(child_expr = raw_expr->get_param_expr(i))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret)); + } else if (child_expr->get_expr_type() == T_FUNC_SYS_ARRAY_MAP) { + // do nothing + } else if (OB_FAIL(get_array_map_lambda_params(child_expr, param_idx, param_exprs))) { + LOG_WARN("construct array map info failed", K(ret)); + } + } + } + + return ret; +} + + +int ObExprArrayMap::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + ObIExprExtraInfo *extra_info = nullptr; + if (OB_FAIL(ObExprExtraInfoFactory::alloc(*expr_cg_ctx.allocator_, rt_expr.type_, extra_info))) { + LOG_WARN("Failed to allocate memory for ObExprArrayMapInfo", K(ret)); + } else if (OB_ISNULL(extra_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("extra_info should not be nullptr", K(ret)); + } else { + ObExprArrayMapInfo *var_params_info = static_cast(extra_info); + ObArray param_exprs; + ObArray param_idx; + if (OB_FAIL(get_array_map_lambda_params(&raw_expr, param_idx, param_exprs))) { + LOG_WARN("get array map lambda params failed", K(ret)); + } else if (param_exprs.count() == 0) { + // do nothing + } else { + int64_t alloc_size = param_exprs.count() * (sizeof(ObExpr *) + sizeof(uint32_t)); + var_params_info->param_num_ = param_exprs.count(); + char *buf = static_cast(expr_cg_ctx.allocator_->alloc(alloc_size)); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret), K(alloc_size)); + } else { + var_params_info->param_exprs_ = reinterpret_cast(buf); + var_params_info->param_idx_ = reinterpret_cast(buf + (param_exprs.count() * sizeof(ObExpr*))); + for (int64_t i = 0; OB_SUCC(ret) && i < param_exprs.count(); i++) { + var_params_info->param_exprs_[i] = param_exprs[i]; + var_params_info->param_idx_[i] = param_idx[i]; + } + } + } + if (OB_SUCC(ret)) { + rt_expr.extra_info_ = extra_info; + rt_expr.eval_func_ = eval_array_map; + } + } + return ret; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_array_map.h b/src/sql/engine/expr/ob_expr_array_map.h new file mode 100644 index 0000000000..9c20e67c2c --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_map.h @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_map. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ARRAY_MAP +#define OCEANBASE_SQL_OB_EXPR_ARRAY_MAP + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" + + +namespace oceanbase +{ +namespace sql +{ + +// used in expr.extra_ +struct ObExprArrayMapInfo : public ObIExprExtraInfo +{ + OB_UNIS_VERSION(1); +public: + ObExprArrayMapInfo(common::ObIAllocator &alloc, ObExprOperatorType type) + : ObIExprExtraInfo(alloc, type), + allocator_(alloc), + param_exprs_(NULL), + param_num_(0), + param_idx_(NULL) + { + } + + virtual int deep_copy(common::ObIAllocator &allocator, + const ObExprOperatorType type, + ObIExprExtraInfo *&copied_info) const override; + +public: + + // for deserialize + common::ObIAllocator &allocator_; + ObExpr** param_exprs_; + int64_t param_num_; + uint32_t* param_idx_; +}; + +class ObExprArrayMap : public ObFuncExprOperator +{ +public: + explicit ObExprArrayMap(common::ObIAllocator &alloc); + explicit ObExprArrayMap(common::ObIAllocator &alloc, ObExprOperatorType type, + const char *name, int32_t param_num, int32_t dimension); + virtual ~ObExprArrayMap(); + + virtual int calc_result_typeN(ObExprResType& type, + ObExprResType* types, + int64_t param_num, + common::ObExprTypeCtx& type_ctx) const override; + static int eval_array_map(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + + int get_array_map_lambda_params(const ObRawExpr *raw_expr, ObArray ¶m_idx, + ObArray ¶m_exprs) const; + DISALLOW_COPY_AND_ASSIGN(ObExprArrayMap); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ARRAY_MAP \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_array_overlaps.cpp b/src/sql/engine/expr/ob_expr_array_overlaps.cpp new file mode 100644 index 0000000000..9b5745be06 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_overlaps.cpp @@ -0,0 +1,263 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_overlaps. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_array_overlaps.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" + + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ + +ObExprArrayOverlaps::ObExprArrayOverlaps(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_ARRAY_OVERLAPS, N_ARRAY_OVERLAPS, 2, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprArrayOverlaps::ObExprArrayOverlaps(ObIAllocator &alloc, + ObExprOperatorType type, + const char *name, + int32_t param_num, + int32_t dimension) : ObFuncExprOperator(alloc, type, name, param_num, VALID_FOR_GENERATED_COL, dimension) +{ +} + +ObExprArrayOverlaps::~ObExprArrayOverlaps() +{ +} + +int ObExprArrayOverlaps::calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec ctx is null", K(ret)); + } else if ((!ob_is_collection_sql_type(type1.get_type()) && !type1.is_null()) + || (!ob_is_collection_sql_type(type2.get_type()) && !type2.is_null())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()), ob_obj_type_str(type2.get_type())); + } else if (type1.is_null() || type2.is_null()) { + // do nothing + } else if (type1.get_subschema_id() == type2.get_subschema_id()) { + // do nothing + } else { + ObExprResType coll_calc_type; + if (OB_FAIL(ObExprResultTypeUtil::get_array_calc_type(exec_ctx, type1, type2, coll_calc_type))) { + LOG_WARN("failed to check array compatibilty", K(ret)); + } else { + if (type1.get_subschema_id() != coll_calc_type.get_subschema_id()) { + type1.set_calc_meta(coll_calc_type); + } + if (type2.get_subschema_id() != coll_calc_type.get_subschema_id()) { + type2.set_calc_meta(coll_calc_type); + } + } + } + if (OB_SUCC(ret)) { + type.set_int32(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + } + + return ret; +} + +int ObExprArrayOverlaps::eval_array_relations(const ObExpr &expr, ObEvalCtx &ctx, Relation relation, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t l_meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t r_meta_id = expr.args_[1]->obj_meta_.get_subschema_id(); + ObIArrayType *l_arr_obj = NULL; + ObIArrayType *r_arr_obj = NULL; + ObDatum *l_datum = NULL; + ObDatum *r_datum = NULL; + bool bret = false; + if (OB_FAIL(expr.args_[0]->eval(ctx, l_datum))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval(ctx, r_datum))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (l_datum->is_null() || r_datum->is_null()) { + res.set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, l_meta_id, l_datum->get_string(), l_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, r_meta_id, r_datum->get_string(), r_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (relation == OVERLAPS && OB_FAIL(l_arr_obj->overlaps(*r_arr_obj, bret))) { + LOG_WARN("array overlaps failed", K(ret)); + } else if (relation == CONTAINS_ALL && OB_FAIL(l_arr_obj->contains_all(*r_arr_obj, bret))) { + LOG_WARN("array contains failed", K(ret)); + } else { + res.set_bool(bret); + } + return ret; +} + +int ObExprArrayOverlaps::eval_array_relations_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, + const int64_t batch_size, Relation relation) +{ + int ret = OB_SUCCESS; + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t l_meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t r_meta_id = expr.args_[1]->obj_meta_.get_subschema_id(); + ObIArrayType *l_arr_obj = NULL; + ObIArrayType *r_arr_obj = NULL; + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval date_unit_datum failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("failed to eval batch result args0", K(ret)); + } else { + ObDatumVector l_array = expr.args_[0]->locate_expr_datumvector(ctx); + ObDatumVector r_array = expr.args_[1]->locate_expr_datumvector(ctx); + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { + if (skip.at(j) || eval_flags.at(j)) { + continue; + } + eval_flags.set(j); + bool bret = false; + if (l_array.at(j)->is_null() || r_array.at(j)->is_null()) { + res_datum.at(j)->set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, l_meta_id, l_array.at(j)->get_string(), l_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, r_meta_id, r_array.at(j)->get_string(), r_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (relation == OVERLAPS && OB_FAIL(l_arr_obj->overlaps(*r_arr_obj, bret))) { + LOG_WARN("array overlaps failed", K(ret)); + } else if (relation == CONTAINS_ALL && OB_FAIL(l_arr_obj->contains_all(*r_arr_obj, bret))) { + LOG_WARN("array contains all failed", K(ret)); + } else { + res_datum.at(j)->set_bool(bret); + } + } + } + return ret; +} + +int ObExprArrayOverlaps::eval_array_relation_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound, + Relation relation) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound)) || OB_FAIL(expr.args_[1]->eval_vector(ctx, skip, bound))) { + LOG_WARN("fail to eval params", K(ret)); + } else { + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + ObIVector *left_vec = expr.args_[0]->get_vector(ctx); + VectorFormat left_format = left_vec->get_format(); + ObIVector *right_vec = expr.args_[1]->get_vector(ctx); + VectorFormat right_format = right_vec->get_format(); + const uint16_t left_meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t right_meta_id = expr.args_[1]->obj_meta_.get_subschema_id(); + ObIVector *res_vec = expr.get_vector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObIArrayType *l_arr_obj = NULL; + ObIArrayType *r_arr_obj = NULL; + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { + bool is_null_res = false; + if (skip.at(idx) || eval_flags.at(idx)) { + continue; + } else if (left_vec->is_null(idx) || right_vec->is_null(idx)) { + is_null_res = true; + } else if (left_format == VEC_UNIFORM || left_format == VEC_UNIFORM_CONST) { + ObString left = left_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, left_meta_id, left, l_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( + tmp_allocator, ctx, *expr.args_[0], left_meta_id, idx, l_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + // do nothing, set result at last + } else if (right_format == VEC_UNIFORM || right_format == VEC_UNIFORM_CONST) { + ObString right = right_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, right_meta_id, right, r_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( + tmp_allocator, ctx, *expr.args_[1], right_meta_id, idx, r_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + bool bret = false; + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_vec->set_null(idx); + eval_flags.set(idx); + } else if (relation == OVERLAPS && OB_FAIL(l_arr_obj->overlaps(*r_arr_obj, bret))) { + LOG_WARN("array overlaps failed", K(ret)); + } else if (relation == CONTAINS_ALL && OB_FAIL(l_arr_obj->contains_all(*r_arr_obj, bret))) { + LOG_WARN("array contains all failed", K(ret)); + } else { + res_vec->set_bool(idx, bret); + eval_flags.set(idx); + } + } + } + + return ret; +} + +int ObExprArrayOverlaps::eval_array_overlaps(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + return eval_array_relations(expr, ctx, OVERLAPS, res); +} + +int ObExprArrayOverlaps::eval_array_overlaps_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size) +{ + return eval_array_relations_batch(expr, ctx, skip, batch_size, OVERLAPS); +} + +int ObExprArrayOverlaps::eval_array_overlaps_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + return eval_array_relation_vector(expr, ctx, skip, bound, OVERLAPS); +} + +int ObExprArrayOverlaps::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_array_overlaps; + rt_expr.eval_batch_func_ = eval_array_overlaps_batch; + rt_expr.eval_vector_func_ = eval_array_overlaps_vector; + + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_array_overlaps.h b/src/sql/engine/expr/ob_expr_array_overlaps.h new file mode 100644 index 0000000000..034d8cadb3 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_overlaps.h @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_overlaps. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ARRAY_OVERLAPS +#define OCEANBASE_SQL_OB_EXPR_ARRAY_OVERLAPS + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/udt/ob_array_type.h" + + +namespace oceanbase +{ +namespace sql +{ +class ObExprArrayOverlaps : public ObFuncExprOperator +{ +public: + + enum Relation { + OVERLAPS = 0, + CONTAINS_ALL = 1, + }; + explicit ObExprArrayOverlaps(common::ObIAllocator &alloc); + explicit ObExprArrayOverlaps(common::ObIAllocator &alloc, ObExprOperatorType type, + const char *name, int32_t param_num, int32_t dimension); + virtual ~ObExprArrayOverlaps(); + virtual int calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_array_overlaps(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_overlaps_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size); + static int eval_array_overlaps_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound); + static int eval_array_relations(const ObExpr &expr, ObEvalCtx &ctx, Relation relation, ObDatum &res); + static int eval_array_relations_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, + const int64_t batch_size, Relation relation); + static int eval_array_relation_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound, + Relation relation); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + + DISALLOW_COPY_AND_ASSIGN(ObExprArrayOverlaps); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ARRAY_OVERLAPS \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_array_remove.cpp b/src/sql/engine/expr/ob_expr_array_remove.cpp new file mode 100644 index 0000000000..c7671c8917 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_remove.cpp @@ -0,0 +1,610 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_remove. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_array_remove.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" + + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ + +ObExprArrayRemove::ObExprArrayRemove(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_ARRAY_REMOVE, N_ARRAY_REMOVE, 2, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprArrayRemove::ObExprArrayRemove(ObIAllocator &alloc, + ObExprOperatorType type, + const char *name, + int32_t param_num, + int32_t dimension) : ObFuncExprOperator(alloc, type, name, param_num, VALID_FOR_GENERATED_COL, dimension) +{ +} + +ObExprArrayRemove::~ObExprArrayRemove() +{ +} + +int ObExprArrayRemove::calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + uint16_t subschema_id = type1.get_subschema_id(); + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec ctx is null", K(ret)); + } else if (type1.is_null()) { + // do nothing + } else if (!ob_is_collection_sql_type(type1.get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()), ob_obj_type_str(type2.get_type())); + } else if (type2.is_null()) { + // do nothing + } else if (OB_FAIL(ObArrayExprUtils::deduce_array_type(exec_ctx, type1, type2, subschema_id))) { + LOG_WARN("failed to get result array type subschema id", K(ret)); + } + if (OB_SUCC(ret) && !type1.is_null()) { + type.set_collection(subschema_id); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObCollectionSQLType]).get_length()); + } + + return ret; +} + +#define EVAL_FUNC_ARRAY_REMOVE(TYPE, GET_FUNC) \ + int ObExprArrayRemove::eval_array_remove_##TYPE(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) \ + { \ + int ret = OB_SUCCESS; \ + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); \ + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); \ + const uint16_t meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); \ + ObIArrayType *arr_obj = NULL; \ + ObIArrayType *res_arr_obj = NULL; \ + ObDatum *datum = NULL; \ + ObDatum *datum_val = NULL; \ + TYPE val; \ + bool bret = true; \ + bool changed = true; \ + if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) { \ + LOG_WARN("failed to eval args", K(ret)); \ + } else if (OB_FAIL(expr.args_[1]->eval(ctx, datum_val))) { \ + LOG_WARN("failed to eval args", K(ret)); \ + } else if (datum->is_null()) { \ + res.set_null(); \ + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, meta_id, datum->get_string(), arr_obj))) { \ + LOG_WARN("construct array obj failed", K(ret)); \ + } else if (datum_val->is_null() && !arr_obj->contain_null()) { \ + changed = false; \ + res_arr_obj = arr_obj; \ + } else if (!datum_val->is_null() && FALSE_IT(val = datum_val->GET_FUNC())) { \ + } else if (!datum_val->is_null() && OB_FAIL(ObArrayUtil::contains(*arr_obj, val, bret))) { \ + LOG_WARN("array contains failed", K(ret)); \ + } else if (!bret) { \ + changed = false; \ + res_arr_obj = arr_obj; \ + } \ + if (OB_SUCC(ret) && !datum->is_null()) { \ + if (changed) { \ + if (OB_FAIL(ObArrayUtil::clone_except(tmp_allocator, *arr_obj, &val, datum_val->is_null(), res_arr_obj))) { \ + LOG_WARN("array remove failed", K(ret)); \ + } \ + } \ + if (OB_SUCC(ret)) { \ + ObString res_str; \ + if (OB_FAIL(ObArrayExprUtils::set_array_res( \ + res_arr_obj, res_arr_obj->get_raw_binary_len(), expr, ctx, res_str))) { \ + LOG_WARN("get array binary string failed", K(ret)); \ + } else { \ + res.set_string(res_str); \ + } \ + } \ + } \ + return ret; \ + } + +EVAL_FUNC_ARRAY_REMOVE(int64_t, get_int) +EVAL_FUNC_ARRAY_REMOVE(float, get_float) +EVAL_FUNC_ARRAY_REMOVE(double, get_double) +EVAL_FUNC_ARRAY_REMOVE(ObString, get_string) + +int ObExprArrayRemove::eval_array_remove_array(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t r_meta_id = expr.args_[1]->obj_meta_.get_subschema_id(); + ObIArrayType *arr_obj = NULL; + ObIArrayType *remove_arr_obj = NULL; + ObIArrayType *res_arr_obj = NULL; + ObDatum *datum = NULL; + ObDatum *datum_val = NULL; + bool bret = true; + bool changed = true; + if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval(ctx, datum_val))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (datum->is_null()) { + res.set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, meta_id, datum->get_string(), arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (datum_val->is_null() && !arr_obj->contain_null()) { + changed = false; + res_arr_obj = arr_obj; + } else if (!datum_val->is_null() + && OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, r_meta_id, datum_val->get_string(), remove_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (remove_arr_obj != NULL && OB_FAIL(ObArrayUtil::contains(*arr_obj, *remove_arr_obj, bret))) { + LOG_WARN("array contains failed", K(ret)); + } else if (!bret) { + changed = false; + res_arr_obj = arr_obj; + } + if (OB_SUCC(ret) && !datum->is_null()) { + if (changed) { + if (OB_FAIL(ObArrayUtil::clone_except(tmp_allocator, *arr_obj, remove_arr_obj, datum_val->is_null(), res_arr_obj))) { + LOG_WARN("array remove failed", K(ret)); + } + } + if (OB_SUCC(ret)) { + ObString res_str; + if (OB_FAIL( + ObArrayExprUtils::set_array_res(res_arr_obj, res_arr_obj->get_raw_binary_len(), expr, ctx, res_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + res.set_string(res_str); + } + } + } + return ret; +} + +#define EVAL_FUNC_ARRAY_REMOVE_BATCH(TYPE, GET_FUNC) \ + int ObExprArrayRemove::eval_array_remove_batch_##TYPE( \ + const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size) \ + { \ + int ret = OB_SUCCESS; \ + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); \ + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); \ + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); \ + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); \ + const uint16_t meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); \ + ObIArrayType *arr_obj = NULL; \ + ObIArrayType *res_arr_obj = NULL; \ + ObDatum *datum = NULL; \ + ObDatum *datum_val = NULL; \ + TYPE val; \ + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { \ + LOG_WARN("failed to eval args", K(ret)); \ + } else if (OB_FAIL(expr.args_[1]->eval_batch(ctx, skip, batch_size))) { \ + LOG_WARN("failed to eval args", K(ret)); \ + } else { \ + ObDatumVector src_array = expr.args_[0]->locate_expr_datumvector(ctx); \ + ObDatumVector val_array = expr.args_[1]->locate_expr_datumvector(ctx); \ + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { \ + if (skip.at(j) || eval_flags.at(j)) { \ + continue; \ + } \ + eval_flags.set(j); \ + bool bret = true; \ + bool changed = true; \ + if (src_array.at(j)->is_null()) { \ + res_datum.at(j)->set_null(); \ + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj( \ + tmp_allocator, ctx, meta_id, src_array.at(j)->get_string(), arr_obj))) { \ + LOG_WARN("construct array obj failed", K(ret)); \ + } else if (val_array.at(j)->is_null() && !arr_obj->contain_null()) { \ + changed = false; \ + res_arr_obj = arr_obj; \ + } else if (!val_array.at(j)->is_null() && FALSE_IT(val = val_array.at(j)->GET_FUNC())) { \ + } else if (!val_array.at(j)->is_null() && OB_FAIL(ObArrayUtil::contains(*arr_obj, val, bret))) { \ + LOG_WARN("array contains failed", K(ret)); \ + } else if (!bret) { \ + changed = false; \ + res_arr_obj = arr_obj; \ + } \ + if (OB_SUCC(ret) && !src_array.at(j)->is_null()) { \ + if (changed) { \ + if (OB_FAIL(ObArrayUtil::clone_except( \ + tmp_allocator, *arr_obj, &val, val_array.at(j)->is_null(), res_arr_obj))) { \ + LOG_WARN("array remove failed", K(ret)); \ + } \ + } \ + if (OB_SUCC(ret)) { \ + int32_t res_size = res_arr_obj->get_raw_binary_len(); \ + char *res_buf = nullptr; \ + int64_t res_buf_len = 0; \ + ObTextStringDatumResult output_result(expr.datum_meta_.type_, &expr, &ctx, res_datum.at(j)); \ + if (OB_FAIL(output_result.init_with_batch_idx(res_size, j))) { \ + LOG_WARN("fail to init result", K(ret), K(res_size)); \ + } else if (OB_FAIL(output_result.get_reserved_buffer(res_buf, res_buf_len))) { \ + LOG_WARN("fail to get reserver buffer", K(ret)); \ + } else if (res_buf_len < res_size) { \ + ret = OB_ERR_UNEXPECTED; \ + LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); \ + } else if (OB_FAIL(res_arr_obj->get_raw_binary(res_buf, res_buf_len))) { \ + LOG_WARN("get array raw binary failed", K(ret), K(res_buf_len), K(res_size)); \ + } else if (OB_FAIL(output_result.lseek(res_size, 0))) { \ + LOG_WARN("failed to lseek res.", K(ret), K(output_result), K(res_size)); \ + } else { \ + output_result.set_result(); \ + res_arr_obj->clear(); \ + } \ + } \ + } \ + } \ + } \ + return ret; \ + } + +EVAL_FUNC_ARRAY_REMOVE_BATCH(int64_t, get_int) +EVAL_FUNC_ARRAY_REMOVE_BATCH(float, get_float) +EVAL_FUNC_ARRAY_REMOVE_BATCH(double, get_double) +EVAL_FUNC_ARRAY_REMOVE_BATCH(ObString, get_string) + +int ObExprArrayRemove::eval_array_remove_array_batch( + const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size) +{ + int ret = OB_SUCCESS; + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t r_meta_id = expr.args_[1]->obj_meta_.get_subschema_id(); + ObIArrayType *arr_obj = NULL; + ObIArrayType *remove_arr_obj = NULL; + ObIArrayType *res_arr_obj = NULL; + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("failed to eval args", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("failed to eval args", K(ret)); + } else { + ObDatumVector src_array = expr.args_[0]->locate_expr_datumvector(ctx); + ObDatumVector val_array = expr.args_[1]->locate_expr_datumvector(ctx); + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { + if (skip.at(j) || eval_flags.at(j)) { + continue; + } + eval_flags.set(j); + bool bret = true; + bool changed = true; + if (src_array.at(j)->is_null()) { + res_datum.at(j)->set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj( + tmp_allocator, ctx, meta_id, src_array.at(j)->get_string(), arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (val_array.at(j)->is_null() && !arr_obj->contain_null()) { + changed = false; + res_arr_obj = arr_obj; + } else if (!val_array.at(j)->is_null() && + OB_FAIL(ObArrayExprUtils::get_array_obj( + tmp_allocator, ctx, r_meta_id, val_array.at(j)->get_string(), remove_arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (!val_array.at(j)->is_null() && OB_FAIL(ObArrayUtil::contains(*arr_obj, *remove_arr_obj, bret))) { + LOG_WARN("array contains failed", K(ret)); + } else if (!bret) { + changed = false; + res_arr_obj = arr_obj; + } + if (OB_SUCC(ret) && !src_array.at(j)->is_null()) { + if (changed) { + if (OB_FAIL( + ObArrayUtil::clone_except(tmp_allocator, *arr_obj, remove_arr_obj, val_array.at(j)->is_null(), res_arr_obj))) { + LOG_WARN("array remove failed", K(ret)); + } + } + if (OB_SUCC(ret)) { + int32_t res_size = res_arr_obj->get_raw_binary_len(); + char *res_buf = nullptr; + int64_t res_buf_len = 0; + ObTextStringDatumResult output_result(expr.datum_meta_.type_, &expr, &ctx, res_datum.at(j)); + if (OB_FAIL(output_result.init_with_batch_idx(res_size, j))) { + LOG_WARN("fail to init result", K(ret), K(res_size)); + } else if (OB_FAIL(output_result.get_reserved_buffer(res_buf, res_buf_len))) { + LOG_WARN("fail to get reserver buffer", K(ret)); + } else if (res_buf_len < res_size) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(res_arr_obj->get_raw_binary(res_buf, res_buf_len))) { + LOG_WARN("get array raw binary failed", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(output_result.lseek(res_size, 0))) { + LOG_WARN("failed to lseek res.", K(ret), K(output_result), K(res_size)); + } else { + output_result.set_result(); + res_arr_obj->clear(); + } + } + } + } + } + return ret; +} + +#define EVAL_FUNC_ARRAY_REMOVE_VECTOR(TYPE, GET_FUNC) \ + int ObExprArrayRemove::eval_array_remove_vector_##TYPE( \ + const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound) \ + { \ + int ret = OB_SUCCESS; \ + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound)) || \ + OB_FAIL(expr.args_[1]->eval_vector(ctx, skip, bound))) { \ + LOG_WARN("fail to eval params", K(ret)); \ + } else { \ + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); \ + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); \ + ObIVector *left_vec = expr.args_[0]->get_vector(ctx); \ + VectorFormat left_format = left_vec->get_format(); \ + ObIVector *right_vec = expr.args_[1]->get_vector(ctx); \ + const uint16_t meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); \ + ObIVector *res_vec = expr.get_vector(ctx); \ + VectorFormat res_format = res_vec->get_format(); \ + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); \ + ObIArrayType *arr_obj = NULL; \ + TYPE val; \ + ObIArrayType *res_arr_obj = NULL; \ + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { \ + bool is_null_res = false; \ + bool bret = true; \ + bool changed = true; \ + if (skip.at(idx) || eval_flags.at(idx)) { \ + continue; \ + } else if (left_vec->is_null(idx)) { \ + is_null_res = true; \ + } else if (left_format == VEC_UNIFORM || left_format == VEC_UNIFORM_CONST) { \ + ObString left = left_vec->get_string(idx); \ + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, meta_id, left, arr_obj))) { \ + LOG_WARN("construct array obj failed", K(ret)); \ + } \ + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( \ + tmp_allocator, ctx, *expr.args_[0], meta_id, idx, arr_obj))) { \ + LOG_WARN("construct array obj failed", K(ret)); \ + } \ + if (OB_FAIL(ret)) { \ + } else if (is_null_res) { \ + } else if (right_vec->is_null(idx)) { \ + if (!arr_obj->contain_null()) { \ + changed = false; \ + res_arr_obj = arr_obj; \ + } \ + } else if (FALSE_IT(val = right_vec->GET_FUNC(idx))) { \ + } else if (OB_FAIL(ObArrayUtil::contains(*arr_obj, val, bret))) { \ + LOG_WARN("array contains failed", K(ret)); \ + } else if (!bret) { \ + changed = false; \ + res_arr_obj = arr_obj; \ + } \ + if (OB_FAIL(ret)) { \ + } else if (is_null_res) { \ + res_vec->set_null(idx); \ + eval_flags.set(idx); \ + } else { \ + if (changed) { \ + if (OB_FAIL( \ + ObArrayUtil::clone_except(tmp_allocator, *arr_obj, &val, right_vec->is_null(idx), res_arr_obj))) { \ + LOG_WARN("array remove failed", K(ret)); \ + } \ + } \ + if (OB_SUCC(ret)) { \ + if (res_format == VEC_DISCRETE) { \ + if (OB_FAIL(ObArrayExprUtils::set_array_res( \ + res_arr_obj, expr, ctx, static_cast(res_vec), idx))) { \ + LOG_WARN("set array res failed", K(ret)); \ + } \ + } else if (res_format == VEC_UNIFORM) { \ + if (OB_FAIL(ObArrayExprUtils::set_array_res>( \ + res_arr_obj, expr, ctx, static_cast *>(res_vec), idx))) { \ + LOG_WARN("set array res failed", K(ret)); \ + } \ + } else if (OB_FAIL(ObArrayExprUtils::set_array_res( \ + res_arr_obj, expr, ctx, static_cast(res_vec), idx))) { \ + LOG_WARN("set array res failed", K(ret)); \ + } \ + if (OB_SUCC(ret)) { \ + eval_flags.set(idx); \ + res_arr_obj->clear(); \ + } \ + } \ + } \ + } \ + } \ + return ret; \ + } + +EVAL_FUNC_ARRAY_REMOVE_VECTOR(int64_t, get_int) +EVAL_FUNC_ARRAY_REMOVE_VECTOR(float, get_float) +EVAL_FUNC_ARRAY_REMOVE_VECTOR(double, get_double) +EVAL_FUNC_ARRAY_REMOVE_VECTOR(ObString, get_string) + +int ObExprArrayRemove::eval_array_remove_array_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound)) || OB_FAIL(expr.args_[1]->eval_vector(ctx, skip, bound))) { + LOG_WARN("fail to eval params", K(ret)); + } else { + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + ObIVector *left_vec = expr.args_[0]->get_vector(ctx); + VectorFormat left_format = left_vec->get_format(); + ObIVector *right_vec = expr.args_[1]->get_vector(ctx); + VectorFormat right_format = right_vec->get_format(); + const uint16_t meta_id = expr.args_[0]->obj_meta_.get_subschema_id(); + const uint16_t r_meta_id = expr.args_[1]->obj_meta_.get_subschema_id(); + ObIVector *res_vec = expr.get_vector(ctx); + VectorFormat res_format = res_vec->get_format(); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObIArrayType *arr_obj = NULL; + ObIArrayType *arr_val = NULL; + ObIArrayType *res_arr_obj = NULL; + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { + bool is_null_res = false; + bool bret = true; + bool changed = true; + if (skip.at(idx) || eval_flags.at(idx)) { + continue; + } else if (left_vec->is_null(idx)) { + is_null_res = true; + } else if (left_format == VEC_UNIFORM || left_format == VEC_UNIFORM_CONST) { + ObString left = left_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, meta_id, left, arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param(tmp_allocator, ctx, *expr.args_[0], meta_id, idx, arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + // do noting + } else if (right_vec->is_null(idx)) { + if (!arr_obj->contain_null()) { + changed = false; + res_arr_obj = arr_obj; + } + } else if (right_format == VEC_UNIFORM || right_format == VEC_UNIFORM_CONST) { + ObString right = right_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, r_meta_id, right, arr_val))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param(tmp_allocator, ctx, *expr.args_[1], r_meta_id, idx, arr_val))) { + LOG_WARN("construct array obj failed", K(ret)); + } + + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_vec->set_null(idx); + eval_flags.set(idx); + } else if (!right_vec->is_null(idx) && OB_FAIL(ObArrayUtil::contains(*arr_obj, *arr_val, bret))) { + LOG_WARN("array contains failed", K(ret)); + } else if (!bret) { + changed = false; + res_arr_obj = arr_obj; + } + + if (OB_SUCC(ret) && !is_null_res) { + if (changed) { + if (OB_FAIL(ObArrayUtil::clone_except(tmp_allocator, *arr_obj, arr_val, right_vec->is_null(idx), res_arr_obj))) { + LOG_WARN("array remove failed", K(ret)); + } + } + if (OB_SUCC(ret)) { + if (res_format == VEC_DISCRETE) { + if (OB_FAIL(ObArrayExprUtils::set_array_res(res_arr_obj, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (res_format == VEC_UNIFORM) { + if (OB_FAIL(ObArrayExprUtils::set_array_res>(res_arr_obj, expr, ctx, static_cast *>(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(res_arr_obj, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + if (OB_SUCC(ret)) { + eval_flags.set(idx); + res_arr_obj->clear(); + } + } + } + } + } + + return ret; +} + + +int ObExprArrayRemove::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + UNUSED(raw_expr); + if (rt_expr.arg_cnt_ != 2 || OB_ISNULL(rt_expr.args_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("count of children is not 2 or children is null", K(ret), K(rt_expr.arg_cnt_), + K(rt_expr.args_)); + } else if (OB_ISNULL(rt_expr.args_[0]) || OB_ISNULL(rt_expr.args_[1])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("child is null", K(ret), K(rt_expr.args_[0]), K(rt_expr.args_[1])); + } else { + rt_expr.eval_func_ = NULL; + const ObObjType right_type = rt_expr.args_[1]->datum_meta_.type_; + ObObjTypeClass right_tc = ob_obj_type_class(right_type); + if (right_tc == ObNullTC) { + // use array element type + ObExecContext *exec_ctx = expr_cg_ctx.session_->get_cur_exec_ctx(); + const uint16_t sub_id = rt_expr.args_[0]->obj_meta_.get_subschema_id(); + ObObjType elem_type; + uint32_t unused; + bool is_vec = false; + if (OB_FAIL(ObArrayExprUtils::get_array_element_type(exec_ctx, sub_id, elem_type, unused, is_vec))) { + LOG_WARN("failed to get collection elem type", K(ret), K(sub_id)); + } else { + right_tc = ob_obj_type_class(elem_type); + } + } + if OB_SUCC(ret) { + switch (right_tc) { + case ObIntTC: + rt_expr.eval_func_ = eval_array_remove_int64_t; + rt_expr.eval_batch_func_ = eval_array_remove_batch_int64_t; + rt_expr.eval_vector_func_ = eval_array_remove_vector_int64_t; + break; + case ObFloatTC: + rt_expr.eval_func_ = eval_array_remove_float; + rt_expr.eval_batch_func_ = eval_array_remove_batch_float; + rt_expr.eval_vector_func_ = eval_array_remove_vector_float; + break; + case ObDoubleTC: + rt_expr.eval_func_ = eval_array_remove_double; + rt_expr.eval_batch_func_ = eval_array_remove_batch_double; + rt_expr.eval_vector_func_ = eval_array_remove_vector_double; + break; + case ObStringTC: + rt_expr.eval_func_ = eval_array_remove_ObString; + rt_expr.eval_batch_func_ = eval_array_remove_batch_ObString; + rt_expr.eval_vector_func_ = eval_array_remove_vector_ObString; + break; + case ObNullTC: + case ObCollectionSQLTC: + rt_expr.eval_func_ = eval_array_remove_array; + rt_expr.eval_batch_func_ = eval_array_remove_array_batch; + rt_expr.eval_vector_func_ = eval_array_remove_array_vector; + break; + default : + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid type", K(ret), K(right_type)); + } + } + } + + return ret; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_array_remove.h b/src/sql/engine/expr/ob_expr_array_remove.h new file mode 100644 index 0000000000..b0d64a1aa1 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_remove.h @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_remove. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ARRAY_REMOVE +#define OCEANBASE_SQL_OB_EXPR_ARRAY_REMOVE + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" + + +namespace oceanbase +{ +namespace sql +{ +class ObExprArrayRemove : public ObFuncExprOperator +{ +public: + explicit ObExprArrayRemove(common::ObIAllocator &alloc); + explicit ObExprArrayRemove(common::ObIAllocator &alloc, ObExprOperatorType type, + const char *name, int32_t param_num, int32_t dimension); + virtual ~ObExprArrayRemove(); + virtual int calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_array_remove_int64_t(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_remove_float(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_remove_double(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_remove_ObString(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_remove_array(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_remove_array_batch(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size); + static int eval_array_remove_batch_int64_t(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size); + static int eval_array_remove_batch_float(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size); + static int eval_array_remove_batch_double(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size); + static int eval_array_remove_batch_ObString(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const int64_t batch_size); + static int eval_array_remove_vector_int64_t(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound); + static int eval_array_remove_vector_float(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound); + static int eval_array_remove_vector_double(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound); + static int eval_array_remove_vector_ObString(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound); + static int eval_array_remove_array_vector(const ObExpr &expr, ObEvalCtx &ctx, const ObBitVector &skip, const EvalBound &bound); + + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + + DISALLOW_COPY_AND_ASSIGN(ObExprArrayRemove); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ARRAY_REMOVE \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_array_to_string.cpp b/src/sql/engine/expr/ob_expr_array_to_string.cpp new file mode 100644 index 0000000000..8d15cd9d17 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_to_string.cpp @@ -0,0 +1,332 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_to_string expression. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_array_to_string.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ +ObExprArrayToString::ObExprArrayToString(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_ARRAY_TO_STRING, N_ARRAY_TO_STRING, TWO_OR_THREE, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprArrayToString::~ObExprArrayToString() +{ +} + +int ObExprArrayToString::calc_result_typeN(ObExprResType &type, + ObExprResType *types, + int64_t param_num, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = NULL; + ObExecContext *exec_ctx = NULL; + ObExprResType *array_type = &types[0]; + ObExprResType *delimiter_type = &types[1]; + ObSubSchemaValue arr_meta; + + if (OB_ISNULL(session = const_cast(type_ctx.get_session()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ObSQLSessionInfo is null", K(ret)); + } else if (OB_ISNULL(exec_ctx = session->get_cur_exec_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ObExecContext is null", K(ret)); + } else if (ob_is_null(array_type->get_type())) { + // do nothing + } else if (!ob_is_collection_sql_type(array_type->get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "ARRAY", ob_obj_type_str(array_type->get_type())); + } else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(array_type->get_subschema_id(), arr_meta))) { + LOG_WARN("failed to get elem meta.", K(ret), K(array_type->get_subschema_id())); + } else if (arr_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid subschema type", K(ret), K(arr_meta.type_)); + } + if (OB_FAIL(ret)) { + } else if (!ob_is_string_tc(delimiter_type->get_type()) && !ob_is_null(delimiter_type->get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "VARCHAR", ob_obj_type_str(delimiter_type->get_type())); + } else if (param_num == 3) { + ObExprResType *null_str_type = &types[2]; + if (!ob_is_string_tc(null_str_type->get_type()) && !ob_is_null(null_str_type->get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "VARCHAR", ob_obj_type_str(null_str_type->get_type())); + } + } + + if (OB_SUCC(ret)) { + type.set_type(ObLongTextType); + type.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI); + type.set_collation_level(CS_LEVEL_IMPLICIT); + type.set_accuracy(ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType]); + } + + return ret; +} + +int ObExprArrayToString::eval_array_to_string(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObDatum *arr_datum = NULL; + ObDatum *delimiter_datum = NULL; + ObDatum *null_str_datum = NULL; + ObSubSchemaValue meta; + ObCollectionArrayType *arr_type = NULL; + const ObSqlCollectionInfo *src_coll_info = NULL; + bool is_null_res = false; + ObIArrayType *arr_obj = NULL; + ObString delimiter; + ObString null_str; + bool has_null_str = false; + + if (OB_FAIL(expr.args_[0]->eval(ctx, arr_datum))) { + LOG_WARN("failed to eval source array arg", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval(ctx, delimiter_datum))) { + LOG_WARN("failed to eval delimiter string arg", K(ret)); + } else if (expr.arg_cnt_ > 2 && OB_FAIL(expr.args_[2]->eval(ctx, null_str_datum))) { + LOG_WARN("failed to eval null string arg", K(ret)); + } else if (arr_datum->is_null() || delimiter_datum->is_null()) { + is_null_res = true; + } else if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get subschema meta", K(ret), K(subschema_id)); + } else if (OB_ISNULL(src_coll_info = reinterpret_cast(meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection info is null", K(ret)); + } else if (OB_ISNULL(arr_type = static_cast(src_coll_info->collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection array type is null", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, arr_datum->get_string(), arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FALSE_IT(delimiter = delimiter_datum->get_string())) { + } else if (expr.arg_cnt_ > 2 && !null_str_datum->is_null()) { + has_null_str = true; + null_str = null_str_datum->get_string(); + } + + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res.set_null(); + } else { + ObStringBuffer res_buf(&tmp_allocator); + ObTextStringDatumResult str_result(expr.datum_meta_.type_, &expr, &ctx, &res); + if (OB_FAIL(arr_obj->print_element(arr_type->element_type_, res_buf, 0, 0, delimiter, has_null_str, null_str))) { + LOG_WARN("failed to format array", K(ret)); + } else if (OB_FAIL(str_result.init(res_buf.length()))) { + LOG_WARN("failed to init result", K(ret), K(res_buf.length())); + } else if (OB_FAIL(str_result.append(res_buf.ptr(), res_buf.length()))) { + LOG_WARN("failed to append realdata", K(ret), K(res_buf)); + } else { + str_result.set_result(); + } + } + return ret; +} + +int ObExprArrayToString::eval_array_to_string_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size) +{ + int ret = OB_SUCCESS; + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObSubSchemaValue meta; + ObCollectionArrayType *arr_type = NULL; + const ObSqlCollectionInfo *src_coll_info = NULL; + ObIArrayType *arr_obj = NULL; + + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval delimiter string failed", K(ret)); + } else if (OB_FAIL(expr.arg_cnt_ > 2 && expr.args_[2]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval null string failed", K(ret)); + } else { + ObDatumVector arr_array = expr.args_[0]->locate_expr_datumvector(ctx); + ObDatumVector delimiter_array = expr.args_[1]->locate_expr_datumvector(ctx); + ObDatumVector null_str_array = expr.arg_cnt_ > 2 ? expr.args_[2]->locate_expr_datumvector(ctx) : ObDatumVector(); + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { + bool is_null_res = false; + ObString delimiter; + ObString null_str; + bool has_null_str = false; + if (skip.at(j) || eval_flags.at(j)) { + continue; + } + eval_flags.set(j); + if (arr_array.at(j)->is_null() || delimiter_array.at(j)->is_null()) { + is_null_res = true; + } else if (OB_ISNULL(arr_type)) { + if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get subschema meta", K(ret), K(subschema_id)); + } else if (OB_ISNULL(src_coll_info = reinterpret_cast(meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection info is null", K(ret)); + } else if (OB_ISNULL(arr_type = static_cast(src_coll_info->collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection array type is null", K(ret)); + } + } + if (OB_FAIL(ret) || is_null_res) { + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, arr_array.at(j)->get_string(), arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FALSE_IT(delimiter = delimiter_array.at(j)->get_string())) { + } else if (expr.arg_cnt_ > 2 && !null_str_array.at(j)->is_null()) { + has_null_str = true; + null_str = null_str_array.at(j)->get_string(); + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_datum.at(j)->set_null(); + } else { + ObStringBuffer res_buf(&tmp_allocator); + ObTextStringDatumResult str_result(expr.datum_meta_.type_, &expr, &ctx, res_datum.at(j)); + if (OB_FAIL(arr_obj->print_element(arr_type->element_type_, res_buf, 0, 0, delimiter, has_null_str, null_str))) { + LOG_WARN("failed to format array", K(ret)); + } else if (OB_FAIL(str_result.init_with_batch_idx(res_buf.length(), j))) { + LOG_WARN("failed to init result", K(ret), K(res_buf.length()), K(j)); + } else if (OB_FAIL(str_result.append(res_buf.ptr(), res_buf.length()))) { + LOG_WARN("failed to append realdata", K(ret), K(res_buf)); + } else { + str_result.set_result(); + } + } + } // end for + } + return ret; +} + +int ObExprArrayToString::eval_array_to_string_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObSubSchemaValue meta; + ObCollectionArrayType *arr_type = NULL; + const ObSqlCollectionInfo *src_coll_info = NULL; + ObIArrayType *arr_obj = NULL; + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval delimiter string failed", K(ret)); + } else if (OB_FAIL(expr.arg_cnt_ > 2 && expr.args_[2]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval null string failed", K(ret)); + } else { + ObIVector *arr_vec = expr.args_[0]->get_vector(ctx); + VectorFormat arr_format = arr_vec->get_format(); + ObIVector *delimiter_vec = expr.args_[1]->get_vector(ctx); + ObIVector *null_str_vec = expr.arg_cnt_ > 2 ? expr.args_[2]->get_vector(ctx) : NULL; + ObIVector *res_vec = expr.get_vector(ctx); + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + VectorFormat res_format = expr.get_format(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { + bool is_null_res = false; + ObString delimiter; + ObString null_str; + bool has_null_str = false; + if (skip.at(idx) || eval_flags.at(idx)) { + continue; + } else if (arr_vec->is_null(idx) || delimiter_vec->is_null(idx)) { + is_null_res = true; + } else if (OB_ISNULL(arr_type)) { + if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get subschema meta", K(ret), K(subschema_id)); + } else if (OB_ISNULL(src_coll_info = reinterpret_cast(meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection info is null", K(ret)); + } else if (OB_ISNULL(arr_type = static_cast(src_coll_info->collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection array type is null", K(ret)); + } + } + if (OB_FAIL(ret) || is_null_res) { + } else if (arr_format == VEC_UNIFORM || arr_format == VEC_UNIFORM_CONST) { + ObString arr_str = arr_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, subschema_id, arr_str, arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( + tmp_allocator, ctx, *expr.args_[0], subschema_id, idx, arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_FAIL(ret) || is_null_res) { + } else if (OB_FALSE_IT(delimiter = delimiter_vec->get_string(idx))) { + } else if (expr.arg_cnt_ > 2 && !null_str_vec->is_null(idx)) { + has_null_str = true; + null_str = null_str_vec->get_string(idx); + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_vec->set_null(idx); + eval_flags.set(idx); + } else { + ObStringBuffer res_buf(&tmp_allocator); + if (OB_FAIL(arr_obj->print_element(arr_type->element_type_, res_buf, 0, 0, delimiter, has_null_str, null_str))) { + LOG_WARN("failed to format array", K(ret)); + } else { + if (res_format == VEC_DISCRETE) { + if (OB_FAIL(set_text_res(res_buf, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (res_format == VEC_UNIFORM) { + if (OB_FAIL(set_text_res>(res_buf, expr, ctx, static_cast *>(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (OB_FAIL(set_text_res(res_buf, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } + if (OB_SUCC(ret)) { + eval_flags.set(idx); + } + } + } // end for + } + return ret; +} + +int ObExprArrayToString::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_array_to_string; + rt_expr.eval_batch_func_ = eval_array_to_string_batch; + rt_expr.eval_vector_func_ = eval_array_to_string_vector; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_array_to_string.h b/src/sql/engine/expr/ob_expr_array_to_string.h new file mode 100644 index 0000000000..c60498aa03 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_array_to_string.h @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for array_to_string expression. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ARRAY_TO_STRING +#define OCEANBASE_SQL_OB_EXPR_ARRAY_TO_STRING + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprArrayToString : public ObFuncExprOperator +{ +public: + explicit ObExprArrayToString(common::ObIAllocator &alloc); + + virtual ~ObExprArrayToString(); + + virtual int calc_result_typeN(ObExprResType &type, + ObExprResType *types, + int64_t param_num, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_array_to_string(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_array_to_string_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size); + static int eval_array_to_string_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound); + template + static int set_text_res(ObStringBuffer &res_buf, const ObExpr &expr, ObEvalCtx &ctx, + ResVec *res_vec, int64_t batch_idx) + { + int ret = OB_SUCCESS; + char *buf = nullptr; + int64_t len = 0; + ObTextStringVectorResult str_result(expr.datum_meta_.type_, &expr, &ctx, res_vec, batch_idx); + if (OB_FAIL(str_result.init_with_batch_idx(res_buf.length(), batch_idx))) { + SQL_ENG_LOG(WARN, "fail to init result", K(ret), K(res_buf.length())); + } else if (OB_FAIL(str_result.get_reserved_buffer(buf, len))) { + SQL_ENG_LOG(WARN, "fail to get reserver buffer", K(ret)); + } else if (len < res_buf.length()) { + ret = OB_ERR_UNEXPECTED; + SQL_ENG_LOG(WARN, "get invalid res buf len", K(ret), K(len), K(res_buf.length())); + } else if (OB_FALSE_IT(MEMCPY(buf, res_buf.ptr(), res_buf.length()))) { + } else if (OB_FAIL(str_result.lseek(len, 0))) { + SQL_ENG_LOG(WARN, "failed to lseek res.", K(ret), K(str_result), K(len)); + } else { + str_result.set_result(); + } + return ret; + } + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + DISALLOW_COPY_AND_ASSIGN(ObExprArrayToString); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ARRAY_TO_STRING \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_element_at.cpp b/src/sql/engine/expr/ob_expr_element_at.cpp new file mode 100644 index 0000000000..44fc8506ae --- /dev/null +++ b/src/sql/engine/expr/ob_expr_element_at.cpp @@ -0,0 +1,390 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for element_at expression. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_element_at.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/expr/ob_array_cast.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ +ObExprElementAt::ObExprElementAt(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_ELEMENT_AT, N_ELEMENT_AT, 2, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprElementAt::~ObExprElementAt() +{ +} + +int ObExprElementAt::calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObDataType res_data_type; + ObSQLSessionInfo *session = NULL; + ObExecContext *exec_ctx = NULL; + ObSubSchemaValue arr_meta; + + if (OB_ISNULL(session = const_cast(type_ctx.get_session()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ObSQLSessionInfo is null", K(ret)); + } else if (OB_ISNULL(exec_ctx = session->get_cur_exec_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ObExecContext is null", K(ret)); + } else if (!ob_is_collection_sql_type(type1.get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "ARRAY", ob_obj_type_str(type1.get_type())); + } else if (!ob_is_integer_type(type2.get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "INTEGER", ob_obj_type_str(type2.get_type())); + } else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(type1.get_subschema_id(), arr_meta))) { + LOG_WARN("failed to get elem meta.", K(ret), K(type1.get_subschema_id())); + } else { + const ObSqlCollectionInfo *coll_info = reinterpret_cast(arr_meta.value_); + ObCollectionArrayType *arr_type = static_cast(coll_info->collection_meta_); + if (arr_type->element_type_->type_id_ == ObNestedType::OB_BASIC_TYPE) { + ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); + type.set_meta(elem_type->basic_meta_.get_meta_type()); + type.set_accuracy(elem_type->basic_meta_.get_accuracy()); + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + ObString child_def; + uint16_t child_subschema_id = 0; + if (OB_FAIL(coll_info->get_child_def_string(child_def))) { + LOG_WARN("failed to get child define", K(ret), K(*coll_info)); + } else if (OB_FAIL(session->get_cur_exec_ctx()->get_subschema_id_by_type_string(child_def, child_subschema_id))) { + LOG_WARN("failed to get child subschema id", K(ret), K(*coll_info), K(child_def)); + } else { + type.set_collection(child_subschema_id); + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_VECTOR_TYPE) { + type.set_float(); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected ObNestedType type", K(ret), K(arr_type->element_type_->type_id_)); + } + } + return ret; +} + +int ObExprElementAt::eval_element_at(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObSubSchemaValue meta; + ObCollectionArrayType *arr_type = NULL; + const ObSqlCollectionInfo *src_coll_info = NULL; + ObIArrayType *src_arr = NULL; + int64_t idx = 0; + ObDatum *arr_datum = NULL; + ObDatum *idx_datum = NULL; + + if (OB_FAIL(expr.args_[0]->eval(ctx, arr_datum))) { + LOG_WARN("failed to eval source array arg", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval(ctx, idx_datum))) { + LOG_WARN("failed to eval index arg", K(ret)); + } else if (arr_datum->is_null() || idx_datum->is_null()) { + res.set_null(); + } else if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get subschema value", K(ret), K(subschema_id)); + } else if (OB_ISNULL(src_coll_info = reinterpret_cast(meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection info is null", K(ret)); + } else if (OB_ISNULL(arr_type = static_cast(src_coll_info->collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection array type is null", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, arr_datum->get_string(), src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FALSE_IT(idx = idx_datum->get_int() - 1)) { + } else if (idx < 0 || idx > src_arr->size() - 1 || idx > UINT32_MAX) { + res.set_null(); + } else if (src_arr->get_format() != ArrayFormat::Vector && src_arr->is_null(idx)) { + res.set_null(); + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_BASIC_TYPE) { + ObObj elem_obj; + ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); + if (OB_FAIL(ObArrayCastUtils::cast_get_element(src_arr, elem_type, static_cast(idx), elem_obj))) { + LOG_WARN("failed to cast get element", K(ret)); + } else { + res.from_obj(elem_obj); + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + uint16_t child_subschema_id = expr.obj_meta_.get_subschema_id(); + ObIArrayType* child_arr = NULL; + ObString child_arr_str; + if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator,ctx, child_subschema_id, child_arr, false))) { + LOG_WARN("construct child array obj failed", K(ret)); + } else if (OB_FAIL(src_arr->at(static_cast(idx), *child_arr))) { + LOG_WARN("failed to get child array", K(ret), K(idx)); + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(child_arr, child_arr->get_raw_binary_len(), expr, ctx, child_arr_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + res.set_string(child_arr_str); + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_VECTOR_TYPE) { + float *vector_data = reinterpret_cast(src_arr->get_data()); + res.set_float(vector_data[idx]); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid element type", K(ret), K(arr_type->element_type_->type_id_)); + } + return ret; +} + +int ObExprElementAt::eval_element_at_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size) +{ + int ret = OB_SUCCESS; + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObSubSchemaValue meta; + ObCollectionArrayType *arr_type = NULL; + const ObSqlCollectionInfo *src_coll_info = NULL; + ObIArrayType *src_arr = NULL; + ObIArrayType* child_arr = NULL; + + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval index failed", K(ret)); + } else { + ObDatumVector arr_array = expr.args_[0]->locate_expr_datumvector(ctx); + ObDatumVector idx_array = expr.args_[1]->locate_expr_datumvector(ctx); + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { + bool is_null_res = false; + int64_t idx = 0; + if (skip.at(j) || eval_flags.at(j)) { + continue; + } + eval_flags.set(j); + if (arr_array.at(j)->is_null()) { + is_null_res = true; + } else if (OB_ISNULL(arr_type)) { + if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get subschema value", K(ret), K(subschema_id)); + } else if (OB_ISNULL(src_coll_info = reinterpret_cast(meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection info is null", K(ret)); + } else if (OB_ISNULL(arr_type = static_cast(src_coll_info->collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection array type is null", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_datum.at(j)->set_null(); + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, arr_array.at(j)->get_string(), src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (OB_FALSE_IT(idx = idx_array.at(j)->get_int() - 1)) { + } else if (idx < 0 || idx > src_arr->size() - 1 || idx > UINT32_MAX) { + res_datum.at(j)->set_null(); + } else if (src_arr->get_format() != ArrayFormat::Vector && src_arr->is_null(idx)) { + res_datum.at(j)->set_null(); + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_BASIC_TYPE) { + ObObj elem_obj; + ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); + if (OB_FAIL(ObArrayCastUtils::cast_get_element(src_arr, elem_type, static_cast(idx), elem_obj))) { + LOG_WARN("failed to cast get element", K(ret)); + } else { + res_datum.at(j)->from_obj(elem_obj); + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + uint16_t child_subschema_id = expr.obj_meta_.get_subschema_id(); + ObString child_arr_str; + if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator,ctx, child_subschema_id, child_arr, false))) { + LOG_WARN("construct child array obj failed", K(ret)); + } else if (OB_FALSE_IT(child_arr->clear())) { + } else if (OB_FAIL(src_arr->at(static_cast(idx), *child_arr))) { + LOG_WARN("failed to get child array", K(ret), K(idx)); + } else { + int32_t res_size = child_arr->get_raw_binary_len(); + char *res_buf = nullptr; + int64_t res_buf_len = 0; + ObTextStringDatumResult output_result(expr.datum_meta_.type_, &expr, &ctx, res_datum.at(j)); + if (OB_FAIL(output_result.init_with_batch_idx(res_size, j))) { + LOG_WARN("fail to init result", K(ret), K(res_size)); + } else if (OB_FAIL(output_result.get_reserved_buffer(res_buf, res_buf_len))) { + LOG_WARN("fail to get reserver buffer", K(ret)); + } else if (res_buf_len < res_size) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(child_arr->get_raw_binary(res_buf, res_buf_len))) { + LOG_WARN("get array raw binary failed", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(output_result.lseek(res_size, 0))) { + LOG_WARN("failed to lseek res.", K(ret), K(output_result), K(res_size)); + } else { + output_result.set_result(); + } + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_VECTOR_TYPE) { + float *vector_data = reinterpret_cast(src_arr->get_data()); + res_datum.at(j)->set_float(vector_data[idx]); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid element type", K(ret), K(arr_type->element_type_->type_id_)); + } + } // end for + } + return ret; +} + +int ObExprElementAt::eval_element_at_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObSubSchemaValue meta; + ObCollectionArrayType *arr_type = NULL; + const ObSqlCollectionInfo *src_coll_info = NULL; + ObIArrayType *src_arr = NULL; + ObIArrayType* child_arr = NULL; + + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval index failed", K(ret)); + } else { + ObIVector *arr_vec = expr.args_[0]->get_vector(ctx); + VectorFormat arr_format = arr_vec->get_format(); + ObIVector *idx_vec = expr.args_[1]->get_vector(ctx); + ObIVector *res_vec = expr.get_vector(ctx); + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + VectorFormat res_format = expr.get_format(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { + bool is_null_res = false; + int64_t arr_idx = 0; + if (skip.at(idx) || eval_flags.at(idx)) { + continue; + } + if (arr_vec->is_null(idx)) { + is_null_res = true; + } else if (OB_ISNULL(arr_type)) { + if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get subschema meta", K(ret), K(subschema_id)); + } else if (OB_ISNULL(src_coll_info = reinterpret_cast(meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection info is null", K(ret)); + } else if (OB_ISNULL(arr_type = static_cast(src_coll_info->collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("source array collection array type is null", K(ret)); + } + } + if (OB_FAIL(ret) || is_null_res) { + } else if (arr_format == VEC_UNIFORM || arr_format == VEC_UNIFORM_CONST) { + ObString arr_str = arr_vec->get_string(idx); + if (OB_FAIL(ObNestedVectorFunc::construct_param(tmp_allocator, ctx, subschema_id, arr_str, src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } + } else if (OB_FAIL(ObNestedVectorFunc::construct_attr_param( + tmp_allocator, ctx, *expr.args_[0], subschema_id, idx, src_arr))) { + LOG_WARN("construct array obj failed", K(ret)); + } + if (OB_FAIL(ret) || is_null_res) { + } else if (OB_FALSE_IT(arr_idx = idx_vec->get_int(idx) - 1)) { + } else if (arr_idx < 0 || arr_idx > src_arr->size() - 1 || arr_idx > UINT32_MAX) { + is_null_res = true; + } else if (src_arr->get_format() != ArrayFormat::Vector && src_arr->is_null(arr_idx)) { + is_null_res = true; + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res_vec->set_null(idx); + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_BASIC_TYPE) { + ObObj elem_obj; + ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); + if (OB_FAIL(ObArrayCastUtils::cast_get_element(src_arr, elem_type, static_cast(arr_idx), elem_obj))) { + LOG_WARN("failed to cast get element", K(ret)); + } else if (ob_is_int_tc(elem_obj.get_type())) { + res_vec->set_int(idx, elem_obj.get_int()); + } else if (ob_is_uint_tc(elem_obj.get_type())) { + res_vec->set_uint(idx, elem_obj.get_uint64()); + } else if (ObFloatType == elem_obj.get_type()) { + res_vec->set_float(idx, elem_obj.get_float()); + } else if (ObDoubleType == elem_obj.get_type()) { + res_vec->set_double(idx, elem_obj.get_double()); + } else if (ObDecimalIntType == elem_obj.get_type()) { + res_vec->set_decimal_int(idx, elem_obj.get_decimal_int(), elem_obj.get_int_bytes()); + } else if (ObVarcharType == elem_obj.get_type()) { + res_vec->set_string(idx, elem_obj.get_string()); + } else { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "unexpected element type", K(ret), K(elem_obj.get_type())); + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + uint16_t child_subschema_id = expr.obj_meta_.get_subschema_id(); + ObString child_arr_str; + if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator,ctx, child_subschema_id, child_arr, false))) { + LOG_WARN("construct child array obj failed", K(ret)); + } else if (OB_FALSE_IT(child_arr->clear())) { + } else if (OB_FAIL(src_arr->at(static_cast(arr_idx), *child_arr))) { + LOG_WARN("failed to get child array", K(ret), K(arr_idx)); + } else if (res_format == VEC_DISCRETE) { + if (OB_FAIL(ObArrayExprUtils::set_array_res(child_arr, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (res_format == VEC_UNIFORM) { + if (OB_FAIL(ObArrayExprUtils::set_array_res>(child_arr, expr, ctx, static_cast *>(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(child_arr, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_VECTOR_TYPE) { + float *vector_data = reinterpret_cast(src_arr->get_data()); + res_vec->set_float(idx, vector_data[arr_idx]); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid element type", K(ret), K(arr_type->element_type_->type_id_)); + } + if (OB_SUCC(ret)) { + eval_flags.set(idx); + } + } // end for + } + return ret; +} + +int ObExprElementAt::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_element_at; + rt_expr.eval_batch_func_ = eval_element_at_batch; + rt_expr.eval_vector_func_ = eval_element_at_vector; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_element_at.h b/src/sql/engine/expr/ob_expr_element_at.h new file mode 100644 index 0000000000..f2c983354f --- /dev/null +++ b/src/sql/engine/expr/ob_expr_element_at.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for element_at expression. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ELEMENT_AT +#define OCEANBASE_SQL_OB_EXPR_ELEMENT_AT + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprElementAt : public ObFuncExprOperator +{ +public: + explicit ObExprElementAt(common::ObIAllocator &alloc); + virtual ~ObExprElementAt(); + + virtual int calc_result_type2(ObExprResType &type, + ObExprResType &type1, + ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_element_at(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_element_at_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size); + static int eval_element_at_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + DISALLOW_COPY_AND_ASSIGN(ObExprElementAt); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ELEMENT_AT \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_eval_functions.cpp b/src/sql/engine/expr/ob_expr_eval_functions.cpp index f087bed336..06c1ad36dd 100644 --- a/src/sql/engine/expr/ob_expr_eval_functions.cpp +++ b/src/sql/engine/expr/ob_expr_eval_functions.cpp @@ -404,10 +404,21 @@ #include "ob_expr_rb_to_string.h" #include "ob_expr_rb_from_string.h" #include "ob_expr_rb_select.h" +#include "ob_expr_rb_build.h" #include "ob_expr_array_contains.h" +#include "ob_expr_array_to_string.h" +#include "ob_expr_string_to_array.h" +#include "ob_expr_array_append.h" +#include "ob_expr_element_at.h" +#include "ob_expr_array_cardinality.h" #include "ob_expr_audit_log_func.h" #include "ob_expr_can_access_trigger.h" #include "ob_expr_split_part.h" +#include "ob_expr_array_overlaps.h" +#include "ob_expr_array_contains_all.h" +#include "ob_expr_array_distinct.h" +#include "ob_expr_array_remove.h" +#include "ob_expr_array_map.h" #include "ob_expr_get_mysql_routine_parameter_type_str.h" #include "ob_expr_priv_st_geohash.h" #include "ob_expr_priv_st_makepoint.h" @@ -1274,27 +1285,27 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { NULL, // ObExprEnhancedAesEncrypt::eval_aes_encrypt /* 759 */ NULL, // ObExprEnhancedAesDecrypt::eval_aes_decrypt /* 760 */ NULL, // ObExprMysqlProcInfo::eval_mysql_proc_info /* 761 */ - NULL, // ObExprArrayOverlaps::eval_array_overlaps, /* 762 */ - NULL, // ObExprArrayContainsAll::eval_array_contains_all, /* 763 */ + ObExprArrayOverlaps::eval_array_overlaps, /* 762 */ + ObExprArrayContainsAll::eval_array_contains_all, /* 763 */ NULL, // ObExprInnerIsTrue::decimal_int_is_true_start, /* 764 */ NULL, // ObExprInnerIsTrue::decimal_int_is_true_end, /* 765 */ NULL, // ObExprInnerIsTrue::json_is_true_start, /* 766 */ NULL, // ObExprInnerIsTrue::json_is_true_end, /* 767 */ ObExprGetMySQLRoutineParameterTypeStr::get_mysql_routine_parameter_type_str, /* 768 */ - NULL, // ObExprArrayDistinct::eval_array_distinct, /* 769 */ - NULL, // ObExprArrayRemove::eval_array_remove_int64_t, /* 770 */ - NULL, // ObExprArrayRemove::eval_array_remove_float, /* 771 */ - NULL, // ObExprArrayRemove::eval_array_remove_double, /* 772 */ - NULL, // ObExprArrayRemove::eval_array_remove_ObString, /* 773 */ - NULL, // ObExprArrayRemove::eval_array_remove_array, /* 774 */ - NULL, // ObExprArrayMap::eval_array_map, /* 775 */ + ObExprArrayDistinct::eval_array_distinct, /* 769 */ + ObExprArrayRemove::eval_array_remove_int64_t, /* 770 */ + ObExprArrayRemove::eval_array_remove_float, /* 771 */ + ObExprArrayRemove::eval_array_remove_double, /* 772 */ + ObExprArrayRemove::eval_array_remove_ObString, /* 773 */ + ObExprArrayRemove::eval_array_remove_array, /* 774 */ + ObExprArrayMap::eval_array_map, /* 775 */ NULL, // ObExprOraLoginUser::eval_ora_login_user, /* 776 */ - NULL, // ObExprArrayToString::eval_array_to_string, /* 777 */ - NULL, // ObExprStringToArray::eval_string_to_array, /* 778 */ - NULL, // ObExprArrayAppend::eval_array_append, /* 779 */ - NULL, // ObExprElementAt::eval_element_at, /* 780 */ - NULL, // ObExprArrayCardinality::eval_array_cardinality, /* 781 */ - NULL, // ObExprRbBuild::eval_rb_build, /* 782 */ + ObExprArrayToString::eval_array_to_string, /* 777 */ + ObExprStringToArray::eval_string_to_array, /* 778 */ + ObExprArrayAppend::eval_array_append, /* 779 */ + ObExprElementAt::eval_element_at, /* 780 */ + ObExprArrayCardinality::eval_array_cardinality, /* 781 */ + ObExprRbBuild::eval_rb_build, /* 782 */ NULL, // ObExprArrayPrepend::eval_array_prepend, /* 783 */ NULL, // ObExprArrayConcat::eval_array_concat, /* 784 */ NULL, // ObExprArrayDifference::eval_array_difference, /* 785 */ @@ -1450,19 +1461,19 @@ static ObExpr::EvalBatchFunc g_expr_eval_batch_functions[] = { ObExprArrayContains::eval_array_contains_batch_double, /* 141 */ ObExprArrayContains::eval_array_contains_batch_ObString, /* 142 */ ObExprArrayContains::eval_array_contains_array_batch, /* 143 */ - NULL,// ObExprArrayOverlaps::eval_array_overlaps_batch, /* 144 */ - NULL,// ObExprArrayContainsAll::eval_array_contains_all_batch, /* 145 */ - NULL,// ObExprArrayDistinct::eval_array_distinct_batch, /* 146 */ - NULL,// ObExprArrayRemove::eval_array_remove_batch_int64_t, /* 147 */ - NULL,// ObExprArrayRemove::eval_array_remove_batch_float, /* 148 */ - NULL,// ObExprArrayRemove::eval_array_remove_batch_double, /* 149 */ - NULL,// ObExprArrayRemove::eval_array_remove_batch_ObString, /* 150 */ - NULL,// ObExprArrayRemove::eval_array_remove_array_batch, /* 151 */ - NULL,// ObExprArrayToString::eval_array_to_string_batch, /* 152 */ - NULL,// ObExprStringToArray::eval_string_to_array_batch, /* 153 */ - NULL,// ObExprArrayAppend::eval_array_append_batch, /* 154 */ - NULL,// ObExprElementAt::eval_element_at_batch, /* 155 */ - NULL,// ObExprArrayCardinality::eval_array_cardinality_batch, /* 156 */ + ObExprArrayOverlaps::eval_array_overlaps_batch, /* 144 */ + ObExprArrayContainsAll::eval_array_contains_all_batch, /* 145 */ + ObExprArrayDistinct::eval_array_distinct_batch, /* 146 */ + ObExprArrayRemove::eval_array_remove_batch_int64_t, /* 147 */ + ObExprArrayRemove::eval_array_remove_batch_float, /* 148 */ + ObExprArrayRemove::eval_array_remove_batch_double, /* 149 */ + ObExprArrayRemove::eval_array_remove_batch_ObString, /* 150 */ + ObExprArrayRemove::eval_array_remove_array_batch, /* 151 */ + ObExprArrayToString::eval_array_to_string_batch, /* 152 */ + ObExprStringToArray::eval_string_to_array_batch, /* 153 */ + ObExprArrayAppend::eval_array_append_batch, /* 154 */ + ObExprElementAt::eval_element_at_batch, /* 155 */ + ObExprArrayCardinality::eval_array_cardinality_batch, /* 156 */ NULL,// ObExprArrayPrepend::eval_array_prepend_batch, /* 157 */ NULL,// ObExprArrayConcat::eval_array_concat_batch, /* 158 */ NULL,// ObExprArrayDifference::eval_array_difference_batch, /* 159 */ @@ -1594,8 +1605,8 @@ static ObExpr::EvalVectorFunc g_expr_eval_vector_functions[] = { ObExprCalcPartitionBase::fast_calc_partition_level_one_vector,/* 122 */ NULL, // ObExprTrim::eval_trim_vector /* 123 */ NULL, // ObExprEncodeSortkey::eval_encode_sortkey_vector /* 124 */ - NULL, // ObExprArrayOverlaps::eval_array_overlaps_vector, /* 125 */ - NULL, // ObExprArrayContainsAll::eval_array_contains_all_vector, /* 126 */ + ObExprArrayOverlaps::eval_array_overlaps_vector, /* 125 */ + ObExprArrayContainsAll::eval_array_contains_all_vector, /* 126 */ NULL, // ObBitwiseExprOperator::calc_bitwise_result2_mysql_vector, /* 127 */ NULL, // ObBitwiseExprOperator::calc_bitwise_result2_oracle_vector, /* 128 */ NULL, // ObExprDiv::decint_div_mysql_vec_fn, /* 129 */ @@ -1613,12 +1624,12 @@ static ObExpr::EvalVectorFunc g_expr_eval_vector_functions[] = { NULL, // ObExprDiv::decint_div_mysql_vec_fn, /* 141 */ NULL, // ObExprDiv::decint_div_mysql_vec_fn, /* 142 */ NULL, // ObExprDiv::decint_div_mysql_vec_fn, /* 143 */ - NULL, // ObExprArrayRemove::eval_array_remove_vector_int64_t, /* 144 */ - NULL, // ObExprArrayRemove::eval_array_remove_vector_float, /* 145 */ - NULL, // ObExprArrayRemove::eval_array_remove_vector_double, /* 146 */ - NULL, // ObExprArrayRemove::eval_array_remove_vector_ObString, /* 147 */ - NULL, // ObExprArrayRemove::eval_array_remove_array_vector, /* 148 */ - NULL, // ObExprArrayDistinct::eval_array_distinct_vector, /* 149 */ + ObExprArrayRemove::eval_array_remove_vector_int64_t, /* 144 */ + ObExprArrayRemove::eval_array_remove_vector_float, /* 145 */ + ObExprArrayRemove::eval_array_remove_vector_double, /* 146 */ + ObExprArrayRemove::eval_array_remove_vector_ObString, /* 147 */ + ObExprArrayRemove::eval_array_remove_array_vector, /* 148 */ + ObExprArrayDistinct::eval_array_distinct_vector, /* 149 */ NULL, // ObExprDateFormat::calc_date_format_vector, /* 150 */ NULL, // ObExprYear::calc_year_vector, /* 151 */ NULL, // ObExprMonth::calc_month_vector, /* 152 */ @@ -1638,11 +1649,11 @@ static ObExpr::EvalVectorFunc g_expr_eval_vector_functions[] = { NULL, // ObExprFromDays::calc_fromdays_vector, /* 166 */ NULL, // ObExprTimeStampDiff::eval_timestamp_diff_vector, /* 167 */ NULL, // ObExprTimeStampAdd::calc_timestamp_add_vector, /* 168 */ - NULL, // ObExprArrayToString::eval_array_to_string_vector, /* 169 */ - NULL, // ObExprStringToArray::eval_string_to_array_vector, /* 170 */ - NULL, // ObExprArrayAppend::eval_array_append_vector, /* 171 */ - NULL, // ObExprElementAt::eval_element_at_vector, /* 172 */ - NULL, // ObExprArrayCardinality::eval_array_cardinality_vector, /* 173 */ + ObExprArrayToString::eval_array_to_string_vector, /* 169 */ + ObExprStringToArray::eval_string_to_array_vector, /* 170 */ + ObExprArrayAppend::eval_array_append_vector, /* 171 */ + ObExprElementAt::eval_element_at_vector, /* 172 */ + ObExprArrayCardinality::eval_array_cardinality_vector, /* 173 */ NULL, // ObExprArrayPrepend::eval_array_prepend_vector, /* 174 */ NULL, // ObExprArrayConcat::eval_array_concat_vector, /* 175 */ NULL, // ObExprArrayDifference::eval_array_difference_vector, /* 176 */ diff --git a/src/sql/engine/expr/ob_expr_extra_info_factory.cpp b/src/sql/engine/expr/ob_expr_extra_info_factory.cpp index 0651985f3d..7f5e7f235a 100644 --- a/src/sql/engine/expr/ob_expr_extra_info_factory.cpp +++ b/src/sql/engine/expr/ob_expr_extra_info_factory.cpp @@ -38,6 +38,7 @@ #include "sql/engine/expr/ob_expr_json_schema_validation_report.h" #include "sql/engine/expr/ob_expr_json_utils.h" #include "sql/engine/expr/ob_expr_get_path.h" +#include "sql/engine/expr/ob_expr_array_map.h" namespace oceanbase { @@ -116,6 +117,7 @@ void ObExprExtraInfoFactory::register_expr_extra_infos() REG_EXTRA_INFO(T_FUN_SYS_JSON_VALUE, ObExprJsonQueryParamInfo); REG_EXTRA_INFO(T_FUN_SYS_JSON_QUERY, ObExprJsonQueryParamInfo); REG_EXTRA_INFO(T_PSEUDO_EXTERNAL_FILE_COL, ObDataAccessPathExtraInfo); + REG_EXTRA_INFO(T_FUNC_SYS_ARRAY_MAP, ObExprArrayMapInfo); } } // end namespace sql diff --git a/src/sql/engine/expr/ob_expr_operator_factory.cpp b/src/sql/engine/expr/ob_expr_operator_factory.cpp index 3b33f54607..8b8a1cbe8a 100644 --- a/src/sql/engine/expr/ob_expr_operator_factory.cpp +++ b/src/sql/engine/expr/ob_expr_operator_factory.cpp @@ -463,7 +463,13 @@ #include "sql/engine/expr/ob_expr_rb_to_string.h" #include "sql/engine/expr/ob_expr_rb_from_string.h" #include "sql/engine/expr/ob_expr_rb_select.h" +#include "sql/engine/expr/ob_expr_rb_build.h" #include "sql/engine/expr/ob_expr_array_contains.h" +#include "sql/engine/expr/ob_expr_array_to_string.h" +#include "sql/engine/expr/ob_expr_string_to_array.h" +#include "sql/engine/expr/ob_expr_array_append.h" +#include "sql/engine/expr/ob_expr_element_at.h" +#include "sql/engine/expr/ob_expr_array_cardinality.h" #include "sql/engine/expr/ob_expr_tokenize.h" #include "sql/engine/expr/ob_expr_lock_func.h" #include "sql/engine/expr/ob_expr_decode_trace_id.h" @@ -473,6 +479,11 @@ #include "sql/engine/expr/ob_expr_audit_log_func.h" #include "sql/engine/expr/ob_expr_can_access_trigger.h" #include "sql/engine/expr/ob_expr_split_part.h" +#include "sql/engine/expr/ob_expr_array_overlaps.h" +#include "sql/engine/expr/ob_expr_array_contains_all.h" +#include "sql/engine/expr/ob_expr_array_distinct.h" +#include "sql/engine/expr/ob_expr_array_remove.h" +#include "sql/engine/expr/ob_expr_array_map.h" #include "sql/engine/expr/ob_expr_get_mysql_routine_parameter_type_str.h" #include "sql/engine/expr/ob_expr_priv_st_geohash.h" #include "sql/engine/expr/ob_expr_priv_st_makepoint.h" @@ -1157,12 +1168,18 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP(ObExprRbToString); REG_OP(ObExprRbFromString); REG_OP(ObExprRbSelect); + REG_OP(ObExprRbBuild); REG_OP(ObExprGetPath); REG_OP(ObExprGTIDSubset); REG_OP(ObExprGTIDSubtract); REG_OP(ObExprWaitForExecutedGTIDSet); REG_OP(ObExprWaitUntilSQLThreadAfterGTIDs); REG_OP(ObExprArrayContains); + REG_OP(ObExprArrayToString); + REG_OP(ObExprStringToArray); + REG_OP(ObExprArrayAppend); + REG_OP(ObExprElementAt); + REG_OP(ObExprArrayCardinality); REG_OP(ObExprDecodeTraceId); REG_OP(ObExprAuditLogSetFilter); REG_OP(ObExprAuditLogRemoveFilter); @@ -1174,6 +1191,11 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP(ObExprSm4Decrypt); REG_OP(ObExprSplitPart); REG_OP(ObExprTokenize); + REG_OP(ObExprArrayOverlaps); + REG_OP(ObExprArrayContainsAll); + REG_OP(ObExprArrayDistinct); + REG_OP(ObExprArrayRemove); + REG_OP(ObExprArrayMap); REG_OP(ObExprGetMySQLRoutineParameterTypeStr); }(); // 注册oracle系统函数 diff --git a/src/sql/engine/expr/ob_expr_rb_build.cpp b/src/sql/engine/expr/ob_expr_rb_build.cpp new file mode 100644 index 0000000000..e64b7abf36 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_rb_build.cpp @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for rb_build expression. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_rb_build.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" +#include "sql/engine/expr/ob_expr_rb_func_helper.h" +#include "lib/roaringbitmap/ob_rb_utils.h" + + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ +ObExprRbBuild::ObExprRbBuild(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_RB_BUILD, N_RB_BUILD, 1, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprRbBuild::~ObExprRbBuild() +{ +} + +int ObExprRbBuild::calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = NULL; + ObExecContext *exec_ctx = NULL; + ObSubSchemaValue arr_meta; + const ObSqlCollectionInfo *coll_info = NULL; + uint16_t subschema_id; + + if (OB_ISNULL(session = const_cast(type_ctx.get_session()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ObSQLSessionInfo is null", K(ret)); + } else if (OB_ISNULL(exec_ctx = session->get_cur_exec_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ObExecContext is null", K(ret)); + } else if (ob_is_null(type1.get_type())) { + // do nothing + } else if (!ob_is_collection_sql_type(type1.get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "ARRAY", ob_obj_type_str(type1.get_type())); + } else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(type1.get_subschema_id(), arr_meta))) { + LOG_WARN("failed to get elem meta.", K(ret), K(type1.get_subschema_id())); + } else if (arr_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid subschema type", K(ret), K(arr_meta.type_)); + } else { + ObDataType data_type; + uint32_t depth = 0; + bool is_vec = false; + if (OB_FAIL(ObArrayExprUtils::get_array_element_type(exec_ctx, type1.get_subschema_id(), data_type, depth, is_vec))) { + LOG_WARN("failed to get array element type", K(ret)); + } else if (!ob_is_integer_type(data_type.get_obj_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("basic element type of array is not integer", K(ret), K(data_type.get_obj_type())); + } + } + + if (OB_SUCC(ret)) { + type.set_roaringbitmap(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObRoaringBitmapType]).get_length()); + } + + return ret; +} + +int ObExprRbBuild::eval_rb_build(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + ObDatum *arr_datum = NULL; + ObRoaringBitmap *rb = NULL; + ObString rb_bin; + ObIArrayType *arr_obj = NULL; + const uint16_t subschema_id = expr.args_[0]->obj_meta_.get_subschema_id(); + ObSubSchemaValue meta; + const ObSqlCollectionInfo *coll_info = NULL; + ObCollectionArrayType *arr_type = NULL; + bool is_null_res = false; + + if (OB_FAIL(expr.args_[0]->eval(ctx, arr_datum))) { + LOG_WARN("failed to eval source array arg", K(ret)); + } else if (arr_datum->is_null()) { + is_null_res = true; + } else if (OB_FAIL(ObArrayExprUtils::get_array_obj(tmp_allocator, ctx, subschema_id, arr_datum->get_string(), arr_obj))) { + LOG_WARN("construct array obj failed", K(ret)); + } else if (arr_obj->contain_null()) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("array contains null element", K(ret)); + } else if (OB_ISNULL(rb = OB_NEWx(ObRoaringBitmap, &tmp_allocator, (&tmp_allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to create alloc memory to roaringbitmap", K(ret)); + } else if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get subschema value", K(ret), K(subschema_id)); + } else if (OB_ISNULL(coll_info = reinterpret_cast(meta.value_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("coll info is null", K(ret)); + } else if (OB_ISNULL(arr_type = static_cast(coll_info->collection_meta_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("array type is null", K(ret)); + } else { + for (uint32_t i = 0; OB_SUCC(ret) && i < arr_obj->cardinality(); ++i) { + ObObj elem_obj; + bool is_null_elem = false; + if (OB_FAIL(ObArrayExprUtils::get_basic_elem_obj(arr_obj, arr_type->element_type_, i, elem_obj, is_null_elem))) { + LOG_WARN("failed to cast get element", K(ret)); + } else if (is_null_elem) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("array contains null basic element", K(ret)); + } else if (OB_UNLIKELY(!elem_obj.is_integer_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("element is not integer", K(ret), K(elem_obj.get_type())); + } else if (elem_obj.is_signed_integer() && elem_obj.get_int() < 0) { + if (elem_obj.get_int() < INT32_MIN) { + ret = OB_SIZE_OVERFLOW; + LOG_WARN("negative integer not in the range of int32", K(ret), K(elem_obj.get_int())); + } else { + uint32_t uint32_val = static_cast(elem_obj.get_int()); + if (OB_FAIL(rb->value_add(static_cast(uint32_val)))) { + LOG_WARN("failed to add value to roaringbtimap", K(ret), K(uint32_val)); + } + } + } else if (OB_FAIL(rb->value_add(elem_obj.get_uint64()))) { + LOG_WARN("failed to add value to roaringbtimap", K(ret), K(elem_obj.get_uint64())); + } + } + } + + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res.set_null(); + } else if (OB_FAIL(ObRbUtils::rb_serialize(tmp_allocator, rb_bin, rb))) { + LOG_WARN("failed to serialize roaringbitmap", K(ret)); + } else if (OB_FAIL(ObRbExprHelper::pack_rb_res(expr, ctx, res, rb_bin))) { + LOG_WARN("fail to pack roaringbitmap res", K(ret)); + } + ObRbUtils::rb_destroy(rb); + + return ret; +} + +int ObExprRbBuild::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = ObExprRbBuild::eval_rb_build; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_rb_build.h b/src/sql/engine/expr/ob_expr_rb_build.h new file mode 100644 index 0000000000..cd3e4deb3e --- /dev/null +++ b/src/sql/engine/expr/ob_expr_rb_build.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for rb_build expression. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_RB_BUILD +#define OCEANBASE_SQL_OB_EXPR_RB_BUILD + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" +#include "lib/roaringbitmap/ob_roaringbitmap.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprRbBuild : public ObFuncExprOperator +{ +public: + explicit ObExprRbBuild(common::ObIAllocator &alloc); + + virtual ~ObExprRbBuild(); + + virtual int calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_rb_build(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + DISALLOW_COPY_AND_ASSIGN(ObExprRbBuild); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_RB_BUILD \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_result_type_util.cpp b/src/sql/engine/expr/ob_expr_result_type_util.cpp index ce903e859c..0245e402b2 100644 --- a/src/sql/engine/expr/ob_expr_result_type_util.cpp +++ b/src/sql/engine/expr/ob_expr_result_type_util.cpp @@ -890,7 +890,7 @@ int ObExprResultTypeUtil::get_array_calc_type(ObExecContext *exec_ctx, } else { calc_type.set_collection(type2.get_subschema_id()); } - } else if (OB_FAIL(get_array_calc_type(exec_ctx, coll_elem1_type.get_obj_type(), coll_elem2_type.get_obj_type(), + } else if (OB_FAIL(get_array_calc_type(exec_ctx, coll_elem1_type, coll_elem2_type, depth, calc_type, element_type))) { LOG_WARN("failed to get array calc type", K(ret)); } @@ -899,13 +899,16 @@ int ObExprResultTypeUtil::get_array_calc_type(ObExecContext *exec_ctx, } int ObExprResultTypeUtil::get_array_calc_type(ObExecContext *exec_ctx, - const ObObjType &type1, - const ObObjType &type2, + const ObDataType &coll_elem1_type, + const ObDataType &coll_elem2_type, uint32_t depth, ObExprResType &calc_type, ObObjType &element_type) { int ret = OB_SUCCESS; + const ObObjType type1 = coll_elem1_type.get_obj_type(); + const ObObjType type2 = coll_elem2_type.get_obj_type(); + ObDataType elem_data; ObObjType coll_calc_type = ARITH_RESULT_TYPE[type1][type2]; if (ob_is_int_uint(ob_obj_type_class(type1), ob_obj_type_class(type2))) { coll_calc_type = ObIntType; @@ -916,9 +919,27 @@ int ObExprResultTypeUtil::get_array_calc_type(ObExecContext *exec_ctx, } else if (ob_is_null(type2)) { coll_calc_type = type1; } - ObDataType elem_data; + elem_data.meta_.set_type(coll_calc_type); + elem_data.set_accuracy(ObAccuracy::DDL_DEFAULT_ACCURACY[coll_calc_type]); + if (type1 == ObVarcharType || type2 == ObVarcharType + || type1 == ObCharType || type2 == ObCharType) { + coll_calc_type = ObVarcharType; + ObLength len1 = 0; + ObLength len2 = 0; + if (ob_is_string_tc(type1)) { + len1 = coll_elem1_type.get_length(); + } else { + len1 = ObAccuracy::MAX_ACCURACY[type1].get_precision(); + } + if (ob_is_string_tc(type2)) { + len2 = coll_elem2_type.get_length(); + } else { + len2 = ObAccuracy::MAX_ACCURACY[type2].get_precision(); + } + elem_data.meta_.set_type(coll_calc_type); + elem_data.set_length(MAX(len1, len2)); + } uint16_t subschema_id; - elem_data.set_obj_type(coll_calc_type); const int MAX_LEN = 256; char type_name[MAX_LEN] = {0}; ObString type_info; @@ -937,5 +958,40 @@ int ObExprResultTypeUtil::get_array_calc_type(ObExecContext *exec_ctx, return ret; } +int ObExprResultTypeUtil::get_deduce_element_type(ObExprResType &input_type, ObDataType &elem_type) +{ + int ret = OB_SUCCESS; + ObObjType type1 = input_type.get_type(); + ObObjType type2 = elem_type.get_obj_type(); + ObObjType res_type = MERGE_RESULT_TYPE[type1][type2]; + ObObjMeta meta; + if (res_type == ObDecimalIntType || res_type == ObNumberType || res_type == ObUNumberType) { + // decimal type isn't supported in array, use double/bigint instead + if (input_type.get_scale() != 0 || ob_is_float_tc(type2) || ob_is_double_tc(type2)) { + meta.set_double(); + } else { + meta.set_int(); + } + } else { + meta.set_type(res_type); + } + ObAccuracy acc = ObAccuracy::DDL_DEFAULT_ACCURACY[meta.get_type()]; + if (ob_is_collection_sql_type(elem_type.get_obj_type())) { + ret = OB_ERR_ILLEGAL_ARGUMENT_FOR_FUNCTION; + LOG_USER_ERROR(OB_ERR_ILLEGAL_ARGUMENT_FOR_FUNCTION); + } else { + elem_type.set_meta_type(meta); + if (ob_is_string_tc(input_type.get_type())) { + ObLength len = elem_type.get_length(); + elem_type.set_accuracy(acc); + elem_type.set_length(MAX(len, input_type.get_length())); + } else { + elem_type.set_accuracy(acc); + } + } + + return ret; +} + } /* sql */ } /* oceanbase */ diff --git a/src/sql/engine/expr/ob_expr_result_type_util.h b/src/sql/engine/expr/ob_expr_result_type_util.h index e94addbc42..edb0593c6e 100644 --- a/src/sql/engine/expr/ob_expr_result_type_util.h +++ b/src/sql/engine/expr/ob_expr_result_type_util.h @@ -227,11 +227,12 @@ public: const ObExprResType &type2, ObExprResType &calc_type); static int get_array_calc_type(ObExecContext *exec_ctx, - const ObObjType &type1, - const ObObjType &type2, + const ObDataType &coll_elem1_type, + const ObDataType &coll_elem2_type, uint32_t depth, ObExprResType &calc_type, ObObjType &element_type); + static int get_deduce_element_type(ObExprResType &input_type, ObDataType &elem_type); }; diff --git a/src/sql/engine/expr/ob_expr_string_to_array.cpp b/src/sql/engine/expr/ob_expr_string_to_array.cpp new file mode 100644 index 0000000000..0ac7fcd294 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_string_to_array.cpp @@ -0,0 +1,349 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for string_to_array expression. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_string_to_array.h" +#include "lib/udt/ob_collection_type.h" +#include "lib/udt/ob_array_type.h" +#include "sql/engine/expr/ob_array_expr_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; +using namespace oceanbase::omt; + +namespace oceanbase +{ +namespace sql +{ +ObExprStringToArray::ObExprStringToArray(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUNC_SYS_STRING_TO_ARRAY, N_STRING_TO_ARRAY, TWO_OR_THREE, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprStringToArray::~ObExprStringToArray() +{ +} + +int ObExprStringToArray::calc_result_typeN(ObExprResType &type, + ObExprResType *types, + int64_t param_num, + common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + uint16_t subschema_id; + ObDataType res_data_type; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + + for (int i = 0; OB_SUCC(ret) && i < param_num; i++) { + if (!ob_is_string_tc(types[i].get_type()) && !ob_is_null(types[i].get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "VARCHAR", ob_obj_type_str(types[i].get_type())); + } + } + + if (OB_SUCC(ret)) { + res_data_type.set_meta_type(types[0].get_obj_meta()); + res_data_type.set_accuracy(types[0].get_accuracy()); + res_data_type.set_length(types[0].get_length()); + if (OB_FAIL(exec_ctx->get_subschema_id_by_collection_elem_type(ObNestedType::OB_ARRAY_TYPE, res_data_type, subschema_id))) { + LOG_WARN("failed to get collection subschema id", K(ret)); + } else { + type.set_collection(subschema_id); + } + } + return ret; +} + +int ObExprStringToArray::eval_string_to_array(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + uint16_t subschema_id = expr.obj_meta_.get_subschema_id(); + ObDatum *arr_datum = NULL; + ObDatum *delimiter_datum = NULL; + ObDatum *null_str_datum = NULL; + if (OB_FAIL(expr.args_[0]->eval(ctx, arr_datum))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval(ctx, delimiter_datum))) { + LOG_WARN("eval delimiter string failed", K(ret)); + } else if (OB_FAIL(expr.arg_cnt_ > 2 && expr.args_[2]->eval(ctx, null_str_datum))) { + LOG_WARN("eval null string failed", K(ret)); + } else { + std::string arr_str; + std::string delimiter; + std::string null_str; + bool has_arr_str = false; + bool has_delimiter = false; + bool has_null_str = false; + ObIArrayType *arr_obj = NULL; + ObArrayBinary *binary_array = NULL; + if (!arr_datum->is_null()) { + has_arr_str = true; + arr_str.assign(arr_datum->get_string().ptr(), arr_datum->get_string().length()); + } + if (!delimiter_datum->is_null()) { + has_delimiter = true; + delimiter.assign(delimiter_datum->get_string().ptr(), delimiter_datum->get_string().length()); + } + if (expr.arg_cnt_ > 2 && !null_str_datum->is_null()) { + has_null_str = true; + null_str.assign(null_str_datum->get_string().ptr(), null_str_datum->get_string().length()); + } + if (OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator, ctx, subschema_id, arr_obj, false))) { + LOG_WARN("construct array obj failed", K(ret), K(subschema_id)); + } else if (OB_ISNULL(binary_array = static_cast(arr_obj))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("binary array is null", K(ret), K(subschema_id)); + } else if (OB_FAIL(string_to_array(binary_array, arr_str, delimiter, null_str, has_arr_str, has_delimiter, has_null_str))) { + LOG_WARN("failed to convert string to array", K(ret)); + } else if (!has_arr_str) { + res.set_null(); + } else { + ObString res_str; + if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_obj, arr_obj->get_raw_binary_len(), expr, ctx, res_str))) { + LOG_WARN("get array binary string failed", K(ret)); + } else { + res.set_string(res_str); + } + } + } + return ret; +} + +int ObExprStringToArray::eval_string_to_array_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size) +{ + int ret = OB_SUCCESS; + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.obj_meta_.get_subschema_id(); + ObIArrayType *arr_obj = NULL; + + if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval delimiter string failed", K(ret)); + } else if (OB_FAIL(expr.arg_cnt_ > 2 && expr.args_[2]->eval_batch(ctx, skip, batch_size))) { + LOG_WARN("eval null string failed", K(ret)); + } else { + ObDatumVector arr_str_array = expr.args_[0]->locate_expr_datumvector(ctx); + ObDatumVector delimiter_array = expr.args_[1]->locate_expr_datumvector(ctx); + ObDatumVector null_str_array = expr.arg_cnt_ > 2 ? expr.args_[2]->locate_expr_datumvector(ctx) : ObDatumVector(); + for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) { + std::string arr_str; + std::string delimiter; + std::string null_str; + bool has_arr_str = false; + bool has_delimiter = false; + bool has_null_str = false; + ObArrayBinary *binary_array = NULL; + + if (skip.at(j) || eval_flags.at(j)) { + continue; + } + eval_flags.set(j); + if (!arr_str_array.at(j)->is_null()) { + has_arr_str = true; + arr_str.assign(arr_str_array.at(j)->get_string().ptr(), arr_str_array.at(j)->get_string().length()); + } + if (!delimiter_array.at(j)->is_null()) { + has_delimiter = true; + delimiter.assign(delimiter_array.at(j)->get_string().ptr(), delimiter_array.at(j)->get_string().length()); + } + if (expr.arg_cnt_ > 2 && !null_str_array.at(j)->is_null()) { + has_null_str = true; + null_str.assign(null_str_array.at(j)->get_string().ptr(), null_str_array.at(j)->get_string().length()); + } + if (OB_ISNULL(arr_obj) && OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator, ctx, subschema_id, arr_obj, false))) { + LOG_WARN("construct array obj failed", K(ret), K(subschema_id)); + } else if (OB_FALSE_IT(arr_obj->clear())) { + } else if (OB_ISNULL(binary_array = static_cast(arr_obj))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("binary array is null", K(ret), K(subschema_id)); + } else if (OB_FAIL(string_to_array(binary_array, arr_str, delimiter, null_str, has_arr_str, has_delimiter, has_null_str))) { + LOG_WARN("failed to convert string to array", K(ret)); + } else if (!has_arr_str) { + res_datum.at(j)->set_null(); + } else { + int32_t res_size = binary_array->get_raw_binary_len(); + char *res_buf = nullptr; + int64_t res_buf_len = 0; + ObTextStringDatumResult output_result(expr.datum_meta_.type_, &expr, &ctx, res_datum.at(j)); + if (OB_FAIL(output_result.init_with_batch_idx(res_size, j))) { + LOG_WARN("fail to init result", K(ret), K(res_size)); + } else if (OB_FAIL(output_result.get_reserved_buffer(res_buf, res_buf_len))) { + LOG_WARN("fail to get reserver buffer", K(ret)); + } else if (res_buf_len < res_size) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(binary_array->get_raw_binary(res_buf, res_buf_len))) { + LOG_WARN("get array raw binary failed", K(ret), K(res_buf_len), K(res_size)); + } else if (OB_FAIL(output_result.lseek(res_size, 0))) { + LOG_WARN("failed to lseek res.", K(ret), K(output_result), K(res_size)); + } else { + output_result.set_result(); + } + } + } // end for + } + return ret; +} + +int ObExprStringToArray::eval_string_to_array_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + const uint16_t subschema_id = expr.obj_meta_.get_subschema_id(); + ObIArrayType *arr_obj = NULL; + + if (OB_FAIL(expr.args_[0]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval source array failed", K(ret)); + } else if (OB_FAIL(expr.args_[1]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval delimiter string failed", K(ret)); + } else if (OB_FAIL(expr.arg_cnt_ > 2 && expr.args_[2]->eval_vector(ctx, skip, bound))) { + LOG_WARN("eval null string failed", K(ret)); + } else { + ObIVector *arr_str_vec = expr.args_[0]->get_vector(ctx); + ObIVector *delimiter_vec = expr.args_[1]->get_vector(ctx); + ObIVector *null_str_vec = expr.arg_cnt_ > 2 ? expr.args_[2]->get_vector(ctx) : NULL; + ObIVector *res_vec = expr.get_vector(ctx); + ObDatumVector res_datum = expr.locate_expr_datumvector(ctx); + VectorFormat res_format = expr.get_format(ctx); + ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); + + for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) { + bool has_arr_str = false; + bool has_delimiter = false; + bool has_null_str = false; + std::string arr_str; + std::string delimiter; + std::string null_str; + ObArrayBinary *binary_array = NULL; + + if (skip.at(idx) || eval_flags.at(idx)) { + continue; + } + eval_flags.set(idx); + if (!arr_str_vec->is_null(idx)) { + has_arr_str = true; + arr_str.assign(arr_str_vec->get_string(idx).ptr(), arr_str_vec->get_string(idx).length()); + } + if (!delimiter_vec->is_null(idx)) { + has_delimiter = true; + delimiter.assign(delimiter_vec->get_string(idx).ptr(), delimiter_vec->get_string(idx).length()); + } + if (expr.arg_cnt_ > 2 && !null_str_vec->is_null(idx)) { + has_null_str = true; + null_str.assign(null_str_vec->get_string(idx).ptr(), null_str_vec->get_string(idx).length()); + } + if (OB_ISNULL(arr_obj) && OB_FAIL(ObArrayExprUtils::construct_array_obj(tmp_allocator, ctx, subschema_id, arr_obj, false))) { + LOG_WARN("construct array obj failed", K(ret), K(subschema_id)); + } else if (OB_FALSE_IT(arr_obj->clear())) { + } else if (OB_ISNULL(binary_array = static_cast(arr_obj))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("binary array is null", K(ret), K(subschema_id)); + } else if (OB_FAIL(string_to_array(binary_array, arr_str, delimiter, null_str, has_arr_str, has_delimiter, has_null_str))) { + LOG_WARN("failed to convert string to array", K(ret)); + } else if (!has_arr_str) { + res_vec->set_null(idx); + } else { + if (res_format == VEC_DISCRETE) { + if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_obj, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (res_format == VEC_UNIFORM) { + if (OB_FAIL(ObArrayExprUtils::set_array_res>(arr_obj, expr, ctx, static_cast *>(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } else if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_obj, expr, ctx, static_cast(res_vec), idx))) { + LOG_WARN("set array res failed", K(ret)); + } + } + } // end for + } + return ret; +} + +int ObExprStringToArray::string_to_array(ObArrayBinary *binary_array, + std::string arr_str, std::string delimiter, std::string null_str, + bool has_arr_str, bool has_delimiter, bool has_null_str) +{ + int ret = OB_SUCCESS; + if (!has_arr_str) { + // do nothing + } else if (!has_delimiter) { + // add value to array character by character + for (int i = 0; OB_SUCC(ret) && i < arr_str.length(); ++i) { + if (OB_FAIL(add_value_str_to_array(binary_array, std::string(1, arr_str[i]), has_null_str, null_str))) { + LOG_WARN("failed to add character to array", K(ret), K(arr_str[i])); + } + } + } else { + size_t value_start = 0; + size_t value_end = 0; + bool parse_finished = false; + while (OB_SUCC(ret) && !parse_finished) { + value_end = delimiter.empty() ? arr_str.length() : arr_str.find(delimiter, value_start); + if (value_end >= arr_str.length()) { + parse_finished = true; + value_end = arr_str.length(); + } + std::string value_str = arr_str.substr(value_start, value_end - value_start); + if (OB_FAIL(add_value_str_to_array(binary_array, value_str, has_null_str, null_str))) { + LOG_WARN("failed to add value string to array", K(ret), K(ObString(value_str.length(), value_str.data()))); + } else { + value_start = value_end + delimiter.length(); + } + } // end while + } + return ret; +} + +int ObExprStringToArray::add_value_str_to_array(ObArrayBinary *binary_array, std::string value_str, bool has_null_str, std::string null_str) +{ + int ret = OB_SUCCESS; + if (has_null_str && value_str.compare(null_str) == 0) { + // value is null + if (OB_FAIL(binary_array->push_back(ObString(), true))) { + LOG_WARN("failed to push back null value", K(ret)); + } + } else { + if (OB_FAIL(binary_array->push_back(ObString(value_str.length(), value_str.data())))) { + LOG_WARN("failed to push back value string", K(ret)); + } + } + return ret; +} + +int ObExprStringToArray::cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_string_to_array; + rt_expr.eval_batch_func_ = eval_string_to_array_batch; + rt_expr.eval_vector_func_ = eval_string_to_array_vector; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_string_to_array.h b/src/sql/engine/expr/ob_expr_string_to_array.h new file mode 100644 index 0000000000..48ca3d7db2 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_string_to_array.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2021 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. + * This file contains implementation for string_to_array expression. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_STRING_TO_ARRAY +#define OCEANBASE_SQL_OB_EXPR_STRING_TO_ARRAY + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/udt/ob_array_type.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprStringToArray : public ObFuncExprOperator +{ +public: + explicit ObExprStringToArray(common::ObIAllocator &alloc); + virtual ~ObExprStringToArray(); + + virtual int calc_result_typeN(ObExprResType &type, + ObExprResType *types, + int64_t param_num, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_string_to_array(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_string_to_array_batch(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const int64_t batch_size); + static int eval_string_to_array_vector(const ObExpr &expr, ObEvalCtx &ctx, + const ObBitVector &skip, const EvalBound &bound); + static int add_value_str_to_array(ObArrayBinary *binary_array, std::string value_str, bool has_null_str, std::string null_str); + static int string_to_array(ObArrayBinary *binary_array, + std::string arr_str, std::string delimiter, std::string null_str, + bool has_arr_str, bool has_delimiter, bool has_null_str); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + DISALLOW_COPY_AND_ASSIGN(ObExprStringToArray); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_STRING_TO_ARRAY \ No newline at end of file diff --git a/src/sql/engine/ob_subschema_ctx.cpp b/src/sql/engine/ob_subschema_ctx.cpp index dbcd5d2230..89a9b2322c 100644 --- a/src/sql/engine/ob_subschema_ctx.cpp +++ b/src/sql/engine/ob_subschema_ctx.cpp @@ -13,9 +13,8 @@ #define USING_LOG_PREFIX SQL_ENG #include "sql/engine/ob_subschema_ctx.h" #include "deps/oblib/src/lib/udt/ob_udt_type.h" -#include "deps/oblib/src/lib/udt/ob_array_type.h" +#include "deps/oblib/src/lib/udt/ob_array_utils.h" #include "lib/enumset/ob_enum_set_meta.h" -#include "src/share/rc/ob_tenant_base.h" namespace oceanbase { diff --git a/src/sql/engine/window_function/ob_window_function_op.cpp b/src/sql/engine/window_function/ob_window_function_op.cpp index 86b058548b..4a98d8f342 100644 --- a/src/sql/engine/window_function/ob_window_function_op.cpp +++ b/src/sql/engine/window_function/ob_window_function_op.cpp @@ -1312,7 +1312,8 @@ int ObWindowFunctionOp::init() case T_FUN_SYS_ST_ASMVT: case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: - case T_FUN_SYS_RB_AND_AGG: { + case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { void *tmp_ptr = local_allocator_.alloc(sizeof(AggrCell)); void *tmp_array = local_allocator_.alloc(sizeof(AggrInfoFixedArray)); ObIArray *aggr_infos = NULL; diff --git a/src/sql/engine/window_function/ob_window_function_vec_op.cpp b/src/sql/engine/window_function/ob_window_function_vec_op.cpp index 5f09ed243a..be57c26b53 100644 --- a/src/sql/engine/window_function/ob_window_function_vec_op.cpp +++ b/src/sql/engine/window_function/ob_window_function_vec_op.cpp @@ -778,7 +778,8 @@ int ObWindowFunctionVecOp::init() case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_ARRAYAGG: case T_FUN_ORA_JSON_OBJECTAGG: - case T_FUN_ORA_XMLAGG: { + case T_FUN_ORA_XMLAGG: + case T_FUNC_SYS_ARRAY_AGG: { aggregate::IAggregate *agg_func = nullptr; winfunc::AggrExpr *aggr_expr = nullptr; if (OB_FAIL(alloc_expr(*local_allocator_, aggr_expr))) { diff --git a/src/sql/ob_sql.cpp b/src/sql/ob_sql.cpp index b3428eff80..32009beb6c 100644 --- a/src/sql/ob_sql.cpp +++ b/src/sql/ob_sql.cpp @@ -836,7 +836,7 @@ int ObSql::fill_select_result_set(ObResultSet &result_set, ObSqlCtx *context, co && !ObObjUDTUtil::ob_is_supported_sql_udt(udt_id)) { // array type field.type_.set_subschema_id(subschema_id); - field.charsetnr_ = CS_TYPE_BINARY; + field.charsetnr_ = CS_TYPE_UTF8MB4_BIN; field.length_ = OB_MAX_LONGTEXT_LENGTH; } else if (OB_FAIL(result_set.get_exec_context().get_subschema_id_by_udt_id(udt_id, tmp_subschema_id))) { LOG_WARN("unsupported udt id", K(ret), K(subschema_id)); diff --git a/src/sql/ob_sql_define.h b/src/sql/ob_sql_define.h index 3cce3c6e3d..0e9282e64c 100644 --- a/src/sql/ob_sql_define.h +++ b/src/sql/ob_sql_define.h @@ -125,6 +125,7 @@ enum JtColType { COL_TYPE_XMLTYPE_XML, // 8 COL_TYPE_ORDINALITY_XML = 9, COL_TYPE_RB_ITERATE = 10, + COL_TYPE_UNNEST = 11, }; enum ObNameTypeClass diff --git a/src/sql/parser/non_reserved_keywords_mysql_mode.c b/src/sql/parser/non_reserved_keywords_mysql_mode.c index b0717c14c1..a51e65c537 100644 --- a/src/sql/parser/non_reserved_keywords_mysql_mode.c +++ b/src/sql/parser/non_reserved_keywords_mysql_mode.c @@ -56,6 +56,7 @@ static const NonReservedKeyword Mysql_none_reserved_keywords[] = {"arbitration", ARBITRATION}, {"archivelog", ARCHIVELOG}, {"array", ARRAY}, + {"array_map", ARRAY_MAP}, {"as", AS}, {"asc", ASC}, {"asensitive", ASENSITIVE}, @@ -75,6 +76,7 @@ static const NonReservedKeyword Mysql_none_reserved_keywords[] = {"avg", AVG}, {"avg_row_length", AVG_ROW_LENGTH}, {"array", ARRAY}, + {"array_agg", ARRAY_AGG}, {"backup", BACKUP}, {"backupset", BACKUPSET}, {"balance", BALANCE}, @@ -1096,6 +1098,7 @@ static const NonReservedKeyword Mysql_none_reserved_keywords[] = {"rb_iterate", RB_ITERATE}, {"optimizer_costs", OPTIMIZER_COSTS}, {"micro_index_clustered", MICRO_INDEX_CLUSTERED}, + {"unnest", UNNEST}, {"tenant_sts_credential", TENANT_STS_CREDENTIAL} }; diff --git a/src/sql/parser/sql_parser_mysql_mode.y b/src/sql/parser/sql_parser_mysql_mode.y index e8dd7f7c42..0b9aa2f643 100644 --- a/src/sql/parser/sql_parser_mysql_mode.y +++ b/src/sql/parser/sql_parser_mysql_mode.y @@ -169,7 +169,7 @@ TRACE_LOG LOAD_BATCH_SIZE TRANS_PARAM OPT_PARAM OB_DDL_SCHEMA_VERSION FORCE_REFR DISABLE_PARALLEL_DML ENABLE_PARALLEL_DML MONITOR NO_PARALLEL CURSOR_SHARING_EXACT MAX_CONCURRENT DOP TRACING NO_QUERY_TRANSFORMATION NO_COST_BASED_QUERY_TRANSFORMATION BLOCKING RESOURCE_GROUP // transform hint -NO_REWRITE MERGE_HINT NO_MERGE_HINT NO_EXPAND USE_CONCAT UNNEST NO_UNNEST +NO_REWRITE MERGE_HINT NO_MERGE_HINT NO_EXPAND USE_CONCAT NO_UNNEST PLACE_GROUP_BY NO_PLACE_GROUP_BY INLINE MATERIALIZE SEMI_TO_INNER NO_SEMI_TO_INNER PRED_DEDUCE NO_PRED_DEDUCE PUSH_PRED_CTE NO_PUSH_PRED_CTE REPLACE_CONST NO_REPLACE_CONST SIMPLIFY_ORDER_BY NO_SIMPLIFY_ORDER_BY @@ -270,7 +270,7 @@ END_P SET_VAR DELIMITER ACCESS ACCESS_INFO ACCESSID ACCESSKEY ACCESSTYPE ACCOUNT ACTION ACTIVE ADDDATE AFTER AGAINST AGGREGATE ALGORITHM ALL_META ALL_USER ALWAYS ALLOW ANALYSE ANY APPROX_COUNT_DISTINCT APPROX_COUNT_DISTINCT_SYNOPSIS APPROX_COUNT_DISTINCT_SYNOPSIS_MERGE ARBITRATION ARRAY ASCII ASIS AT ATTRIBUTE AUTHORS AUTO AUTOEXTEND_SIZE AUTO_INCREMENT AUTO_INCREMENT_MODE AUTO_INCREMENT_CACHE_SIZE - AVG AVG_ROW_LENGTH ACTIVATE AVAILABILITY ARCHIVELOG ASYNCHRONOUS AUDIT ADMIN AUTO_REFRESH APPROX APPROXIMATE + AVG AVG_ROW_LENGTH ACTIVATE AVAILABILITY ARCHIVELOG ASYNCHRONOUS AUDIT ADMIN AUTO_REFRESH APPROX APPROXIMATE ARRAY_AGG ARRAY_MAP BACKUP BACKUP_COPIES BALANCE BANDWIDTH BASE BASELINE BASELINE_ID BASIC BEGI BINDING SHARDING BINLOG BIT BIT_AND BIT_OR BIT_XOR BLOCK BLOCK_INDEX BLOCK_SIZE BLOOM_FILTER BOOL BOOLEAN BOOTSTRAP BTREE BYTE @@ -368,7 +368,7 @@ END_P SET_VAR DELIMITER TABLEGROUP_ID TENANT_ID THROTTLE TIME_ZONE_INFO TOP_K_FRE_HIST TIMES TRIM_SPACE TTL TRANSFER TENANT_STS_CREDENTIAL - UNCOMMITTED UNCONDITIONAL UNDEFINED UNDO_BUFFER_SIZE UNDOFILE UNICODE UNINSTALL UNIT UNIT_GROUP UNIT_NUM UNLOCKED UNTIL + UNCOMMITTED UNCONDITIONAL UNDEFINED UNDO_BUFFER_SIZE UNDOFILE UNNEST UNICODE UNINSTALL UNIT UNIT_GROUP UNIT_NUM UNLOCKED UNTIL UNUSUAL UPGRADE USE_BLOOM_FILTER UNKNOWN USE_FRM USER USER_RESOURCES UNBOUNDED UP UNLIMITED USER_SPECIFIED VALID VALUE VARIANCE VARIABLES VERBOSE VERIFY VIEW VISIBLE VIRTUAL_COLUMN_ID VALIDATE VAR_POP @@ -407,7 +407,7 @@ END_P SET_VAR DELIMITER %type date_unit date_params timestamp_params %type drop_table_stmt table_list drop_view_stmt table_or_tables %type explain_stmt explainable_stmt format_name kill_stmt help_stmt create_outline_stmt alter_outline_stmt drop_outline_stmt opt_outline_target -%type expr_list expr expr_const conf_const simple_expr expr_or_default bit_expr bool_pri predicate explain_or_desc pl_expr_stmt +%type expr_list expr expr_const conf_const simple_expr simple_expr_list expr_or_default bit_expr bool_pri predicate explain_or_desc pl_expr_stmt %type column_ref multi_delete_table %type case_expr func_expr in_expr sub_query_flag search_expr %type case_arg when_clause_list when_clause case_default @@ -472,7 +472,7 @@ END_P SET_VAR DELIMITER %type alter_column_behavior opt_set opt_position_column %type alter_system_stmt alter_system_set_parameter_actions alter_system_settp_actions settp_option alter_system_set_parameter_action server_info_list server_info opt_shared_storage_info shared_storage_info alter_system_reset_parameter_actions alter_system_reset_parameter_action %type opt_comment opt_as -%type column_name relation_name opt_relation_name function_name column_label var_name relation_name_or_string row_format_option compression_name +%type column_name relation_name relation_name_list opt_relation_name function_name column_label var_name relation_name_or_string row_format_option compression_name %type audit_stmt audit_clause op_audit_tail_clause audit_operation_clause audit_all_shortcut_list audit_all_shortcut auditing_on_clause auditing_by_user_clause audit_user_list audit_user audit_user_with_host_name %type opt_hint_list hint_option select_with_opt_hint update_with_opt_hint delete_with_opt_hint hint_list_with_end global_hint transform_hint optimize_hint %type create_index_stmt index_name sort_column_list sort_column_key opt_index_option_list index_option opt_sort_column_key_length opt_index_using_algorithm index_using_algorithm visibility_option opt_constraint_name constraint_name create_with_opt_hint index_expr alter_with_opt_hint @@ -551,7 +551,7 @@ END_P SET_VAR DELIMITER %type skip_index_type opt_skip_index_type_list %type opt_rebuild_column_store %type vec_index_params vec_index_param vec_index_param_value -%type json_table_expr rb_iterate_expr mock_jt_on_error_on_empty jt_column_list json_table_column_def +%type json_table_expr rb_iterate_expr unnest_expr mock_jt_on_error_on_empty jt_column_list json_table_column_def %type json_table_ordinality_column_def json_table_exists_column_def json_table_value_column_def json_table_nested_column_def %type opt_value_on_empty_or_error_or_mismatch opt_on_mismatch %type table_values_clause table_values_clause_with_order_by_and_limit values_row_list row_value @@ -566,7 +566,7 @@ END_P SET_VAR DELIMITER %type ttl_definition ttl_expr ttl_unit %type id_dot_id id_dot_id_dot_id %type vector_distance_expr vector_distance_metric -%type any_expr +%type any_expr opt_nulls_first_or_last lambda_expr lambda_expr_params %type opt_empty_table_list opt_repair_mode opt_repair_option_list repair_option repair_option_list opt_checksum_option %type cache_index_stmt load_index_into_cache_stmt tbl_index_list tbl_index tbl_partition_list opt_tbl_partition_list tbl_index_or_partition_list tbl_index_or_partition opt_ignore_leaves key_cache_name %type select_clause_set select_clause_set_body @@ -1865,6 +1865,17 @@ simple_expr collation %prec NEG } ; +simple_expr_list: +simple_expr +{ + malloc_list_node($$, result->malloc_pool_, T_EXPR_LIST, 2, 1, $1); +} +| simple_expr_list ',' simple_expr +{ + push_back_list(result->malloc_pool_, result, $$, $1, $3); +} +; + search_expr: expr_const { @@ -2531,6 +2542,15 @@ GEOMETRYCOLLECTION { $$ = NULL; } | GEOMCOLLECTION { $$ = NULL; } ; +opt_nulls_first_or_last: +NULLS first_or_last +{ + $$ = $2; +} +| /*empty*/ +{ $$ = NULL;} +; + func_expr: MOD '(' expr ',' expr ')' { @@ -3374,6 +3394,36 @@ MOD '(' expr ',' expr ')' { malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 2, $3, NULL); } +| ARRAY_AGG '(' opt_distinct expr ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_FUNC_SYS_ARRAY_AGG, 2, $3, $4); +} +| ARRAY_AGG '(' opt_distinct expr order_by opt_nulls_first_or_last ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_FUNC_SYS_ARRAY_AGG, 4, $3, $4, $5, $6); +} +| ARRAY_MAP '(' lambda_expr ',' expr_list ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_FUNC_SYS_ARRAY_MAP, 2, $3, $5); +} +; + +lambda_expr_params: +NAME_OB { $$ = $1;} +| unreserved_keyword { get_non_reserved_node($$, result->malloc_pool_, @1.first_column, @1.last_column); } +| '(' name_list ')' +{ + $$ = $2; +} +; + +lambda_expr: +lambda_expr_params JSON_EXTRACT '(' expr ')' +{ + ParseNode *params = NULL; + merge_nodes(params, result, T_EXPR_LIST, $1); + malloc_non_terminal_node($$, result->malloc_pool_, T_FUNC_SYS_LAMBDA, 2, params, $4); +} ; vector_distance_expr: @@ -12826,6 +12876,10 @@ tbl_name { $$ = $1; } +| unnest_expr +{ + $$ = $1; +} ; tbl_name: @@ -22675,6 +22729,17 @@ NAME_OB { $$ = $1; } } ; +relation_name_list: +relation_name +{ + malloc_list_node($$, result->malloc_pool_, T_EXPR_LIST, 2, 1, $1); +} +| relation_name_list ',' relation_name +{ + push_back_list(result->malloc_pool_, result, $$, $1, $3); +} +; + opt_relation_name: /* empty */ { @@ -23803,17 +23868,48 @@ JSON '(' column_name ')' STORE AS '(' lob_storage_parameters ')' ; rb_iterate_expr: -RB_ITERATE '(' simple_expr ')' relation_name +RB_ITERATE '(' simple_expr ')' { - malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 2, $3, $5); + malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 3, $3, NULL, NULL); +} +| RB_ITERATE '(' simple_expr ')' relation_name +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 3, $3, $5, NULL); } | RB_ITERATE '(' simple_expr ')' AS relation_name { - malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 2, $3, $6); + malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 3, $3, $6, NULL); } -| RB_ITERATE '(' simple_expr ')' +| RB_ITERATE '(' simple_expr ')' relation_name '(' relation_name ')' { - malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 2, $3, NULL); + malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 3, $3, $5, $7); +} +| RB_ITERATE '(' simple_expr ')' AS relation_name '(' relation_name ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_RB_ITERATE_EXPRESSION, 3, $3, $6, $8); +} +; + +unnest_expr: +UNNEST '(' simple_expr_list ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_UNNEST_EXPRESSION, 3, $3, NULL, NULL); +} +| UNNEST '(' simple_expr_list ')' relation_name +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_UNNEST_EXPRESSION, 3, $3, $5, NULL); +} +| UNNEST '(' simple_expr_list ')' AS relation_name +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_UNNEST_EXPRESSION, 3, $3, $6, NULL); +} +| UNNEST '(' simple_expr_list ')' relation_name '(' relation_name_list ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_UNNEST_EXPRESSION, 3, $3, $5, $7); +} +| UNNEST '(' simple_expr_list ')' AS relation_name '(' relation_name_list ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_UNNEST_EXPRESSION, 3, $3, $6, $8); } ; @@ -23871,6 +23967,8 @@ ACCESS_INFO | AUTO_REFRESH | AVG | AVG_ROW_LENGTH +| ARRAY_AGG +| ARRAY_MAP | BACKUP | BACKUPSET | BACKUP_COPIES @@ -24561,6 +24659,7 @@ ACCESS_INFO | UNDEFINED | UNDO_BUFFER_SIZE | UNDOFILE +| UNNEST | UNICODE | UNKNOWN | UNINSTALL diff --git a/src/sql/printer/ob_dml_stmt_printer.cpp b/src/sql/printer/ob_dml_stmt_printer.cpp index c3e4682af6..5bbf8165b1 100644 --- a/src/sql/printer/ob_dml_stmt_printer.cpp +++ b/src/sql/printer/ob_dml_stmt_printer.cpp @@ -473,6 +473,32 @@ int ObDMLStmtPrinter::print_table(const TableItem *table_item, } DATA_PRINTF(")"); DATA_PRINTF(" %.*s", LEN_AND_PTR(table_item->alias_name_)); + DATA_PRINTF("("); + DATA_PRINTF("%.*s", LEN_AND_PTR(table_item->json_table_def_->all_cols_.at(1)->col_name_)); + DATA_PRINTF(")"); + } + break; + } + case MulModeTableType::OB_UNNEST_TABLE_TYPE : { + DATA_PRINTF("UNNEST("); + for (int64_t i = 0; OB_SUCC(ret) && i < table_item->json_table_def_->doc_exprs_.count(); ++i) { + if (OB_FAIL(expr_printer_.do_print(table_item->json_table_def_->doc_exprs_.at(i), T_FROM_SCOPE))) { + LOG_WARN("failed to print expr", K(ret)); + } else if (i != table_item->json_table_def_->doc_exprs_.count() - 1) { + DATA_PRINTF(","); + } else { + DATA_PRINTF(")"); + } + } + DATA_PRINTF(" %.*s", LEN_AND_PTR(table_item->alias_name_)); + DATA_PRINTF("("); + for (int64_t i = 1; OB_SUCC(ret) && i < table_item->json_table_def_->all_cols_.count(); ++i) { + DATA_PRINTF("%.*s", LEN_AND_PTR(table_item->json_table_def_->all_cols_.at(i)->col_name_)); + if (i != table_item->json_table_def_->all_cols_.count() - 1) { + DATA_PRINTF(","); + } else { + DATA_PRINTF(")"); + } } break; } diff --git a/src/sql/printer/ob_raw_expr_printer.cpp b/src/sql/printer/ob_raw_expr_printer.cpp index 879d7fe32e..840336a808 100644 --- a/src/sql/printer/ob_raw_expr_printer.cpp +++ b/src/sql/printer/ob_raw_expr_printer.cpp @@ -201,6 +201,15 @@ int ObRawExprPrinter::print(ObRawExpr *expr) PRINT_EXPR(match_against_expr); break; } + case ObRawExpr::EXPR_VAR: { + ObVarRawExpr *var_expr = static_cast(expr); + if (var_expr->get_ref_expr() != NULL) { + int8_t idx = var_expr->get_ref_index(); + char token = static_cast('a' + idx); + DATA_PRINTF("%c", token); + } + break; + } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unknown expr class", K(ret), K(expr->get_expr_class())); @@ -1224,6 +1233,12 @@ int ObRawExprPrinter::print(ObAggFunRawExpr *expr) } break; } + case T_FUNC_SYS_ARRAY_AGG: { + if (OB_FAIL(print_array_agg_expr(expr))) { + LOG_WARN("fail to print array_agg.", K(ret)); + } + break; + } case T_FUN_GROUP_RANK: SET_SYMBOL_IF_EMPTY("rank"); case T_FUN_GROUP_DENSE_RANK: @@ -3469,6 +3484,10 @@ int ObRawExprPrinter::print(ObSysFunRawExpr *expr) OZ(print_sql_udt_attr_access(expr)); break; } + case T_FUNC_SYS_ARRAY_MAP: { + OZ(print_array_map(expr)); + break; + } default: { DATA_PRINTF("%.*s", LEN_AND_PTR(func_name)); OZ(inner_print_fun_params(*expr)); @@ -5071,6 +5090,53 @@ int ObRawExprPrinter::print_xml_agg_expr(ObAggFunRawExpr *expr) return ret; } +int ObRawExprPrinter::print_array_agg_expr(ObAggFunRawExpr *expr) +{ + INIT_SUCC(ret); + if (OB_UNLIKELY(1 != expr->get_real_param_count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param count of expr", K(ret), KPC(expr)); + } else { + DATA_PRINTF("array_agg("); + if (expr->is_param_distinct()) { + DATA_PRINTF(" distinct "); + } + PRINT_EXPR(expr->get_param_expr(0)); + if (OB_NOT_NULL(expr->get_param_expr(1))) { + const ObIArray &order_items = expr->get_order_items(); + int64_t order_item_size = order_items.count(); + if (order_item_size > 0) { + DATA_PRINTF(" order by "); + for (int64_t i = 0; OB_SUCC(ret) && i < order_item_size; ++i) { + const OrderItem &order_item = order_items.at(i); + PRINT_EXPR(order_item.expr_); + if (OB_SUCC(ret)) { + if (lib::is_mysql_mode()) { + if (is_descending_direction(order_item.order_type_)) { + DATA_PRINTF(" desc "); + } + } else if (order_item.order_type_ == NULLS_FIRST_ASC) { + DATA_PRINTF(" asc nulls first "); + } else if (order_item.order_type_ == NULLS_LAST_ASC) {//use default value + /*do nothing*/ + } else if (order_item.order_type_ == NULLS_FIRST_DESC) {//use default value + DATA_PRINTF(" desc "); + } else if (order_item.order_type_ == NULLS_LAST_DESC) { + DATA_PRINTF(" desc nulls last "); + } else {/*do nothing*/} + } + DATA_PRINTF(","); + } + if (OB_SUCC(ret)) { + --*pos_; + } + } + } + DATA_PRINTF(")"); + } + return ret; +} + int ObRawExprPrinter::print_xml_attributes_expr(ObSysFunRawExpr *expr) { int ret = OB_SUCCESS; @@ -5228,6 +5294,61 @@ int ObRawExprPrinter::print_sql_udt_construct(ObSysFunRawExpr *expr) return ret; } +int ObRawExprPrinter::get_max_lambda_param_idx(ObRawExpr *expr, uint32_t &max_idx) +{ + int ret = OB_SUCCESS; + if (expr->get_expr_type() == T_EXEC_VAR) { + ObVarRawExpr *var_expr = static_cast(expr); + int64_t idx = var_expr->get_ref_index(); + if (idx > max_idx) { + max_idx = idx; + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); i++) { + ObRawExpr *child_expr = NULL; + if (OB_ISNULL(child_expr = expr->get_param_expr(i))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret)); + } else if (child_expr->get_expr_type() == T_FUNC_SYS_ARRAY_MAP) { + // do nothing + } else if (OB_FAIL(get_max_lambda_param_idx(child_expr, max_idx))) { + LOG_WARN("get max lambda param idx failed", K(ret)); + } + } + } + return ret; +} + +int ObRawExprPrinter::print_array_map(ObSysFunRawExpr *expr) +{ + int ret = OB_SUCCESS; + uint32_t max_idx = 0; + if (OB_ISNULL(expr) || (expr->get_param_count() < 2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param count of expr", K(ret), KPC(expr)); + } else if (OB_FAIL(get_max_lambda_param_idx(expr->get_param_expr(0), max_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("doc type value isn't int value"); + } else { + DATA_PRINTF("array_map(("); + for (uint8_t i = 0; i <= max_idx; i++) { + if (i != 0) { + DATA_PRINTF(","); + } + char token = static_cast('a' + i); + DATA_PRINTF("%c", token); + } + DATA_PRINTF(")->("); + PRINT_EXPR(expr->get_param_expr(0)); + DATA_PRINTF(")"); + for (int i = 1; i < expr->get_param_count() && OB_SUCC(ret); i++) { + DATA_PRINTF(","); + PRINT_EXPR(expr->get_param_expr(i)); + } + DATA_PRINTF(")"); + } + return ret; +} } //end of namespace sql } //end of namespace oceanbase diff --git a/src/sql/printer/ob_raw_expr_printer.h b/src/sql/printer/ob_raw_expr_printer.h index 7434965d7a..54085ba832 100644 --- a/src/sql/printer/ob_raw_expr_printer.h +++ b/src/sql/printer/ob_raw_expr_printer.h @@ -162,6 +162,9 @@ private: int print_sql_udt_attr_access(ObSysFunRawExpr *expr); int print_sql_udt_construct(ObSysFunRawExpr *expr); int print_st_asmvt(ObAggFunRawExpr *expr); + int print_array_agg_expr(ObAggFunRawExpr *expr); + int print_array_map(ObSysFunRawExpr *expr); + int get_max_lambda_param_idx(ObRawExpr *expr, uint32_t &max_idx); int print_type(const ObExprResType &dst_type); diff --git a/src/sql/resolver/ddl/ob_create_table_resolver.cpp b/src/sql/resolver/ddl/ob_create_table_resolver.cpp index e43075921f..86cff564fa 100644 --- a/src/sql/resolver/ddl/ob_create_table_resolver.cpp +++ b/src/sql/resolver/ddl/ob_create_table_resolver.cpp @@ -2170,8 +2170,20 @@ int ObCreateTableResolver::resolve_table_elements_from_select(const ParseNode &p } column.set_meta_type(column_meta); if (column.is_collection()) { // array column - if (OB_FAIL(column.set_extended_type_info(expr->get_enum_set_values()))) { - LOG_WARN("set enum or set info failed", K(ret), K(*expr)); + if (T_REF_COLUMN == expr->get_expr_type()) { + if(OB_FAIL(column.set_extended_type_info(expr->get_enum_set_values()))) { + LOG_WARN("set enum or set info failed", K(ret), K(*expr)); + } + } else { + const ObSqlCollectionInfo *coll_info = NULL; + uint16_t subschema_id = expr->get_result_type().get_subschema_id(); + ObSubSchemaValue value; + if (OB_FAIL(session_info_->get_cur_exec_ctx()->get_sqludt_meta_by_subschema_id(subschema_id, value))) { + LOG_WARN("failed to get subschema ctx", K(ret)); + } else if (FALSE_IT(coll_info = reinterpret_cast(value.value_))) { + } else if (OB_FAIL(column.add_type_info(coll_info->get_def_string()))) { + LOG_WARN("set type info failed", K(ret)); + } } } ObCharsetType char_type = table_schema.get_charset_type(); diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index cbac0a5799..60248660bf 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -4234,6 +4234,19 @@ int ObDMLResolver::resolve_table(const ParseNode &parse_tree, } break; } + case T_UNNEST_EXPRESSION: { + if (OB_ISNULL(session_info_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret)); + } else if (lib::is_mysql_mode() && T_UNNEST_EXPRESSION == table_node->type_ + && GET_MIN_CLUSTER_VERSION() < DATA_VERSION_4_3_3_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unnest not support before 4.3.4", K(ret), K(GET_MIN_CLUSTER_VERSION())); + } else if (OB_FAIL(resolve_unnest_item(*table_node, table_item))) { + LOG_WARN("failed to resolve unnest item", K(ret)); + } + break; + } case T_VALUES_TABLE_EXPRESSION: { if (OB_FAIL(resolve_values_table_item(*table_node, table_item))) { LOG_WARN("failed to resolve values table item", K(ret)); @@ -5166,27 +5179,25 @@ int ObDMLResolver::resolve_str_const(const ParseNode &parse_tree, ObString& path int ObDMLResolver::resolve_rb_iterate_item(const ParseNode &parse_tree, TableItem *&tbl_item) { int ret = OB_SUCCESS; - ObDMLStmt *stmt = get_stmt(); TableItem *item = NULL; ColumnItem *col_item = NULL; ParseNode *expr_node = NULL; - ParseNode *alias_node = NULL; + ParseNode *table_name_node = NULL; + ParseNode *col_name_node = NULL; ObRawExpr *rb_expr = NULL; - ObString alias_name; + ObString table_name; + ObString col_name; - if (T_RB_ITERATE_EXPRESSION != parse_tree.type_ || 2 != parse_tree.num_child_) { + if (T_RB_ITERATE_EXPRESSION != parse_tree.type_ || 3 != parse_tree.num_child_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table type not support ot param num mismatch", K(parse_tree.type_), K(parse_tree.num_child_)); - } else if ((OB_ISNULL(stmt) || OB_ISNULL(allocator_))) { - ret = OB_NOT_INIT; - LOG_WARN("resolver isn't init", K(ret), KP(stmt), KP(allocator_)); } else if (OB_ISNULL(expr_node = parse_tree.children_[0])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr node is null", K(ret)); } else { - alias_node = parse_tree.children_[1]; + table_name_node = parse_tree.children_[1]; + col_name_node = parse_tree.children_[2]; } - // resolve parse nodes if (OB_FAIL(ret)) { } else if (OB_FAIL(resolve_sql_expr(*(expr_node), rb_expr))) { @@ -5200,21 +5211,28 @@ int ObDMLResolver::resolve_rb_iterate_item(const ParseNode &parse_tree, TableIte rb_expr->set_extra(extra); OZ (rb_expr->deduce_type(session_info_)); } - // resolve alias_node + // resolve table_name_node if (OB_FAIL(ret)) { - } else if (OB_ISNULL(alias_node)) { - alias_name = ObString("rb_iterate"); + } else if (OB_ISNULL(table_name_node)) { + table_name = ObString("rb_iterate"); } else { - alias_name.assign_ptr(alias_node->str_value_, alias_node->str_len_); + table_name.assign_ptr(table_name_node->str_value_, table_name_node->str_len_); + } + // resolve col_name_node + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(col_name_node)) { + // use table name as column name + col_name.assign_ptr(table_name.ptr(), table_name.length()); + } else { + col_name.assign_ptr(col_name_node->str_value_, col_name_node->str_len_); } - // create a table item and add root column if (OB_FAIL(ret)) { - } else if (OB_FAIL(create_rb_iterate_table_item(item, alias_name))) { + } else if (OB_FAIL(create_unnest_table_item(item, T_RB_ITERATE_EXPRESSION, table_name))) { LOG_WARN("failed to create rb iterate table item", K(ret)); } else if (OB_FAIL(item->json_table_def_->doc_exprs_.push_back(rb_expr))) { LOG_WARN("failed to push back rb expr", K(ret)); - } else if (OB_FAIL(rb_iterate_table_add_column(item, col_item))) { + } else if (OB_FAIL(unnest_table_add_column(item, col_item, col_name))) { LOG_WARN("failed to add rb iterate table column", K(ret)); } else { tbl_item = item; @@ -5223,6 +5241,81 @@ int ObDMLResolver::resolve_rb_iterate_item(const ParseNode &parse_tree, TableIte return ret; } +int ObDMLResolver::resolve_unnest_item(const ParseNode &parse_tree, TableItem *&tbl_item) +{ + int ret = OB_SUCCESS; + TableItem *item = NULL; + ParseNode *expr_node = NULL; + ParseNode *table_name_node = NULL; + ParseNode *col_name_node = NULL; + ObString table_name; + + if (T_UNNEST_EXPRESSION != parse_tree.type_ || 3 != parse_tree.num_child_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table type not support ot param num mismatch", K(parse_tree.type_), K(parse_tree.num_child_)); + } else if (OB_ISNULL(expr_node = parse_tree.children_[0]) || expr_node->type_ != T_EXPR_LIST) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr node is not expected", K(ret), K(parse_tree.children_[0])); + } else if (OB_FALSE_IT(table_name_node = parse_tree.children_[1])) { + } else if (OB_NOT_NULL(col_name_node = parse_tree.children_[2])) { + if (col_name_node->type_ != T_EXPR_LIST) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column name node is not expected", K(ret), K(parse_tree.children_[2])); + } else if (col_name_node->num_child_ != expr_node->num_child_) { + ret = OB_ERR_PARAM_SIZE; + LOG_WARN("size of column name is invalid", K(ret), K(expr_node->num_child_), K(col_name_node->num_child_)); + } + } + + // resolve table_name node + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(table_name_node)) { + table_name = ObString("unnest"); + } else { + table_name.assign_ptr(table_name_node->str_value_, table_name_node->str_len_); + } + + for (int64_t i = 0; OB_SUCC(ret) && i < expr_node->num_child_; ++i) { + ObRawExpr *expr = NULL; + ColumnItem *col_item = NULL; + ObString col_name; + // resolve expr nodes + if (OB_FAIL(resolve_sql_expr(*(expr_node->children_[i]), expr))) { + LOG_WARN("fail to resolve sql expr", K(ret)); + } else if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("rb expr is null", K(ret)); + } else { + uint64_t extra = expr->get_extra(); + extra |= CM_ERROR_ON_SCALE_OVER; + expr->set_extra(extra); + OZ (expr->deduce_type(session_info_)); + } + // resolve col_name node + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(col_name_node)) { + col_name = ObString("unnest"); + } else { + col_name.assign_ptr(col_name_node->children_[i]->str_value_, col_name_node->children_[i]->str_len_); + } + // create a table item and add columns + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(item) && OB_FAIL(create_unnest_table_item(item, parse_tree.type_, table_name))) { + LOG_WARN("failed to create rb iterate table item", K(ret)); + } else if (OB_FAIL(item->json_table_def_->doc_exprs_.push_back(expr))) { + LOG_WARN("failed to push back rb expr", K(ret)); + } else if (OB_FAIL(unnest_table_add_column(item, col_item, col_name))) { + LOG_WARN("failed to add unnest table column", K(ret)); + } + } // end for + + if (OB_SUCC(ret)) { + tbl_item = item; + } + + return ret; +} + int ObDMLResolver::create_rb_iterate_table_item(TableItem *&table_item, ObString alias_name) { INIT_SUCC(ret); @@ -5304,6 +5397,67 @@ int ObDMLResolver::create_rb_iterate_table_item(TableItem *&table_item, ObString return ret; } +int ObDMLResolver::create_unnest_table_item(TableItem *&table_item, ObItemType item_type, ObString table_name) +{ + INIT_SUCC(ret); + ObDMLStmt *stmt = get_stmt(); + ObJsonTableDef* table_def = NULL; + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("stmt is null", K(stmt), K(ret)); + } else if (OB_ISNULL(table_name) || table_name.empty()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table_name is null", K(ret)); + } else if (OB_ISNULL(table_item = stmt->create_table_item(*allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to create table table_item", K(ret)); + } else if (OB_ISNULL(table_def = static_cast(allocator_->alloc(sizeof(ObJsonTableDef))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("faield to allocate memory json table def buffer", K(ret)); + } else { + table_def = static_cast(new (table_def) ObJsonTableDef()); + if (item_type == T_RB_ITERATE_EXPRESSION) { + table_def->table_type_ = MulModeTableType::OB_RB_ITERATE_TABLE_TYPE; + } else if (item_type == T_UNNEST_EXPRESSION) { + table_def->table_type_ = MulModeTableType::OB_UNNEST_TABLE_TYPE; + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected item_type", K(ret), K(item_type)); + } + } + + if (OB_SUCC(ret)) { + table_item->table_name_ = table_name; + table_item->alias_name_ = table_name; + table_item->table_id_ = generate_table_id(); + table_item->type_ = TableItem::JSON_TABLE; + table_item->json_table_def_ = table_def; + OZ (stmt->add_table_item(session_info_, table_item)); + } + + // create root_col + if (OB_SUCC(ret)) { + ObDmlJtColDef* root_col_def = NULL; + if (OB_ISNULL(root_col_def = static_cast(allocator_->alloc(sizeof(ObDmlJtColDef))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate column def", K(ret)); + } else { + root_col_def = new (root_col_def) ObDmlJtColDef(); + root_col_def->table_id_ = table_item->table_id_; + root_col_def->col_base_info_.col_type_ = NESTED_COL_TYPE; + root_col_def->col_base_info_.parent_id_ = -1; + root_col_def->col_base_info_.id_ = 0; + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(json_table_infos_.push_back(root_col_def))) { + LOG_WARN("failed to push back column info", K(ret)); + } else if (OB_FAIL(table_item->json_table_def_->all_cols_.push_back(&root_col_def->col_base_info_))) { + LOG_WARN("json table cols add param fail", K(ret)); + } + } + + return ret; +} int ObDMLResolver::rb_iterate_table_add_column(TableItem *&table_item, ColumnItem *&col_item, int64_t col_id) { @@ -5371,6 +5525,92 @@ int ObDMLResolver::rb_iterate_table_add_column(TableItem *&table_item, ColumnIte return ret; } +int ObDMLResolver::unnest_table_add_column(TableItem *&table_item, ColumnItem *&col_item, ObString col_name) +{ + INIT_SUCC(ret); + ObDmlJtColDef* col_def = NULL; + common::ObDataType data_type; + int64_t col_id = table_item->json_table_def_->all_cols_.count(); + int32_t col_type = 0; + if (table_item->json_table_def_->table_type_ == MulModeTableType::OB_RB_ITERATE_TABLE_TYPE) { + col_type = COL_TYPE_RB_ITERATE; + } else if (table_item->json_table_def_->table_type_ == MulModeTableType::OB_UNNEST_TABLE_TYPE) { + col_type = COL_TYPE_UNNEST; + } + + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(col_def = static_cast(allocator_->alloc(sizeof(ObDmlJtColDef))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret)); + } else { + col_def = new (col_def) ObDmlJtColDef(); + col_def->col_base_info_.col_name_.assign_ptr(col_name.ptr(), col_name.length()); + col_def->col_base_info_.col_type_ = col_type; + col_def->col_base_info_.parent_id_ = 0; + col_def->col_base_info_.id_ = col_id; + col_def->col_base_info_.output_column_idx_ = col_id; + } + + // resolve data type + if (OB_FAIL(ret)) { + } else if (col_type == COL_TYPE_RB_ITERATE) { + data_type.set_collation_level(CS_LEVEL_IMPLICIT); + data_type.set_uint64(); + data_type.set_accuracy(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type]); + } else if (col_type == COL_TYPE_UNNEST) { + ObRawExpr *value_expr = table_item->json_table_def_->doc_exprs_[col_id - 1]; + uint16_t subschema_id = value_expr->get_subschema_id(); + ObSubSchemaValue value; + if (ObCollectionSQLType != value_expr->get_data_type()) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid array data type provided.", K(ret), K(value_expr->get_data_type())); + } else if (OB_FAIL(session_info_->get_cur_exec_ctx()->get_sqludt_meta_by_subschema_id(subschema_id, value))) { + LOG_WARN("failed to get subschema ctx", K(ret)); + } else if (value.type_ >= OB_SUBSCHEMA_MAX_TYPE) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema type", K(ret), K(value)); + } else { + const ObSqlCollectionInfo *coll_info = reinterpret_cast(value.value_); + ObCollectionArrayType *arr_type = static_cast(coll_info->collection_meta_); + if (arr_type->element_type_->type_id_ == ObNestedType::OB_BASIC_TYPE) { + ObCollectionBasicType *elem_type = static_cast(arr_type->element_type_); + data_type = elem_type->basic_meta_; + } else if (arr_type->element_type_->type_id_ == ObNestedType::OB_ARRAY_TYPE) { + ObString child_def; + uint16_t child_subschema_id = 0; + if (OB_FAIL(coll_info->get_child_def_string(child_def))) { + LOG_WARN("failed to get child define", K(ret), K(*coll_info)); + } else if (OB_FAIL(session_info_->get_cur_exec_ctx()->get_subschema_id_by_type_string(child_def, child_subschema_id))) { + LOG_WARN("failed to get child subschema id", K(ret), K(*coll_info), K(child_def)); + } else { + data_type.set_collation_level(CS_LEVEL_IMPLICIT); + data_type.set_obj_type(ObCollectionSQLType); + data_type.set_subschema_id(child_subschema_id); + } + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supportted array data type provided.", K(ret), K(arr_type->element_type_->type_id_)); + } + } + } + + // resolve column item + if (OB_SUCC(ret)) { + col_def->col_base_info_.data_type_ = data_type; + if (OB_FAIL(generate_json_table_output_column_item(table_item, + data_type, + col_def->col_base_info_.col_name_, + col_def->col_base_info_.id_, + col_item))) { + LOG_WARN("failed to generate json column.", K(ret)); + } else if (OB_FALSE_IT(col_item->col_idx_ = table_item->json_table_def_->all_cols_.count())) { + } else if (OB_FAIL(table_item->json_table_def_->all_cols_.push_back(&col_def->col_base_info_))) { + LOG_WARN("failed to push_back col_base_info_ to all_cols_", K(ret)); + } + } + + return ret; +} int ObDMLResolver::resolve_json_table_item(const ParseNode &parse_tree, TableItem *&tbl_item) { int ret = OB_SUCCESS; @@ -10748,13 +10988,27 @@ int ObDMLResolver::resolve_json_table_column_item(const TableItem &table_item, int ret = OB_SUCCESS; col_item = NULL; ObDMLStmt *stmt = get_stmt(); + ObSEArray columns; CK (OB_NOT_NULL(stmt)); CK (OB_LIKELY(table_item.is_json_table())); CK (OB_NOT_NULL(table_item.json_table_def_)); if (OB_FAIL(ret)) { + } else if (OB_FAIL(stmt->get_column_items(table_item.table_id_, columns))) { + LOG_WARN("failed to get column items", K(ret)); } else { - col_item = stmt->get_column_item(table_item.table_id_, column_name); - if (OB_ISNULL(col_item)) { + common::ObCollationType cs_type = lib::is_oracle_mode() ? common::CS_TYPE_UTF8MB4_BIN : common::CS_TYPE_UTF8MB4_GENERAL_CI; + for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) { + if (0 == ObCharset::strcmp(cs_type, column_name, columns.at(i).column_name_)) { + if (OB_ISNULL(col_item)) { + col_item = &columns.at(i); + } else { + ret = OB_NON_UNIQ_ERROR; + LOG_USER_ERROR(OB_NON_UNIQ_ERROR, column_name.length(), column_name.ptr(), + table_item.get_table_name().length(), table_item.get_table_name().ptr()); + } + } + } // end for + if (OB_SUCC(ret) && OB_ISNULL(col_item)) { ret = OB_ERR_BAD_FIELD_ERROR; LOG_WARN("column not exists", K(column_name), K(ret)); } diff --git a/src/sql/resolver/dml/ob_dml_resolver.h b/src/sql/resolver/dml/ob_dml_resolver.h index 8aeb560e98..393e6853af 100644 --- a/src/sql/resolver/dml/ob_dml_resolver.h +++ b/src/sql/resolver/dml/ob_dml_resolver.h @@ -206,8 +206,11 @@ public: TableItem *&table_item); int resolve_rb_iterate_item(const ParseNode &table_node, TableItem *&table_item); + int resolve_unnest_item(const ParseNode &table_node, TableItem *&table_item); int create_rb_iterate_table_item(TableItem *&table_item, ObString alias_name = NULL); + int create_unnest_table_item(TableItem *&table_item, ObItemType item_type, ObString table_name); int rb_iterate_table_add_column(TableItem *&table_item, ColumnItem *&col_item, int64_t col_id = 1); + int unnest_table_add_column(TableItem *&table_item, ColumnItem *&col_item, ObString col_name); int resolve_xml_namespaces(const ParseNode *namespace_node, ObJsonTableDef*& table_def); int fill_same_column_to_using(JoinedTable* &joined_table); diff --git a/src/sql/resolver/dml/ob_dml_stmt.h b/src/sql/resolver/dml/ob_dml_stmt.h index 3c274bc94e..0b7cfe1615 100644 --- a/src/sql/resolver/dml/ob_dml_stmt.h +++ b/src/sql/resolver/dml/ob_dml_stmt.h @@ -157,6 +157,7 @@ enum MulModeTableType { OB_ORA_JSON_TABLE_TYPE, // 1 OB_ORA_XML_TABLE_TYPE = 2, OB_RB_ITERATE_TABLE_TYPE = 3, + OB_UNNEST_TABLE_TYPE = 4, }; typedef struct ObJtColBaseInfo diff --git a/src/sql/resolver/dml/ob_merge_resolver.cpp b/src/sql/resolver/dml/ob_merge_resolver.cpp index 2747412442..2785a1d71c 100644 --- a/src/sql/resolver/dml/ob_merge_resolver.cpp +++ b/src/sql/resolver/dml/ob_merge_resolver.cpp @@ -386,6 +386,10 @@ int ObMergeResolver::resolve_table(const ParseNode &parse_tree, TableItem *&tabl OZ (resolve_rb_iterate_item(*table_node, table_item)); break; } + case T_UNNEST_EXPRESSION: { + OZ (resolve_unnest_item(*table_node, table_item)); + break; + } default: { /* won't be here */ ret = OB_ERR_PARSER_SYNTAX; diff --git a/src/sql/resolver/expr/ob_raw_expr.cpp b/src/sql/resolver/expr/ob_raw_expr.cpp index 75dabb6ea7..e61d681f73 100644 --- a/src/sql/resolver/expr/ob_raw_expr.cpp +++ b/src/sql/resolver/expr/ob_raw_expr.cpp @@ -1034,7 +1034,8 @@ int ObRawExpr::is_const_inherit_expr(bool &is_const_inherit, || T_FUN_SYS_IS_FREE_LOCK == type_ || T_FUN_SYS_IS_USED_LOCK == type_ || T_FUN_SYS_RELEASE_LOCK == type_ - || T_FUN_SYS_RELEASE_ALL_LOCKS == type_) { + || T_FUN_SYS_RELEASE_ALL_LOCKS == type_ + || T_EXEC_VAR == type_) { is_const_inherit = false; } if (is_const_inherit && T_OP_GET_USER_VAR == type_) { @@ -1668,6 +1669,8 @@ int ObVarRawExpr::assign(const ObRawExpr &other) } else { const ObVarRawExpr &var_expr = static_cast(other); result_type_assigned_ = var_expr.result_type_assigned_; + ref_expr_ = var_expr.get_ref_expr(); + ref_index_ = var_expr.get_ref_index(); } } return ret; @@ -1687,9 +1690,18 @@ bool ObVarRawExpr::inner_same_as(const ObRawExpr &expr, ObExprEqualCheckContext *check_context) const { UNUSED(check_context); - return expr.is_var_expr() + bool res = expr.is_var_expr() && get_expr_type() == expr.get_expr_type() && get_result_type() == expr.get_result_type(); + if (res && ref_expr_ != NULL) { + const ObVarRawExpr &var_expr = static_cast(expr); + if (var_expr.get_ref_expr() == NULL) { + res = false; + } else { + res = ref_expr_->same_as(*var_expr.get_ref_expr(), check_context); + } + } + return res; } void ObVarRawExpr::inner_calc_hash() diff --git a/src/sql/resolver/expr/ob_raw_expr.h b/src/sql/resolver/expr/ob_raw_expr.h index c972178852..38706e881e 100644 --- a/src/sql/resolver/expr/ob_raw_expr.h +++ b/src/sql/resolver/expr/ob_raw_expr.h @@ -2371,13 +2371,17 @@ public: : ObIRawExpr(alloc), ObTerminalRawExpr(alloc), ObVarExpr(), - result_type_assigned_(false) + result_type_assigned_(false), + ref_expr_(nullptr), + ref_index_(common::OB_INVALID_ID) { ObIRawExpr::set_expr_class(ObIRawExpr::EXPR_VAR); } ObVarRawExpr(ObItemType expr_type = T_INVALID) : ObIRawExpr(expr_type), ObTerminalRawExpr(expr_type), ObVarExpr(), - result_type_assigned_(false) + result_type_assigned_(false), + ref_expr_(nullptr), + ref_index_(common::OB_INVALID_ID) { set_expr_class(ObIRawExpr::EXPR_VAR); } virtual ~ObVarRawExpr() {} @@ -2394,9 +2398,15 @@ public: int get_name_internal(char *buf, const int64_t buf_len, int64_t &pos, ExplainType type) const; void set_result_type_assigned(bool v) { result_type_assigned_ = v; } bool get_result_type_assigned() { return result_type_assigned_; } + ObRawExpr *get_ref_expr() const { return ref_expr_; } + int64_t get_ref_index() const { return ref_index_; } + void set_ref_index(int64_t ref_index) { ref_index_ = ref_index; } + void set_ref_expr(ObRawExpr *ref_expr) { ref_expr_ = ref_expr; } private: bool result_type_assigned_; + ObRawExpr *ref_expr_; + int64_t ref_index_; DISALLOW_COPY_AND_ASSIGN(ObVarRawExpr); }; diff --git a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp index 07231b1d54..e787b8a7ba 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp @@ -29,6 +29,7 @@ #include "sql/engine/aggregate/ob_aggregate_processor.h" #include "sql/engine/expr/ob_expr_between.h" #include "sql/engine/expr/ob_expr_cast.h" +#include "sql/engine/expr/ob_array_expr_utils.h" #include "share/ob_lob_access_utils.h" #include "sql/parser/ob_parser.h" @@ -93,7 +94,43 @@ int ObRawExprDeduceType::visit(ObConstRawExpr &expr) int ObRawExprDeduceType::visit(ObVarRawExpr &expr) { int ret = OB_SUCCESS; - if (!(expr.get_result_type().is_null())) { + if (expr.get_ref_expr() != NULL) { + if (OB_FAIL(expr.get_ref_expr()->postorder_accept(*this))) { + LOG_WARN("failed to deduce ref expr", K(ret)); + } else if (expr.get_ref_expr()->get_result_type().is_null()) { + expr.set_result_type(expr.get_ref_expr()->get_result_type()); + } else if (expr.get_ref_expr()->get_result_type().is_collection_sql_type()) { + ObRawExpr *ref_expr = expr.get_ref_expr(); + // get array element tyoe + ObSQLSessionInfo *session = const_cast(my_session_); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + uint32_t depth = 0; + bool is_vec = false; + ObDataType coll_elem_type; + uint16_t subschema_id = ref_expr->get_result_type().get_subschema_id(); + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec_ctx should not be NULL", K(ret)); + } else if (OB_FAIL(ObArrayExprUtils::get_array_element_type(exec_ctx, subschema_id, coll_elem_type, depth, is_vec))) { + LOG_WARN("failed to get array element type", K(ret)); + } else if (depth > 1) { + uint16_t child_subid = 0; + if (OB_FAIL(ObArrayExprUtils::get_child_subschema_id(exec_ctx, subschema_id, child_subid))) { + LOG_WARN("failed to get child subschema id", K(ret)); + } else { + ObExprResType res_type; + res_type.set_collection(child_subid); + expr.set_result_type(res_type); + } + } else { + expr.set_meta_type(coll_elem_type.get_meta_type()); + expr.set_accuracy(coll_elem_type.get_accuracy()); + } + } else { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("unexpected ref expr result type", K(expr), K(ret), K(expr.get_ref_expr()->get_result_type().get_type())); + } + } else if (!(expr.get_result_type().is_null())) { expr.set_result_flag(NOT_NULL_FLAG); } return ret; @@ -1727,6 +1764,12 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) } break; } + case T_FUNC_SYS_ARRAY_AGG: { + if (OB_FAIL(set_array_agg_result_type(expr, result_type))) { + LOG_WARN("set array agg result type failed", K(ret)); + } + break; + } case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: case T_FUN_SYS_RB_AND_AGG: { @@ -3681,6 +3724,59 @@ int ObRawExprDeduceType::set_asmvt_result_type(ObAggFunRawExpr &expr, return ret; } +int ObRawExprDeduceType::set_array_agg_result_type(ObAggFunRawExpr &expr, + ObExprResType& result_type) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(expr.get_real_param_count() < 1)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("get unexpected error", K(ret), K(expr.get_param_count()), K(expr.get_real_param_count()), K(expr)); + } else { + // check order by constrain + const common::ObIArray& order_item = expr.get_order_items(); + for (int64_t i = 0; OB_SUCC(ret) && i < order_item.count(); ++i) { + ObRawExpr* order_expr = order_item.at(i).expr_; + if (OB_ISNULL(order_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("internal order expr is null", K(ret)); + } else if (order_expr->get_result_type().get_type() == ObCollectionSQLType) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("array type used for sorting isn't supported", K(ret)); + } + } + + ObSQLSessionInfo *session = const_cast(my_session_); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + const ObRawExpr *param_expr = expr.get_param_expr(0); + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(param_expr) || OB_ISNULL(session)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected NULL", K(param_expr), K(session), K(ret)); + } else if (OB_ISNULL(session->get_cur_exec_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected NULL", K(param_expr), K(session), K(ret)); + } else { + ObExecContext *exec_ctx = session->get_cur_exec_ctx(); + ObDataType elem_type; + uint16_t subschema_id; + elem_type.set_meta_type(param_expr->get_result_meta()); + if (ob_is_collection_sql_type(elem_type.get_obj_type())) { + if (OB_FAIL(ObArrayExprUtils::deduce_nested_array_subschema_id(exec_ctx, elem_type, subschema_id))) { + LOG_WARN("failed to deduce nested array subschema id", K(ret)); + } + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_collection_elem_type(ObNestedType::OB_ARRAY_TYPE, + elem_type, subschema_id))) { + LOG_WARN("failed to get collection subschema id", K(ret)); + } + if (OB_SUCC(ret)) { + result_type.set_collection(subschema_id); + expr.set_result_type(result_type); + } + } + } + return ret; +} + int ObRawExprDeduceType::set_rb_result_type(ObAggFunRawExpr &expr, ObExprResType& result_type) { diff --git a/src/sql/resolver/expr/ob_raw_expr_deduce_type.h b/src/sql/resolver/expr/ob_raw_expr_deduce_type.h index 6a414ef64e..66234810ab 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.h +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.h @@ -122,6 +122,7 @@ private: int set_xmlagg_result_type(ObAggFunRawExpr &expr, ObExprResType& result_type); int set_agg_xmlagg_result_type(ObAggFunRawExpr &expr, ObExprResType& result_type); + int set_array_agg_result_type(ObAggFunRawExpr &expr, ObExprResType& result_type); // helper functions for add_implicit_cast int add_implicit_cast_for_op_row(ObRawExpr *&child_ptr, diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp index bf81ee4d9b..bcd825add7 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp @@ -866,7 +866,8 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, case T_FUN_SYS_ST_ASMVT: case T_FUN_SYS_RB_BUILD_AGG: case T_FUN_SYS_RB_OR_AGG: - case T_FUN_SYS_RB_AND_AGG: { + case T_FUN_SYS_RB_AND_AGG: + case T_FUNC_SYS_ARRAY_AGG: { if (OB_FAIL(process_agg_node(node, expr))) { LOG_WARN("fail to process agg node", K(ret), K(node)); } @@ -1307,6 +1308,18 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, OZ (process_vector_func_node(node, expr)); break; } + case T_FUNC_SYS_ARRAY_MAP: { + OZ (process_array_map_func_node(node, expr)); + break; + } + case T_FUNC_SYS_LAMBDA: { + OZ (process_lambda_func_node(node, expr)); + break; + } + case T_EXEC_VAR: { + OZ (process_lambda_var_node(node, expr)); + break; + } case T_FUN_SYS_XML_ELEMENT: { if (OB_FAIL(process_xml_element_node(node, expr))) { LOG_WARN("failed to process xmlelement node", K(ret)); @@ -3527,6 +3540,224 @@ int ObRawExprResolverImpl::process_geo_func_node(const ParseNode *node, ObRawExp return ret; } +int ObRawExprResolverImpl::process_lambda_var_node(const ParseNode *node, ObRawExpr *&expr) +{ + int ret = OB_SUCCESS; + ObVarRawExpr *para_expr = NULL; + if (OB_FAIL(ctx_.expr_factory_.create_raw_expr(T_EXEC_VAR, para_expr))) { + LOG_WARN("fail to create raw expr", K(ret)); + } else if (OB_ISNULL(para_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column ref expr is null"); + } else { + para_expr->set_ref_index(node->reserved_); + expr = para_expr; + } + return ret; +} + +int ObRawExprResolverImpl::extract_var_exprs(ObRawExpr *expr, ObIArray &var_exprs) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(expr)); + } else if (expr->is_aggr_expr()) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "aggr expr in lambda function"); + LOG_WARN("aggr expr is not supported in lambda function", K(ret)); + }else if (expr->get_expr_type() == T_EXEC_VAR) { + ObVarRawExpr *var_expr = static_cast(expr); + if (OB_FAIL(add_var_to_array_no_dup(var_exprs, var_expr))) { + LOG_WARN("failed to add var to array no dup", K(ret)); + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { + if (OB_FAIL(SMART_CALL(extract_var_exprs(expr->get_param_expr(i), var_exprs)))) { + LOG_WARN("Failed to extract var exprs", K(ret)); + } + } + } + return ret; +} + +int ObRawExprResolverImpl::check_replace_lambda_params_node(const ParseNode *params_node, ParseNode *func_node) +{ + int ret = OB_SUCCESS; + ParseNode *curr_node = func_node; + if (OB_ISNULL(curr_node)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret)); + } else { + if (curr_node->type_ == T_COLUMN_REF) { + bool found = false; + if (OB_ISNULL(curr_node->str_value_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to recursive resolve expr list item", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < params_node->num_child_ && !found; ++i) { + ParseNode *para_node = params_node->children_[i]; + if (OB_ISNULL(para_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid expr list node children", K(ret), K(i), K(params_node->children_[i])); + } else if (OB_ISNULL(para_node->str_value_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to recursive resolve expr list item", K(ret)); + } else if (strncmp(curr_node->str_value_, para_node->str_value_, curr_node->str_len_) == 0) { + if (curr_node->str_len_ == para_node->str_len_) { + found = true; + curr_node->reserved_ = i; + curr_node->type_ = T_EXEC_VAR; + } + } + } + } else { + for (uint32_t i = 0; OB_SUCC(ret) && i < curr_node->num_child_; ++i) { + if (curr_node->children_[i] == NULL) { + } else if (OB_FAIL(check_replace_lambda_params_node(params_node, const_cast(curr_node->children_[i])))) { + LOG_WARN("fail to replace lambda params", K(ret)); + } + } + } + } + return ret; +} + +int ObRawExprResolverImpl::check_lambda_params_duplicated(const ParseNode *params_node) +{ + int ret = OB_SUCCESS; + for (uint32_t i = 0; OB_SUCC(ret) && i < params_node->num_child_; ++i) { + ParseNode *para_node = params_node->children_[i]; + if (OB_ISNULL(para_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid expr list node children", K(ret), K(i), K(params_node->children_[i])); + } else if (OB_ISNULL(para_node->str_value_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to recursive resolve expr list item", K(ret)); + } else { + for (uint32_t j = 0; OB_SUCC(ret) && j < i; ++j) { + if (strncmp(params_node->children_[j]->str_value_, para_node->str_value_, para_node->str_len_) == 0) { + // duplicated param name + ret = OB_ERR_PARAM_DUPLICATE; + LOG_WARN("duplicated param name", K(ret), KCSTRING(para_node->str_value_)); + } + } + } + } + return ret; +} + +int ObRawExprResolverImpl::process_lambda_func_node(const ParseNode *node, ObRawExpr *&expr) +{ + int ret = OB_SUCCESS; + ObSysFunRawExpr *func_expr = NULL; + + if (OB_ISNULL(node)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(node)); + } else if (OB_FAIL(ctx_.expr_factory_.create_raw_expr(node->type_, func_expr))) { + LOG_WARN("fail to create raw expr", K(ret)); + }else { + func_expr->set_func_name("lambda"); + ObRawExpr *sub_expr1 = NULL; + ObRawExpr *sub_expr2 = NULL; + if (OB_UNLIKELY(2 != node->num_child_) || OB_ISNULL(node->children_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid node children", K(ret), K_(node->num_child), + K_(node->children), K_(node->type)); + } else if (OB_FAIL(check_lambda_params_duplicated(node->children_[0]))) { + LOG_WARN("check params duplicated failed", K(ret)); + }else if (OB_FAIL(check_replace_lambda_params_node(node->children_[0], const_cast(node->children_[1])))) { + LOG_WARN("fail to replace lambda params", K(ret)); + } else if (OB_FAIL(SMART_CALL(recursive_resolve(node->children_[1], sub_expr1)))) { + LOG_WARN("resolve function child failed", K(ret)); + } else if (sub_expr1->is_query_ref_expr()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("query expr isn't supported in lambda function", K(ret)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "query expr in lambda function"); + } else if (OB_FAIL(func_expr->add_param_expr(sub_expr1))) { + LOG_WARN("fail to add param expr to expr", K(ret)); + } + } + + if (OB_SUCC(ret)) { + expr = func_expr; + } + return ret; +} + +int ObRawExprResolverImpl::process_array_map_func_node(const ParseNode *node, ObRawExpr *&expr) +{ + int ret = OB_SUCCESS; + ObSysFunRawExpr *func_expr = NULL; + + if (OB_ISNULL(node)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(node)); + } else if (OB_FAIL(ctx_.expr_factory_.create_raw_expr(node->type_, func_expr))) { + LOG_WARN("fail to create raw expr", K(ret)); + } else { + func_expr->set_func_name("array_map"); + ObRawExpr *sub_expr1 = NULL; + ObRawExpr *sub_expr2 = NULL; + if (OB_UNLIKELY(2 != node->num_child_) || OB_ISNULL(node->children_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid node children", K(ret), K_(node->num_child), + K_(node->children), K_(node->type)); + } else if (OB_FAIL(SMART_CALL(recursive_resolve(node->children_[0], sub_expr1)))) { + LOG_WARN("resolve x child failed", K(ret)); + } else if (sub_expr1->get_expr_type() != T_FUNC_SYS_LAMBDA) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected expr type", K(ret), K(sub_expr1->get_expr_type())); + } else { + ObSEArray var_exprs; + for (int64_t i = 0; OB_SUCC(ret) && i < sub_expr1->get_param_count(); ++i) { + if (OB_FAIL(func_expr->add_param_expr(sub_expr1->get_param_expr(i)))) { + LOG_WARN("fail to add param expr to expr", K(ret)); + } else if (OB_FAIL(extract_var_exprs(sub_expr1->get_param_expr(i), var_exprs))) { + LOG_WARN("fail to extract var exprs", K(ret)); + } + } + if (OB_SUCC(ret)) { + ParseNode *expr_list_node = node->children_[1]; + if (OB_ISNULL(expr_list_node) || OB_UNLIKELY(T_EXPR_LIST != expr_list_node->type_) + || OB_ISNULL(expr_list_node->children_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid children for geometry type function", K(node), K(expr_list_node)); + } else if (expr_list_node->num_child_ != node->children_[0]->children_[0]->num_child_) { + ret = OB_ERR_PARAM_SIZE; + ObString func_name_("lambda function"); + LOG_USER_ERROR(OB_ERR_PARAM_SIZE, func_name_.length(), func_name_.ptr()); + LOG_WARN("wrong param number from lambda function", K(ret), + K(expr_list_node->num_child_), K(node->children_[0]->children_[0]->num_child_)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < expr_list_node->num_child_; ++i) { + ObRawExpr *para_expr = NULL; + if (OB_ISNULL(expr_list_node->children_[i])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid expr list node children", K(ret), K(i), K(expr_list_node->children_[i])); + } else if (OB_FAIL(SMART_CALL(recursive_resolve(expr_list_node->children_[i], para_expr)))) { + LOG_WARN("fail to recursive resolve expr list item", K(ret)); + } else if (OB_FAIL(func_expr->add_param_expr(para_expr))) { + LOG_WARN("fail to add param expr to expr", K(ret)); + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < var_exprs.count(); j++) { + ObVarRawExpr* var = var_exprs.at(j); + if (var->get_ref_index() == i) { + var->set_ref_expr(para_expr); + } + } + } + } + } + } + } + if (OB_SUCC(ret)) { + expr = func_expr; + } + return ret; +} + int ObRawExprResolverImpl::process_left_value_node(const ParseNode *node, ObRawExpr *&expr) { int ret = OB_SUCCESS; @@ -5072,6 +5303,59 @@ int ObRawExprResolverImpl::process_agg_node(const ParseNode *node, ObRawExpr *&e } } } + } else if (T_FUNC_SYS_ARRAY_AGG == node->type_) { + sub_expr = NULL; + if (NULL != node->children_[0] && T_DISTINCT == node->children_[0]->type_) { + agg_expr->set_param_distinct(true); + } + for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; ++i) { + if (OB_ISNULL(node->children_[i])) { + // do nothing + } else if (i == 1) { + if (OB_FAIL(SMART_CALL(recursive_resolve(node->children_[i], sub_expr)))) { + LOG_WARN("fail to resursive resolve expr list item", K(ret)); + } else if (OB_FAIL(agg_expr->add_real_param_expr(sub_expr))) { + LOG_WARN("fail to add param expr to agg expr", K(ret)); + } + } else if (i == 2) { + // process order by desc/asc + const ParseNode *sort_list = NULL; + if (OB_UNLIKELY(node->children_[2]->type_ != T_ORDER_BY) + || OB_UNLIKELY(node->children_[2]->num_child_ != 2) + || OB_ISNULL(node->children_[2]->children_) + || OB_ISNULL(sort_list = node->children_[2]->children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid parameter", K(node->children_[1])); + } else if (NULL != node->children_[2]->children_[1]) { + ret = OB_ERR_CBY_OREDER_SIBLINGS_BY_NOT_ALLOWED; + LOG_WARN("should not be here, invalid agg node"); + } else { + for (int32_t i = 0; OB_SUCC(ret) && i < sort_list->num_child_; i++) { + ParseNode *sort_node = sort_list->children_[i]; + OrderItem order_item; + if (OB_FAIL(SMART_CALL(recursive_resolve(sort_node->children_[0], sub_expr)))) { + LOG_WARN("fail to recursive_resolve expr list item", K(ret)); + } else if (OB_FAIL(ObResolverUtils::set_direction_by_mode(*sort_node, order_item))) { + LOG_WARN("failed to set direction by mode", K(ret)); + } else { + order_item.expr_ = sub_expr; + if (OB_FAIL(agg_expr->add_order_item(order_item))) { + LOG_WARN("Add order expression error", K(ret)); + } + } + } + } + } else if (i == 3) { + // process nulls first / nulls last + if (OB_UNLIKELY(node->children_[3]->type_ != T_FIRST) && OB_UNLIKELY(node->children_[3]->type_ != T_LAST)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid parameter", K(node->children_[3])); + } else if (OB_FAIL(set_array_aggr_null_direction(agg_expr->get_order_items_for_update(), + node->children_[3]->type_ == T_FIRST))) { + LOG_WARN("set array agg null direction failed", K(ret)); + } + } + } } else if (T_FUN_COUNT != node->type_ || (T_FUN_COUNT == node->type_ && 2 == node->num_child_ && T_ALL == node->children_[0]->type_) || T_FUN_GROUPING == node->type_) { @@ -5095,7 +5379,7 @@ int ObRawExprResolverImpl::process_agg_node(const ParseNode *node, ObRawExpr *&e LOG_WARN("fail to add median order item", K(ret)); } else { /* do nothong */ } } - } else { + } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("should not be here, invalid agg node", K(ret), K(node)); } @@ -5494,6 +5778,30 @@ int ObRawExprResolverImpl::reset_keep_aggr_sort_direction(ObIArray &a return ret; } +int ObRawExprResolverImpl::set_array_aggr_null_direction(ObIArray &aggr_sort_item, bool is_null_first) +{ + int ret = OB_SUCCESS; + ObOrderDirection dir; + for (int64_t i = 0; OB_SUCC(ret) && i < aggr_sort_item.count(); ++i) { + switch (aggr_sort_item.at(i).order_type_) + { + case NULLS_FIRST_ASC: + dir = is_null_first ? NULLS_FIRST_ASC : NULLS_LAST_ASC; + aggr_sort_item.at(i).order_type_ = dir; + break; + case NULLS_LAST_DESC: + dir = is_null_first ? NULLS_FIRST_DESC : NULLS_LAST_DESC; + aggr_sort_item.at(i).order_type_ = dir; + break; + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected order type", K(ret), K(aggr_sort_item.at(i).order_type_)); + break; + } + } + return ret; +} + int ObRawExprResolverImpl::process_xmlparse_node(const ParseNode *node, ObRawExpr *&expr) { INIT_SUCC(ret); diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h index 98e4a39f01..5b3b429c6d 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h @@ -220,6 +220,12 @@ private: ObQualifiedName &column_ref, ObRawExpr *&expr); int process_array_contains_node(const ParseNode *node, ObRawExpr *&expr); + int process_lambda_func_node(const ParseNode *node, ObRawExpr *&expr); + int process_array_map_func_node(const ParseNode *node, ObRawExpr *&expr); + int check_replace_lambda_params_node(const ParseNode *params_node, ParseNode *func_node); + int process_lambda_var_node(const ParseNode *node, ObRawExpr *&expr); + int extract_var_exprs(ObRawExpr *expr, ObIArray &var_exprs); + int check_lambda_params_duplicated(const ParseNode *params_node); private: int process_sys_func_params(ObSysFunRawExpr &func_expr, int current_columns_count); int transform_ratio_afun_to_arg_div_sum(const ParseNode *ratio_to_report, ParseNode *&div); @@ -227,6 +233,7 @@ private: int get_opposite_string(const common::ObString &orig_string, common::ObString &new_string, common::ObIAllocator &allocator); int reset_keep_aggr_sort_direction(ObIArray &aggr_sort_item); int reset_aggr_sort_nulls_first(ObIArray &aggr_sort_item); + int set_array_aggr_null_direction(ObIArray &aggr_sort_item, bool is_null_first); inline void set_udf_param_syntax_err(const bool val) { is_udf_param_syntax_err_ = val; } inline bool get_udf_param_syntax_err() { return is_udf_param_syntax_err_; } diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index 50da5432fc..c80d819db1 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -3454,6 +3454,16 @@ int ObRawExprUtils::replace_ref_column(ObRawExpr *&raw_expr, ObRawExpr *from, } else if (OB_FAIL(SMART_CALL(replace_ref_column(relation_exprs, from, to, except_exprs)))) { LOG_WARN("replace reference column failed", K(ret)); } + } else if (raw_expr->is_var_expr()) { + ObVarRawExpr *var_expr = static_cast(raw_expr); + ObRawExpr *ref_expr = var_expr->get_ref_expr(); + if (ref_expr != NULL) { + if (OB_FAIL(SMART_CALL(replace_ref_column(ref_expr, from, to, except_exprs)))) { + LOG_WARN("replace reference column failed", K(ret)); + } else { + var_expr->set_ref_expr(ref_expr); + } + } } else { int64_t N = raw_expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { @@ -3498,6 +3508,16 @@ int ObRawExprUtils::replace_ref_column(ObRawExpr *&raw_expr, } else if (OB_FAIL(SMART_CALL(replace_ref_column(relation_exprs, from, to, except_exprs)))) { LOG_WARN("replace reference column failed", K(ret)); } + } else if (raw_expr->is_var_expr()) { + ObVarRawExpr *var_expr = static_cast(raw_expr); + ObRawExpr *ref_expr = var_expr->get_ref_expr(); + if (ref_expr != NULL) { + if (OB_FAIL(SMART_CALL(replace_ref_column(ref_expr, from, to, except_exprs)))) { + LOG_WARN("replace reference column failed", K(ret)); + } else { + var_expr->set_ref_expr(ref_expr); + } + } } else { int64_t N = raw_expr->get_param_count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { diff --git a/unittest/share/test_array_meta.cpp b/unittest/share/test_array_meta.cpp index 791afec16b..1b7234dbea 100644 --- a/unittest/share/test_array_meta.cpp +++ b/unittest/share/test_array_meta.cpp @@ -13,8 +13,9 @@ #include #define private public #define protected public +#include "lib/hash/ob_hashset.h" #include "lib/udt/ob_collection_type.h" -#include "lib/udt/ob_array_type.h" +#include "lib/udt/ob_array_utils.h" #include "lib/json_type/ob_json_tree.h" #include "lib/json_type/ob_json_bin.h" #include "lib/json_type/ob_json_parse.h" @@ -45,6 +46,8 @@ TEST_F(TestArrayMeta, serialize_deserialize) { ObCollectionBasicType int_type; int_type.basic_meta_.meta_.set_int32(); + int_type.basic_meta_.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObInt32Type].scale_); + int_type.basic_meta_.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObInt32Type].precision_); int_type.type_id_ = ObNestedType::OB_BASIC_TYPE; ObArenaAllocator allocator(ObModIds::TEST); ObCollectionArrayType arr1_type(allocator); @@ -307,25 +310,39 @@ TEST_F(TestArrayMeta, array_compare) ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var2, dst_elem_type)); ASSERT_EQ(OB_SUCCESS, arr_var1->init()); ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + uint64_t hash_val1 = 0; + uint64_t hash_val2 = 0; + ASSERT_EQ(OB_SUCCESS, arr_var1->hash(hash_val1)); + ASSERT_EQ(OB_SUCCESS, arr_var2->hash(hash_val2)); int cmp_ret = 0; ASSERT_EQ(OB_SUCCESS, arr_var1->compare(*arr_var2, cmp_ret)); ASSERT_EQ(0, cmp_ret); + EXPECT_TRUE((*arr_var1) == (*arr_var2)); + ASSERT_EQ(hash_val1, hash_val2); + std::cout << "arr_hash1: " << hash_val1 << "; arr_hash2: " << hash_val2 << std::endl; ObString arr2_text("[3.14, 2.414, 2.718]"); arr_var2->clear(); ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + ASSERT_EQ(OB_SUCCESS, arr_var2->hash(hash_val2)); cmp_ret = 0; ASSERT_EQ(OB_SUCCESS, arr_var1->compare(*arr_var2, cmp_ret)); ASSERT_EQ(-1, cmp_ret); + EXPECT_FALSE((*arr_var1) == (*arr_var2)); + ASSERT_NE(hash_val1, hash_val2); + std::cout << "arr_hash1: " << hash_val1 << "; arr_hash2: " << hash_val2 << std::endl; ObString arr3_text("[3.14, 1.414]"); arr_var2->clear(); ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr3_text, arr_var2, dst_elem_type)); ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + ASSERT_EQ(OB_SUCCESS, arr_var2->hash(hash_val2)); cmp_ret = 0; ASSERT_EQ(OB_SUCCESS, arr_var1->compare(*arr_var2, cmp_ret)); ASSERT_EQ(1, cmp_ret); - + EXPECT_FALSE((*arr_var1) == (*arr_var2)); + ASSERT_NE(hash_val1, hash_val2); + std::cout << "arr_hash1: " << hash_val1 << "; arr_hash2: " << hash_val2 << std::endl; } TEST_F(TestArrayMeta, varchar_array_construct) @@ -347,17 +364,27 @@ TEST_F(TestArrayMeta, varchar_array_construct) ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var2, dst_elem_type)); ASSERT_EQ(OB_SUCCESS, arr_var1->init()); ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + uint64_t hash_val1 = 0; + uint64_t hash_val2 = 0; + ASSERT_EQ(OB_SUCCESS, arr_var1->hash(hash_val1)); + ASSERT_EQ(OB_SUCCESS, arr_var2->hash(hash_val2)); int cmp_ret = 0; ASSERT_EQ(OB_SUCCESS, arr_var1->compare(*arr_var2, cmp_ret)); ASSERT_EQ(0, cmp_ret); + EXPECT_TRUE((*arr_var1) == (*arr_var2)); + ASSERT_EQ(hash_val1, hash_val2); + std::cout << "arr_hash1: " << hash_val1 << "; arr_hash2: " << hash_val2 << std::endl; ObString arr2_text("[\"hi\", \"hello\"]"); ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + ASSERT_EQ(OB_SUCCESS, arr_var2->hash(hash_val2)); cmp_ret = 0; ASSERT_EQ(OB_SUCCESS, arr_var1->compare(*arr_var2, cmp_ret)); ASSERT_EQ(-1, cmp_ret); - + EXPECT_FALSE((*arr_var1) == (*arr_var2)); + ASSERT_NE(hash_val1, hash_val2); + std::cout << "arr_hash1: " << hash_val1 << "; arr_hash2: " << hash_val2 << std::endl; } TEST_F(TestArrayMeta, array_nested_compare) @@ -378,17 +405,28 @@ TEST_F(TestArrayMeta, array_nested_compare) ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var2, arr_type1->element_type_)); ASSERT_EQ(OB_SUCCESS, arr_var1->init()); ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + uint64_t hash_val1 = 0; + uint64_t hash_val2 = 0; + ASSERT_EQ(OB_SUCCESS, arr_var1->hash(hash_val1)); + ASSERT_EQ(OB_SUCCESS, arr_var2->hash(hash_val2)); int cmp_ret = 0; ASSERT_EQ(OB_SUCCESS, arr_var1->compare(*arr_var2, cmp_ret)); ASSERT_EQ(0, cmp_ret); + EXPECT_TRUE((*arr_var1) == (*arr_var2)); + ASSERT_EQ(hash_val1, hash_val2); + std::cout << "arr_hash1: " << hash_val1 << "; arr_hash2: " << hash_val2 << std::endl; ObString arr2_text("[[3.14159, 95.27, null, null], [8.878, 912.33], [333, 12.134, null]]"); arr_var2->clear(); ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, arr_type1->element_type_)); ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + ASSERT_EQ(OB_SUCCESS, arr_var2->hash(hash_val2)); cmp_ret = 0; ASSERT_EQ(OB_SUCCESS, arr_var1->compare(*arr_var2, cmp_ret)); ASSERT_EQ(-1, cmp_ret); + EXPECT_FALSE((*arr_var1) == (*arr_var2)); + ASSERT_NE(hash_val1, hash_val2); + std::cout << "arr_hash1: " << hash_val1 << "; arr_hash2: " << hash_val2 << std::endl; } TEST_F(TestArrayMeta, array_contains) @@ -473,6 +511,457 @@ TEST_F(TestArrayMeta, array_nested_contains) ASSERT_EQ(bret, true); } +TEST_F(TestArrayMeta, array_contains_all) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(FLOAT)"), "ARRAY(FLOAT)"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_var2 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var2)); + // construct array from string [3.14, 1.414, 2.718] + ObString arr1_text("[3.14, 1.414, 2.718, null]"); + ObString arr2_text("[1.414, 2.718]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bool bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->contains_all(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr3_text("[1.414, null]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr3_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->contains_all(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr4_text("[1.414, 88]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr4_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->contains_all(*arr_var2, bret)); + ASSERT_EQ(bret, false); + +} + +TEST_F(TestArrayMeta, varchar_array_contains_all) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(VARCHAR(256))"), "ARRAY(VARCHAR(256))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_var2 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var2)); + // construct array from string [3.14, 1.414, 2.718] + ObString arr1_text("[\"hello\", \"hi\", \"what\", \"is\", null]"); + ObString arr2_text("[\"is\", \"hi\"]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bool bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->contains_all(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr3_text("[null, \"hi\"]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr3_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->contains_all(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr4_text("[\"is\", \"what is\"]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr4_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->contains_all(*arr_var2, bret)); + ASSERT_EQ(bret, false); +} + +TEST_F(TestArrayMeta, array_nested_contains_all) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(ARRAY(DOUBLE))"), "ARRAY(ARRAY(DOUBLE))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_var2 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var2)); + // construct array from string [3.14, 1.414, 2.718] + ObString arr1_text("[[3.14159, 95.27, null, null], [8.878, 912.33], [333, 12.134, null]]"); + ObString arr2_text("[[8.878, 912.33], [333, 12.134, null]]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bool bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->contains_all(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr3_text("[[8.878, 912.33], null]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr3_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->contains_all(*arr_var2, bret)); + ASSERT_EQ(bret, false); +} + +TEST_F(TestArrayMeta, array_overlaps) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(FLOAT)"), "ARRAY(FLOAT)"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_var2 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var2)); + // construct array from string [3.14, 1.414, 2.718] + ObString arr1_text("[3.14, 1.414, 2.718, null]"); + ObString arr2_text("[1.414, 2.718]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bool bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->overlaps(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr3_text("[512, null]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr3_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->overlaps(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr4_text("[5.31, 88]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr4_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->overlaps(*arr_var2, bret)); + ASSERT_EQ(bret, false); + +} + +TEST_F(TestArrayMeta, varchar_array_overlaps) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(VARCHAR(256))"), "ARRAY(VARCHAR(256))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_var2 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var2)); + // construct array from string [3.14, 1.414, 2.718] + ObString arr1_text("[\"hello\", \"hi\", \"what\", \"is\", null]"); + ObString arr2_text("[\"is\", \"hi\"]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bool bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->overlaps(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr3_text("[null, \"how\"]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr3_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->overlaps(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr4_text("[\"old\", \"what is\"]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr4_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->overlaps(*arr_var2, bret)); + ASSERT_EQ(bret, false); +} + +TEST_F(TestArrayMeta, array_nested_overlaps) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(ARRAY(DOUBLE))"), "ARRAY(ARRAY(DOUBLE))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_var2 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var2)); + // construct array from string [3.14, 1.414, 2.718] + ObString arr1_text("[[3.14159, 95.27, null, null], [8.878, 912.33], [333, 12.134, null]]"); + ObString arr2_text("[null, [333, 12.134, null]]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bool bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->overlaps(*arr_var2, bret)); + ASSERT_EQ(bret, true); + + arr_var2->clear(); + ObString arr3_text("[[333, 12.134], null]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr3_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + bret = false; + ASSERT_EQ(OB_SUCCESS, arr_var1->overlaps(*arr_var2, bret)); + ASSERT_EQ(bret, false); +} + +TEST_F(TestArrayMeta, array_fix_distinct) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(FLOAT)"), "ARRAY(FLOAT)"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ObString arr1_text("[3.14, 1.414, 2.718, null, 1.414, null, 3.14, 3.14]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ObIArrayType *arr_dist = nullptr; + ASSERT_EQ(OB_SUCCESS, arr_var1->distinct(allocator, arr_dist)); + + ObStringBuffer format_str(&allocator); + ASSERT_EQ(OB_SUCCESS, arr_dist->init()); + ASSERT_EQ(OB_SUCCESS, arr_dist->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1: " << format_str.ptr() << std::endl; +} + +TEST_F(TestArrayMeta, varchar_array_distinct) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(VARCHAR(256))"), "ARRAY(VARCHAR(256))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + // construct array from string ["hello", "world"] + ObString arr1_text("[\"hello\", \"hi\", null, \"hi\", \"Hi\", null, \"what\"]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ObIArrayType *arr_dist = nullptr; + ASSERT_EQ(OB_SUCCESS, arr_var1->distinct(allocator, arr_dist)); + + ObStringBuffer format_str(&allocator); + ASSERT_EQ(OB_SUCCESS, arr_dist->init()); + ASSERT_EQ(OB_SUCCESS, arr_dist->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1: " << format_str.ptr() << std::endl; +} + +TEST_F(TestArrayMeta, nested_array_distinct) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(ARRAY(DOUBLE))"), "ARRAY(ARRAY(DOUBLE))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_dist = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ObString arr1_text("[[3.14159, 95.27, null, null], [8.878, 912.33], [333, 12.134, null], [8.878, 912.33], [333, 12.134, null], [333, 12.134], [null]]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ASSERT_EQ(OB_SUCCESS, arr_var1->distinct(allocator, arr_dist)); + + ObStringBuffer format_str(&allocator); + ASSERT_EQ(OB_SUCCESS, arr_dist->init()); + ASSERT_EQ(OB_SUCCESS, arr_dist->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1: " << format_str.ptr() << std::endl; + +} + +TEST_F(TestArrayMeta, array_nested_hasset) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(ARRAY(DOUBLE))"), "ARRAY(ARRAY(DOUBLE))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_var2 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var2)); + ObString arr1_text("[[3.14159, 95.27, null, null], [8.878, 912.33], [333, 12.134, null]]"); + ObString arr2_text("[[3.14159, 95.27, null, null], [8.878, 910.33], [333, 12.134, null]]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + hash::ObHashSet nested_arrs; + ASSERT_EQ(OB_SUCCESS, nested_arrs.create(10)); + ASSERT_EQ(OB_SUCCESS, nested_arrs.set_refactored(*static_cast(arr_var1), 0)); + ASSERT_EQ(OB_HASH_EXIST, nested_arrs.set_refactored(*static_cast(arr_var2), 0)); + + arr_var2->clear(); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + ASSERT_EQ(OB_SUCCESS, nested_arrs.set_refactored(*static_cast(arr_var2), 0)); + ASSERT_EQ(2, nested_arrs.size()); + ObStringBuffer format_str(&allocator); + hash::ObHashSet::iterator iter = nested_arrs.begin(); + for (; iter != nested_arrs.end(); iter++) { + ObArrayNested &arr_item = iter->first; + ASSERT_EQ(OB_SUCCESS, arr_item.print(arr_type1->element_type_, format_str)); + std::cout << "arr_va3: " << format_str.ptr() << std::endl; + format_str.reset(); + } +} + +TEST_F(TestArrayMeta, array_fix_remove) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(FLOAT)"), "ARRAY(FLOAT)"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_res = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + // construct array from string [3.14, 1.414, 2.718] + ObString arr1_text("[3.14, 1.414, 2.718, null, 3.14]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + float val_remove = 3.14; + ASSERT_EQ(OB_SUCCESS, ObArrayUtil::clone_except(allocator, *arr_var1, &val_remove, false, arr_res)); + ObStringBuffer format_str(&allocator); + ASSERT_EQ(OB_SUCCESS, arr_res->init()); + ASSERT_EQ(OB_SUCCESS, arr_res->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1 remove 3.14: " << format_str.ptr() << std::endl; + + arr_res->clear(); + format_str.reset(); + ASSERT_EQ(OB_SUCCESS, ObArrayUtil::clone_except(allocator, *arr_var1, &val_remove, true, arr_res)); + ASSERT_EQ(OB_SUCCESS, arr_res->init()); + ASSERT_EQ(OB_SUCCESS, arr_res->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1 remove null: " << format_str.ptr() << std::endl; +} + +TEST_F(TestArrayMeta, varchar_array_remove) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(VARCHAR(256))"), "ARRAY(VARCHAR(256))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + // construct array from string ["hello", "world"] + ObString arr1_text("[\"hello\", \"hi\", null, \"hi\", \"Hi\", null, \"what\"]"); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + ObIArrayType *arr_res = nullptr; + ObString remove_text("hi"); + ASSERT_EQ(OB_SUCCESS, ObArrayUtil::clone_except(allocator, *arr_var1, &remove_text, false, arr_res)); + ObStringBuffer format_str(&allocator); + ASSERT_EQ(OB_SUCCESS, arr_res->init()); + ASSERT_EQ(OB_SUCCESS, arr_res->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1 remove hi: " << format_str.ptr() << std::endl; + + arr_res->clear(); + format_str.reset(); + ASSERT_EQ(OB_SUCCESS, ObArrayUtil::clone_except(allocator, *arr_var1, &remove_text, true, arr_res)); + ASSERT_EQ(OB_SUCCESS, arr_res->init()); + ASSERT_EQ(OB_SUCCESS, arr_res->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1 remove null: " << format_str.ptr() << std::endl; + +} + +TEST_F(TestArrayMeta, nested_array_remove) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObSqlCollectionInfo type1_info_parse(allocator); + ObString type1_name(strlen("ARRAY(ARRAY(DOUBLE))"), "ARRAY(ARRAY(DOUBLE))"); + type1_info_parse.set_name(type1_name); + ASSERT_EQ(OB_SUCCESS, type1_info_parse.parse_type_info()); + ObIArrayType *arr_var1 = nullptr; + ObIArrayType *arr_res = nullptr; + ObCollectionArrayType *arr_type1 = static_cast(type1_info_parse.collection_meta_); + ObCollectionBasicType *dst_elem_type = static_cast(arr_type1->element_type_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type1, arr_var1)); + ObString arr1_text("[[3.14159, 95.27, null, null], [8.878, 912.33], [333, 12.134, null], null, [8.878, 912.33], [333, 12.134, null], [333, 12.134], [null]]"); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr1_text, arr_var1, dst_elem_type)); + ASSERT_EQ(OB_SUCCESS, arr_var1->init()); + + ObSqlCollectionInfo type2_info_parse(allocator); + ObString type2_name(strlen("ARRAY(DOUBLE)"), "ARRAY(DOUBLE)"); + type2_info_parse.set_name(type2_name); + ASSERT_EQ(OB_SUCCESS, type2_info_parse.parse_type_info()); + ObIArrayType *arr_var2 = nullptr; + ObCollectionArrayType *arr_type2 = static_cast(type2_info_parse.collection_meta_); + ASSERT_EQ(OB_SUCCESS, ObArrayTypeObjFactory::construct(allocator, *arr_type2, arr_var2)); + ObString arr2_text("[8.878, 912.33]"); + ObCollectionBasicType *dst_elem_type2 = static_cast(arr_type2->element_type_); + ASSERT_EQ(OB_SUCCESS, sql::ObArrayCastUtils::string_cast(allocator, arr2_text, arr_var2, dst_elem_type2)); + ASSERT_EQ(OB_SUCCESS, arr_var2->init()); + + ASSERT_EQ(OB_SUCCESS, ObArrayUtil::clone_except(allocator, *arr_var1, arr_var2, false, arr_res)); + ObStringBuffer format_str(&allocator); + ASSERT_EQ(OB_SUCCESS, arr_res->init()); + ASSERT_EQ(OB_SUCCESS, arr_res->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1: " << format_str.ptr() << std::endl; + + arr_res->clear(); + format_str.reset(); + ASSERT_EQ(OB_SUCCESS, ObArrayUtil::clone_except(allocator, *arr_var1, arr_var2, true, arr_res)); + ASSERT_EQ(OB_SUCCESS, arr_res->init()); + ASSERT_EQ(OB_SUCCESS, arr_res->print(arr_type1->element_type_, format_str)); + std::cout << "arr_va1 remove null: " << format_str.ptr() << std::endl; +} + } // namespace common } // namespace oceanbase