1196 lines
51 KiB
C++
1196 lines
51 KiB
C++
/**
|
|
* 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 ob_array_expr_utils.
|
|
*/
|
|
|
|
#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"
|
|
|
|
using namespace oceanbase::common;
|
|
namespace oceanbase
|
|
{
|
|
namespace sql
|
|
{
|
|
|
|
const char* ObArrayExprUtils::DEFAULT_CAST_TYPE_NAME = "ARRAY(FLOAT)";
|
|
const ObString ObArrayExprUtils::DEFAULT_CAST_TYPE_STR = ObString::make_string(DEFAULT_CAST_TYPE_NAME);
|
|
|
|
int ObArrayExprUtils::get_type_vector(
|
|
const ObExpr &expr,
|
|
ObEvalCtx &ctx,
|
|
ObIAllocator &allocator,
|
|
ObIArrayType *&result,
|
|
bool &is_null)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObDatum *datum = NULL;
|
|
if (OB_FAIL(expr.eval(ctx, datum))) {
|
|
LOG_WARN("eval failed", K(ret));
|
|
} else if (OB_UNLIKELY(datum->is_null())) {
|
|
is_null = true;
|
|
} else if (OB_FAIL(get_type_vector(expr, *datum, ctx, allocator, result))) {
|
|
LOG_WARN("failed to get vector", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// get vector or array(float)
|
|
int ObArrayExprUtils::get_type_vector(
|
|
const ObExpr &expr,
|
|
const ObDatum &datum,
|
|
ObEvalCtx &ctx,
|
|
ObIAllocator &allocator,
|
|
ObIArrayType *&result)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSubSchemaValue value;
|
|
uint16_t subschema_id = expr.obj_meta_.get_subschema_id();
|
|
if (!expr.obj_meta_.is_collection_sql_type()) {
|
|
ret = OB_NOT_SUPPORTED;
|
|
LOG_WARN("not support", K(ret), K(expr.obj_meta_));
|
|
} else 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 {
|
|
ObString blob_data = datum.get_string();
|
|
const ObSqlCollectionInfo *coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(value.value_);
|
|
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(coll_info->collection_meta_);
|
|
if (OB_FAIL(ObTextStringHelper::read_real_string_data(&allocator,
|
|
ObLongTextType,
|
|
CS_TYPE_BINARY,
|
|
true,
|
|
blob_data))) {
|
|
LOG_WARN("fail to get real data.", K(ret), K(blob_data));
|
|
} else if (OB_FAIL(ObArrayTypeObjFactory::construct(allocator, *arr_type, result, true))) {
|
|
LOG_WARN("construct array obj failed", K(ret), K(*coll_info));
|
|
} else if (OB_FAIL(result->init(blob_data))) {
|
|
LOG_WARN("failed to init array", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::vector_datum_add(ObDatum &res, const ObDatum &data, ObIAllocator &allocator, bool negative)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObString blob_res = res.get_string();
|
|
ObString blob_data = data.get_string();
|
|
if (OB_FAIL(ObTextStringHelper::read_real_string_data(&allocator,
|
|
ObLongTextType,
|
|
CS_TYPE_BINARY,
|
|
true,
|
|
blob_data))) {
|
|
LOG_WARN("fail to get real data.", K(ret), K(blob_data));
|
|
} else if (OB_FAIL(ObTextStringHelper::read_real_string_data(&allocator,
|
|
ObLongTextType,
|
|
CS_TYPE_BINARY,
|
|
true,
|
|
blob_res))) {
|
|
LOG_WARN("fail to get real data.", K(ret), K(blob_data));
|
|
} else {
|
|
int64_t length = blob_data.length() / sizeof(float);
|
|
float *float_data = reinterpret_cast<float *>(blob_data.ptr());
|
|
float *float_res = reinterpret_cast<float *>(blob_res.ptr());
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < length; ++i) {
|
|
negative ? float_res[i] -= float_data[i] : float_res[i] += float_data[i];
|
|
if (isinff(float_res[i]) != 0) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
SQL_LOG(WARN, "value overflow", K(ret), K(i), K(float_data[i]), K(float_res[i]));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// cast any array and varchar to array(float)
|
|
int ObArrayExprUtils::calc_cast_type(
|
|
ObExprResType &type,
|
|
common::ObExprTypeCtx &type_ctx,
|
|
const bool only_vector)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo *session = const_cast<ObSQLSessionInfo *>(type_ctx.get_session());
|
|
ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx();
|
|
uint16_t dst_subschema_id = 0;
|
|
bool need_cast = false;
|
|
if (!type.is_collection_sql_type() && !type.is_string_type() && !type.is_null()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret), K(type));
|
|
} else if (type.is_collection_sql_type()) {
|
|
ObSubSchemaValue value;
|
|
uint16_t src_subschema_id = type.get_subschema_id();
|
|
if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(src_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 = NULL;
|
|
coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(value.value_);
|
|
if (coll_info->collection_meta_->type_id_ == ObNestedType::OB_ARRAY_TYPE) {
|
|
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(coll_info->collection_meta_);
|
|
if (only_vector) {
|
|
ret = OB_ERR_INVALID_TYPE_FOR_OP;
|
|
LOG_WARN("only support vector type", K(ret));
|
|
} else if (arr_type->element_type_->type_id_ != ObNestedType::OB_BASIC_TYPE) {
|
|
ret = OB_NOT_SUPPORTED;
|
|
LOG_WARN("nested array is not support", K(ret));
|
|
} else {
|
|
ObCollectionBasicType *elem_type = static_cast<ObCollectionBasicType *>(arr_type->element_type_);
|
|
if (ObFloatType != elem_type->basic_meta_.get_obj_type()) {
|
|
need_cast = true;
|
|
}
|
|
}
|
|
}
|
|
// vector and array(float) don't need to cast
|
|
if (OB_SUCC(ret) && !need_cast) {
|
|
type.set_calc_type(ObCollectionSQLType);
|
|
type.set_calc_subschema_id(src_subschema_id); // avoid cast by set the same subschema_id
|
|
}
|
|
}
|
|
} else if (type.is_string_type()) {
|
|
need_cast = true;
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (need_cast) {
|
|
if (OB_FAIL(exec_ctx->get_subschema_id_by_type_string(DEFAULT_CAST_TYPE_STR, dst_subschema_id))) {
|
|
LOG_WARN("failed to get subschema id by type string", K(ret), K(DEFAULT_CAST_TYPE_STR));
|
|
} else {
|
|
type.set_calc_type(ObCollectionSQLType);
|
|
type.set_calc_subschema_id(dst_subschema_id);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::collect_vector_cast_info(ObExprResType &type, ObExecContext &exec_ctx, ObVectorCastInfo &info)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (type.is_collection_sql_type()) {
|
|
ObSubSchemaValue value;
|
|
info.subschema_id_ = type.get_subschema_id();
|
|
if (OB_FAIL(exec_ctx.get_sqludt_meta_by_subschema_id(info.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 = NULL;
|
|
coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(value.value_);
|
|
if (coll_info->collection_meta_->type_id_ == ObNestedType::OB_VECTOR_TYPE) {
|
|
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(coll_info->collection_meta_);
|
|
info.is_vector_ = true;
|
|
info.dim_cnt_ = arr_type->dim_cnt_;
|
|
} else if (coll_info->collection_meta_->type_id_ == ObNestedType::OB_ARRAY_TYPE) {
|
|
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(coll_info->collection_meta_);
|
|
ObCollectionBasicType *elem_type = static_cast<ObCollectionBasicType *>(arr_type->element_type_);
|
|
if (ObFloatType != elem_type->basic_meta_.get_obj_type()) {
|
|
info.need_cast_ = true;
|
|
}
|
|
}
|
|
}
|
|
} else if (type.is_string_type()) {
|
|
info.need_cast_ = true;
|
|
} else if (!type.is_null()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret), K(type));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::calc_cast_type2(
|
|
ObExprResType &type1,
|
|
ObExprResType &type2,
|
|
common::ObExprTypeCtx &type_ctx,
|
|
uint16_t &res_subschema_id,
|
|
const bool only_vector)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
res_subschema_id = UINT16_MAX;
|
|
ObSQLSessionInfo *session = const_cast<ObSQLSessionInfo *>(type_ctx.get_session());
|
|
ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx();
|
|
ObString default_dst_type("ARRAY(FLOAT)");
|
|
uint16_t default_dst_subschema_id = UINT16_MAX;
|
|
|
|
ObVectorCastInfo info1;
|
|
ObVectorCastInfo info2;
|
|
if (OB_ISNULL(exec_ctx)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("exec ctx is null", K(ret));
|
|
} else if (OB_FAIL(collect_vector_cast_info(type1, *exec_ctx, info1))) {
|
|
LOG_WARN("failed to collect vector cast info", K(ret));
|
|
} else if (OB_FAIL(collect_vector_cast_info(type2, *exec_ctx, info2))) {
|
|
LOG_WARN("failed to collect vector cast info", K(ret));
|
|
} else if (info1.is_vector_ && info2.is_vector_) {
|
|
if (info1.dim_cnt_ != info2.dim_cnt_) {
|
|
ret = OB_ERR_INVALID_VECTOR_DIM;
|
|
LOG_WARN("check array validty failed", K(ret), K(info1.dim_cnt_), K(info2.dim_cnt_));
|
|
}
|
|
} else if (info1.is_vector_) {
|
|
if (!type2.is_null()) {
|
|
type2.set_calc_type(ObCollectionSQLType);
|
|
type2.set_calc_subschema_id(info1.subschema_id_);
|
|
info2.need_cast_ = true;
|
|
}
|
|
res_subschema_id = info1.subschema_id_;
|
|
} else if (info2.is_vector_) {
|
|
if (!type1.is_null()) {
|
|
type1.set_calc_type(ObCollectionSQLType);
|
|
type1.set_calc_subschema_id(info2.subschema_id_);
|
|
info1.need_cast_ = true;
|
|
}
|
|
res_subschema_id = info2.subschema_id_;
|
|
} else if (only_vector) {
|
|
ret = OB_NOT_SUPPORTED;
|
|
LOG_WARN("no vector in the expr", K(ret));
|
|
} else if (info1.need_cast_ || info2.need_cast_) {
|
|
if (OB_FAIL(exec_ctx->get_subschema_id_by_type_string(default_dst_type, default_dst_subschema_id))) {
|
|
LOG_WARN("failed to get subschema id by type string", K(ret), K(default_dst_type));
|
|
} else {
|
|
if (info1.need_cast_) {
|
|
type1.set_calc_type(ObCollectionSQLType);
|
|
type1.set_calc_subschema_id(default_dst_subschema_id);
|
|
}
|
|
if (info2.need_cast_) {
|
|
type2.set_calc_type(ObCollectionSQLType);
|
|
type2.set_calc_subschema_id(default_dst_subschema_id);
|
|
}
|
|
res_subschema_id = default_dst_subschema_id;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (type1.is_collection_sql_type() && !info1.need_cast_) {
|
|
type1.set_calc_type(ObCollectionSQLType);
|
|
type1.set_calc_subschema_id(type1.get_subschema_id()); // avoid cast by set the same subschema_id
|
|
res_subschema_id = type1.get_subschema_id();
|
|
}
|
|
if (type2.is_collection_sql_type() && !info2.need_cast_) {
|
|
type2.set_calc_type(ObCollectionSQLType);
|
|
type2.set_calc_subschema_id(type2.get_subschema_id()); // avoid cast by set the same subschema_id
|
|
res_subschema_id = type2.get_subschema_id();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::set_array_res(ObIArrayType *arr_obj, const int32_t res_size, const ObExpr &expr, ObEvalCtx &ctx, ObString &res, const char *data)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char *res_buf = nullptr;
|
|
int64_t res_buf_len = 0;
|
|
ObDatum tmp_res;
|
|
ObTextStringDatumResult str_result(expr.datum_meta_.type_, &expr, &ctx, &tmp_res);
|
|
if (OB_FAIL(str_result.init(res_size, nullptr))) {
|
|
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 (nullptr != data) {
|
|
MEMCPY(res_buf, data, res_size);
|
|
} else if (nullptr != arr_obj && 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));
|
|
}
|
|
if (FAILEDx(str_result.lseek(res_size, 0))) {
|
|
LOG_WARN("failed to lseek res.", K(ret), K(str_result), K(res_size));
|
|
} else {
|
|
str_result.get_result_buffer(res);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::set_array_res(ObIArrayType *arr_obj, const int32_t res_size, ObIAllocator &allocator, ObString &res, const char *data)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool has_lob_header = !IS_CLUSTER_VERSION_BEFORE_4_1_0_0;
|
|
char *res_buf = nullptr;
|
|
int64_t res_buf_len = 0;
|
|
ObDatum tmp_res;
|
|
ObTextStringDatumResult str_result(ObCollectionSQLType, has_lob_header, &tmp_res);
|
|
if (OB_FAIL(str_result.init(res_size, &allocator))) {
|
|
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 (nullptr != data) {
|
|
MEMCPY(res_buf, data, res_size);
|
|
} else if (nullptr != arr_obj && 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));
|
|
}
|
|
if (FAILEDx(str_result.lseek(res_size, 0))) {
|
|
LOG_WARN("failed to lseek res.", K(ret), K(str_result), K(res_size));
|
|
} else {
|
|
str_result.get_result_buffer(res);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template <typename ResVec>
|
|
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<ResVec> 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<ObUniformFormat<true>>(
|
|
ObIArrayType* arr_obj, const ObExpr& expr, ObEvalCtx& ctx,
|
|
ObUniformFormat<true>* res_vec, int64_t batch_idx);
|
|
|
|
int ObArrayExprUtils::set_array_obj_res(ObIArrayType *arr_obj, ObObjCastParams *params, ObObj *obj)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool has_lob_header = !IS_CLUSTER_VERSION_BEFORE_4_1_0_0;
|
|
int32_t res_size = arr_obj->get_raw_binary_len();
|
|
char *res_buf = nullptr;
|
|
int64_t res_buf_len = 0;
|
|
sql::ObTextStringObObjResult text_result(ObCollectionSQLType, params, obj, has_lob_header);
|
|
if (OB_FAIL(text_result.init(res_size, params->allocator_v2_))) {
|
|
LOG_WARN("init lob result failed");
|
|
} else if (OB_FAIL(text_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(text_result.lseek(res_size, 0))) {
|
|
LOG_WARN("failed to lseek res.", K(ret), K(text_result), K(res_size));
|
|
} else {
|
|
text_result.set_result();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::check_array_type_compatibility(ObExecContext *exec_ctx, uint16_t l_subid, uint16_t r_subid, bool &is_compatiable)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSubSchemaValue l_meta;
|
|
ObSubSchemaValue r_meta;
|
|
if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(l_subid, l_meta))) {
|
|
LOG_WARN("failed to get elem meta.", K(ret), K(l_subid));
|
|
} else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(r_subid, r_meta))) {
|
|
LOG_WARN("failed to get elem meta.", K(ret), K(l_subid));
|
|
} else if (l_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE
|
|
|| r_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) {
|
|
ret = OB_ERR_INVALID_TYPE_FOR_OP;
|
|
LOG_WARN("invalid subschema type", K(ret), K(l_meta.type_), K(r_meta.type_));
|
|
} else if (OB_ISNULL(l_meta.value_) || OB_ISNULL(r_meta.value_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("type info is null", K(ret), K(l_meta.value_), K(r_meta.value_));
|
|
} else {
|
|
is_compatiable =
|
|
reinterpret_cast<const ObSqlCollectionInfo *>(l_meta.value_)->has_same_super_type(*reinterpret_cast<const ObSqlCollectionInfo *>(r_meta.value_));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::get_array_element_type(ObExecContext *exec_ctx, uint16_t subid, ObDataType &elem_type,
|
|
uint32_t &depth, bool &is_vec)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSubSchemaValue meta;
|
|
if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(subid, meta))) {
|
|
LOG_WARN("failed to get elem meta.", K(ret), K(subid));
|
|
} else if (meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) {
|
|
ret = OB_ERR_INVALID_TYPE_FOR_OP;
|
|
LOG_WARN("invalid subschema type", K(ret), K(meta.type_));
|
|
} else if (OB_ISNULL(meta.value_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("type info is null", K(ret));
|
|
} else {
|
|
const ObSqlCollectionInfo * coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(meta.value_);
|
|
elem_type = coll_info->get_basic_meta(depth);
|
|
is_vec = coll_info->collection_meta_->type_id_ == ObNestedType::OB_VECTOR_TYPE;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::get_array_element_type(ObExecContext *exec_ctx, uint16_t subid, ObObjType &obj_type,
|
|
uint32_t &depth, bool &is_vec)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObDataType elem_type;
|
|
if (OB_FAIL(get_array_element_type(exec_ctx, subid, elem_type, depth, is_vec))) {
|
|
LOG_WARN("failed to get elem meta.", K(ret), K(subid));
|
|
} else {
|
|
obj_type = elem_type.get_obj_type();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::deduce_array_element_type(ObExecContext *exec_ctx, ObExprResType* types_stack, int64_t param_num, ObDataType &elem_type)
|
|
{
|
|
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;
|
|
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())) {
|
|
// check subschmea id
|
|
if (last_subschema_id == ObInvalidSqlType) {
|
|
coll_calc_type = types_stack[i];
|
|
last_subschema_id = types_stack[i].get_subschema_id();
|
|
elem_type.meta_.set_collection(last_subschema_id);
|
|
} else if (last_subschema_id != types_stack[i].get_subschema_id()) {
|
|
ObExprResType tmp_calc_type;
|
|
if (OB_FAIL(ObExprResultTypeUtil::get_array_calc_type(exec_ctx, coll_calc_type, types_stack[i], tmp_calc_type))) {
|
|
LOG_WARN("failed to check array compatibilty", K(ret));
|
|
} else {
|
|
last_subschema_id = tmp_calc_type.get_subschema_id();
|
|
coll_calc_type = tmp_calc_type;
|
|
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() && !types_stack[i - 1].is_null()) { // null is legal input type
|
|
is_all_same_type = false;
|
|
if (!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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::deduce_nested_array_subschema_id(ObExecContext *exec_ctx, ObDataType &elem_type, uint16_t &subschema_id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
uint16_t elem_subid = elem_type.meta_.get_subschema_id();
|
|
ObSubSchemaValue elem_meta;
|
|
if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(elem_subid, elem_meta))) {
|
|
LOG_WARN("failed to get elem meta.", K(ret), K(elem_subid));
|
|
} else if (elem_meta.type_ != ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) {
|
|
ret = OB_ERR_INVALID_TYPE_FOR_OP;
|
|
LOG_WARN("invalid subschema type", K(ret), K(elem_meta.type_));
|
|
} else {
|
|
const int MAX_LEN = 256;
|
|
int64_t pos = 0;
|
|
char tmp[MAX_LEN] = {0};
|
|
ObString type_info;
|
|
const ObSqlCollectionInfo *coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(elem_meta.value_);
|
|
if (OB_FAIL(databuff_printf(tmp, MAX_LEN, pos, "ARRAY("))) {
|
|
LOG_WARN("failed to convert len to string", K(ret));
|
|
} else if (FALSE_IT(STRNCPY(tmp + pos, coll_info->name_def_, coll_info->name_len_))) {
|
|
} else if (FALSE_IT(pos += coll_info->name_len_)) {
|
|
} else if (OB_FAIL(databuff_printf(tmp, MAX_LEN, pos, ")"))) {
|
|
LOG_WARN("failed to add ) to string", K(ret));
|
|
} else if (FALSE_IT(type_info.assign_ptr(tmp, static_cast<int32_t>(pos)))) {
|
|
} else if (OB_FAIL(exec_ctx->get_subschema_id_by_type_string(type_info, subschema_id))) {
|
|
LOG_WARN("failed get subschema id", K(ret), K(type_info));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObVectorVectorArithFunc::operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const ObExpr &expr, ObEvalCtx &ctx, ArithType type) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObExpr &left_expr = *expr.args_[0];
|
|
const ObExpr &right_expr = *expr.args_[1];
|
|
ObIArrayType *arr_l = NULL;
|
|
ObIArrayType *arr_r = NULL;
|
|
ObIArrayType *arr_res = NULL;
|
|
ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx);
|
|
common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator();
|
|
ObSubSchemaValue value;
|
|
uint16_t subschema_id = expr.obj_meta_.get_subschema_id();
|
|
const ObSqlCollectionInfo *coll_info = NULL;
|
|
ObCollectionArrayType *arr_type = NULL;
|
|
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 (OB_FAIL(ObArrayExprUtils::get_type_vector(left_expr, l, ctx, tmp_allocator, arr_l))) {
|
|
LOG_WARN("failed to get vector", K(ret));
|
|
} else if (OB_FAIL(ObArrayExprUtils::get_type_vector(right_expr, r, ctx, tmp_allocator, arr_r))) {
|
|
LOG_WARN("failed to get vector", K(ret));
|
|
} else if (OB_ISNULL(arr_l) || OB_ISNULL(arr_r)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected nullptr", K(ret), K(arr_l), K(arr_r));
|
|
} else if (OB_UNLIKELY(arr_l->size() != arr_r->size())) {
|
|
ret = OB_ERR_INVALID_VECTOR_DIM;
|
|
LOG_WARN("check array validty failed", K(ret), K(arr_l->size()), K(arr_r->size()));
|
|
} else if (arr_l->contain_null() || arr_r->contain_null()) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("array with null can't add", K(ret));
|
|
} else if (FALSE_IT(coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(value.value_))) {
|
|
} else if (OB_ISNULL(coll_info)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("collect info is null", K(ret), K(subschema_id));
|
|
} else if (OB_ISNULL(arr_type = static_cast<ObCollectionArrayType *>(coll_info->collection_meta_))) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("array type is null", K(ret), K(subschema_id));
|
|
} else if (OB_FAIL(ObArrayTypeObjFactory::construct(tmp_allocator, *arr_type, arr_res))) {
|
|
LOG_WARN("construct array obj failed", K(ret), K(subschema_id), K(coll_info));
|
|
} else {
|
|
const float *data_l = reinterpret_cast<const float*>(arr_l->get_data());
|
|
const float *data_r = reinterpret_cast<const float*>(arr_r->get_data());
|
|
const uint32_t size = arr_l->size();
|
|
ObArrayFixedSize<float> *float_array = static_cast<ObArrayFixedSize<float> *>(arr_res);
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < size; ++i) {
|
|
const float float_res = type == ADD ? data_l[i] + data_r[i] :
|
|
type == MUL ? data_l[i] * data_r[i] :
|
|
data_l[i] - data_r[i];
|
|
if (isinff(float_res) != 0) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_WARN("value overflow", K(ret), K(i), K(data_l[i]), K(data_r[i]));
|
|
} else if (OB_FAIL(float_array->push_back(float_res))) {
|
|
LOG_WARN("failed to push back value", K(ret), K(float_res));
|
|
}
|
|
}
|
|
ObString res_str;
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_res,
|
|
arr_res->get_raw_binary_len(),
|
|
ctx.get_expr_res_alloc(),
|
|
res_str))) {
|
|
LOG_WARN("get array binary string failed", K(ret), K(*coll_info));
|
|
// FIXME huhaosheng.hhs: maybe set batch_idx_ before in order to use frame res_buf
|
|
// } else if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_res, expr, ctx, res_str))) {
|
|
|
|
// LOG_WARN("get array binary string failed", K(ret), K(*coll_info));
|
|
} else {
|
|
res.set_string(res_str);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::dispatch_array_attrs(ObEvalCtx &ctx, ObIArrayType *arr_obj, ObExpr **attrs, uint32_t attr_count, const int64_t row_idx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObArrayAttr arr_attrs[attr_count];
|
|
uint32_t attr_idx = 0;
|
|
if (OB_FAIL(arr_obj->flatten(arr_attrs, attr_count, attr_idx))) {
|
|
LOG_WARN("array flatten failed", K(ret));
|
|
} else {
|
|
for (uint32_t i = 0; i < attr_count; i++) {
|
|
ObIVector *vec = attrs[i]->get_vector(ctx);
|
|
if (i == 0) {
|
|
vec->set_int(row_idx, arr_obj->size());
|
|
} else if (arr_attrs[i - 1].ptr_ == NULL && arr_attrs[i - 1].length_ == 0) {
|
|
vec->set_payload_shallow(row_idx, NULL, 0); // get ride of random values
|
|
vec->set_null(row_idx);
|
|
} else {
|
|
const char *payload = arr_attrs[i - 1].ptr_;
|
|
uint32_t len = arr_attrs[i - 1].length_;
|
|
vec->set_payload_shallow(row_idx, payload, len);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::dispatch_array_attrs(ObEvalCtx &ctx, ObExpr &expr, ObString &array_data, const int64_t row_idx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx);
|
|
// to fix : outrow lob can't use tmp allocator
|
|
common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator();
|
|
ObSubSchemaValue value;
|
|
uint16_t subschema_id = expr.obj_meta_.get_subschema_id();
|
|
const ObSqlCollectionInfo *coll_info = NULL;
|
|
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 {
|
|
ObLobCommon *lob_comm = (ObLobCommon*)(array_data.ptr());
|
|
if (lob_comm->is_valid()
|
|
&& OB_FAIL(ObTextStringHelper::read_real_string_data(&tmp_allocator,
|
|
ObLongTextType,
|
|
CS_TYPE_BINARY,
|
|
true,
|
|
array_data))) {
|
|
LOG_WARN("fail to get real data.", K(ret), K(array_data));
|
|
} else {
|
|
ObIArrayType *arr_obj = NULL;
|
|
coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(value.value_);
|
|
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(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, true))) {
|
|
LOG_WARN("construct array obj failed", K(ret), K(subschema_id), K(coll_info));
|
|
} else if (OB_FAIL(arr_obj->init(array_data))) {
|
|
LOG_WARN("init array obj failed", K(ret), K(subschema_id), K(coll_info));
|
|
} else if (OB_FAIL(dispatch_array_attrs(ctx, arr_obj, expr.attrs_, expr.attrs_cnt_, row_idx))) {
|
|
LOG_WARN("dispatch array attributes failed", K(ret), K(subschema_id), K(coll_info));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObVectorFloatArithFunc::operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, const ObExpr &expr, ObEvalCtx &ctx, ArithType type) const
|
|
{
|
|
UNUSED(type);
|
|
int ret = OB_SUCCESS;
|
|
const ObExpr &left_expr = *expr.args_[0];
|
|
const ObExpr &right_expr = *expr.args_[1];
|
|
ObIArrayType *arr_l = NULL;
|
|
float data_r = r.get_float();
|
|
ObIArrayType *arr_res = NULL;
|
|
ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx);
|
|
common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator();
|
|
ObSubSchemaValue value;
|
|
uint16_t subschema_id = expr.obj_meta_.get_subschema_id();
|
|
const ObSqlCollectionInfo *coll_info = NULL;
|
|
ObCollectionArrayType *arr_type = NULL;
|
|
if (0 == data_r) {
|
|
res.set_null();
|
|
} else 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 (OB_FAIL(ObArrayExprUtils::get_type_vector(left_expr, l, ctx, tmp_allocator, arr_l))) {
|
|
LOG_WARN("failed to get vector", K(ret));
|
|
} else if (OB_ISNULL(arr_l)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected nullptr", K(ret), K(arr_l));
|
|
} else if (arr_l->contain_null()) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("array with null can't add", K(ret));
|
|
} else if (FALSE_IT(coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(value.value_))) {
|
|
} else if (OB_ISNULL(coll_info)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("collect info is null", K(ret), K(subschema_id));
|
|
} else if (OB_ISNULL(arr_type = static_cast<ObCollectionArrayType *>(coll_info->collection_meta_))) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("array type is null", K(ret), K(subschema_id));
|
|
} else if (OB_FAIL(ObArrayTypeObjFactory::construct(tmp_allocator, *arr_type, arr_res))) {
|
|
LOG_WARN("construct array obj failed", K(ret), K(subschema_id), K(coll_info));
|
|
} else {
|
|
const float *data_l = reinterpret_cast<const float*>(arr_l->get_data());
|
|
const uint32_t size = arr_l->size();
|
|
ObVectorData *float_array = static_cast<ObVectorData *>(arr_res);
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < size; ++i) {
|
|
const float float_res = data_l[i] / data_r; // only support div now
|
|
if (isinff(float_res) != 0) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_WARN("value overflow", K(ret), K(i), K(data_l[i]), K(data_r));
|
|
} else if (OB_FAIL(float_array->push_back(float_res))) {
|
|
LOG_WARN("failed to push back value", K(ret), K(float_res));
|
|
}
|
|
}
|
|
ObString res_str;
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(ObArrayExprUtils::set_array_res(arr_res,
|
|
arr_res->get_raw_binary_len(),
|
|
ctx.get_expr_res_alloc(),
|
|
res_str))) {
|
|
LOG_WARN("get array binary string failed", K(ret), K(*coll_info));
|
|
} else {
|
|
res.set_string(res_str);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::batch_dispatch_array_attrs(ObEvalCtx &ctx, ObExpr &expr, int64_t begin, int64_t batch_size, const uint16_t *selector)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObIVector *vec = expr.get_vector(ctx);
|
|
ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx);
|
|
ObIArrayType *arr_obj = NULL;
|
|
// to fix : outrow lob can't use tmp allocator
|
|
common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator();
|
|
if (OB_FAIL(construct_array_obj(tmp_allocator, ctx, expr.obj_meta_.get_subschema_id(), arr_obj))) {
|
|
LOG_WARN("fail to construct array obj.", K(ret));
|
|
} else {
|
|
for (int64_t row_idx = begin; row_idx < begin + batch_size && OB_SUCC(ret); row_idx++) {
|
|
int64_t idx = selector != NULL ? selector[row_idx] : row_idx;
|
|
ObString raw_data = vec->get_string(idx);
|
|
uint32_t attr_idx = 0;
|
|
if (vec->is_null(idx)) {
|
|
for (uint32_t i = 0; i < expr.attrs_cnt_; i++) {
|
|
ObIVector *attr_vec = expr.attrs_[i]->get_vector(ctx);
|
|
attr_vec->set_null(row_idx);
|
|
}
|
|
} else if (OB_FAIL(ObTextStringHelper::read_real_string_data(&tmp_allocator,
|
|
ObLongTextType,
|
|
CS_TYPE_BINARY,
|
|
true,
|
|
raw_data))) {
|
|
LOG_WARN("fail to get real data.", K(ret), K(raw_data));
|
|
} else if (OB_FAIL(arr_obj->init(raw_data))) {
|
|
LOG_WARN("init array obj failed", K(ret));
|
|
} else if (OB_FAIL(dispatch_array_attrs_rows(ctx, arr_obj, idx, expr.attrs_, expr.attrs_cnt_))) {
|
|
LOG_WARN("failed to dispatch array attrs rows", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::assemble_array_attrs(ObEvalCtx &ctx, const ObExpr &expr, int64_t row_idx, ObIArrayType *arr_obj)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObDatum attr_val[expr.attrs_cnt_];
|
|
for (uint32_t i = 0; i < expr.attrs_cnt_; ++i) {
|
|
ObIVector *vec = expr.attrs_[i]->get_vector(ctx);
|
|
const char *payload = NULL;
|
|
ObLength payload_len = 0;
|
|
vec->get_payload(row_idx, payload, payload_len);
|
|
attr_val[i].ptr_ = payload;
|
|
attr_val[i].pack_ = payload_len;
|
|
}
|
|
if (OB_FAIL(arr_obj->init(attr_val, expr.attrs_cnt_))) {
|
|
LOG_WARN("init array attrs failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::transform_array_to_uniform(ObEvalCtx &ctx, const ObExpr &expr, const int64_t batch_size, const ObBitVector *skip)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSubSchemaValue value;
|
|
uint16_t subschema_id = expr.obj_meta_.get_subschema_id();
|
|
const ObBitVector *nulls = NULL;
|
|
if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, value))) {
|
|
LOG_WARN("failed to get subschema", K(ret));
|
|
} else if (expr.get_vector(ctx)->get_format() == VEC_DISCRETE
|
|
&& FALSE_IT(nulls = static_cast<ObDiscreteBase *>(expr.get_vector(ctx))->get_nulls()) ) {
|
|
} else if (expr.get_vector(ctx)->get_format() == VEC_CONTINUOUS
|
|
&& FALSE_IT(nulls = static_cast<ObContinuousBase *>(expr.get_vector(ctx))->get_nulls()) ) {
|
|
} else {
|
|
ObIArrayType *arr_obj = NULL;
|
|
ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx);
|
|
common::ObArenaAllocator &alloc = tmp_alloc_g.get_allocator();
|
|
const ObSqlCollectionInfo *coll_info = reinterpret_cast<const ObSqlCollectionInfo *>(value.value_);
|
|
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(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_ISNULL(nulls)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("failed to get nulls", K(ret), K(expr.get_vector(ctx)->get_format()));
|
|
} else if (OB_FAIL(ObArrayTypeObjFactory::construct(alloc, *arr_type, arr_obj, true))) {
|
|
LOG_WARN("construct array obj failed", K(ret), K(subschema_id), K(coll_info));
|
|
} else {
|
|
ret = expr.init_vector(ctx, VEC_UNIFORM, batch_size);
|
|
UniformFormat *root_vec = static_cast<UniformFormat *>(expr.get_vector(ctx));
|
|
for (int64_t row_idx = 0; OB_SUCC(ret) && row_idx < batch_size; ++row_idx) {
|
|
if (expr.attrs_cnt_ <= 0) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected attrs cnt", K(ret), K(expr.attrs_cnt_));
|
|
} else if (skip != nullptr && skip->at(row_idx)) {
|
|
// skip row
|
|
} else if (nulls->at(row_idx) || expr.attrs_[0]->get_vector(ctx)->is_null(row_idx)) {
|
|
root_vec->set_null(row_idx);
|
|
} else if (OB_FAIL(assemble_array_attrs(ctx, expr, row_idx, arr_obj))) {
|
|
LOG_WARN("assemble array attrs failed", K(ret));
|
|
} else if (OB_FAIL(set_array_res(arr_obj, expr, ctx, root_vec, row_idx))) {
|
|
LOG_WARN("set array res failed", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::calc_nested_expr_data_size(const ObExpr &expr, ObEvalCtx &ctx, const int64_t batch_idx, int64_t &size)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
size = 0;
|
|
for (uint32_t i = 0; i < expr.attrs_cnt_; ++i) {
|
|
ObIVector *vec = expr.attrs_[i]->get_vector(ctx);
|
|
VectorFormat format = vec->get_format();
|
|
if (VEC_DISCRETE == format) {
|
|
ObDiscreteBase *disc_vec = static_cast<ObDiscreteBase *>(vec);
|
|
if (!disc_vec->is_null(batch_idx)) {
|
|
ObLength *lens = disc_vec->get_lens();
|
|
size += lens[batch_idx];
|
|
}
|
|
} else if (VEC_CONTINUOUS == format) {
|
|
ObContinuousBase *cont_vec = static_cast<ObContinuousBase*>(vec);
|
|
uint32_t *offsets = cont_vec->get_offsets();
|
|
size += (offsets[batch_idx + 1] - offsets[batch_idx]);
|
|
} else if (is_uniform_format(format)) {
|
|
ObUniformBase *uni_vec = static_cast<ObUniformBase *>(vec);
|
|
ObDatum *datums = uni_vec->get_datums();
|
|
const uint64_t idx_mask = VEC_UNIFORM_CONST == format ? 0 : UINT64_MAX;
|
|
size += datums[batch_idx & idx_mask].len_;
|
|
} else if (VEC_FIXED == format) {
|
|
// array len
|
|
size += sizeof(uint32_t);
|
|
}
|
|
}
|
|
ObTextStringResult blob_res(ObLongTextType, true, nullptr);
|
|
if (OB_FAIL(blob_res.calc_buffer_len(size))) {
|
|
LOG_WARN("calculate data size failed", K(ret));
|
|
} else {
|
|
size = blob_res.get_buff_len();
|
|
}
|
|
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;
|
|
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<const ObSqlCollectionInfo *>(meta.value_);
|
|
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(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));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::get_array_obj(ObIAllocator &alloc, ObEvalCtx &ctx, const uint16_t subschema_id, const ObString &raw_data, ObIArrayType *&res)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObString data_str = raw_data;
|
|
if (res == NULL && OB_FAIL(construct_array_obj(alloc, ctx, subschema_id, res))) {
|
|
LOG_WARN("construct array obj failed", K(ret));
|
|
} else if (OB_FAIL(ObTextStringHelper::read_real_string_data(&alloc,
|
|
ObLongTextType,
|
|
CS_TYPE_BINARY,
|
|
true,
|
|
data_str))) {
|
|
LOG_WARN("fail to get real data.", K(ret), K(data_str));
|
|
} else if (OB_FAIL(res->init(data_str))) {
|
|
LOG_WARN("failed to init array", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::dispatch_array_attrs_rows(ObEvalCtx &ctx, ObIArrayType *arr_obj, const int64_t row_idx,
|
|
ObExpr **attrs, uint32_t attr_count, bool is_shallow)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObArrayAttr arr_attrs[attr_count];
|
|
uint32_t attr_idx = 0;
|
|
if (OB_FAIL(arr_obj->flatten(arr_attrs, attr_count, attr_idx))) {
|
|
LOG_WARN("array flatten failed", K(ret));
|
|
} else {
|
|
for (uint32_t i = 0; i < attr_count; i++) {
|
|
ObIVector *vec = attrs[i]->get_vector(ctx);
|
|
if (i == 0) {
|
|
vec->set_int(row_idx, arr_obj->size());
|
|
} else if (arr_attrs[i - 1].ptr_ == NULL && arr_attrs[i - 1].length_ == 0) {
|
|
vec->set_payload_shallow(row_idx, NULL, 0); // get ride of random values
|
|
vec->set_null(row_idx);
|
|
} else {
|
|
const char *payload = arr_attrs[i - 1].ptr_;
|
|
uint32_t len = arr_attrs[i - 1].length_;
|
|
(is_shallow || payload == NULL) ? vec->set_payload_shallow(row_idx, payload, len) : vec->set_payload(row_idx, payload, len);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::nested_expr_from_rows(const ObExpr &expr, ObEvalCtx &ctx, const sql::RowMeta &row_meta, const sql::ObCompactRow **stored_rows,
|
|
const int64_t size, const int64_t col_idx, const int64_t *selector)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObIVector *vec = expr.get_vector(ctx);
|
|
VectorFormat format = vec->get_format();
|
|
ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx);
|
|
// to fix : outrow lob can't use tmp allocator
|
|
common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator();
|
|
ObIArrayType *arr_obj = NULL;
|
|
const uint16_t subschema_id = expr.obj_meta_.get_subschema_id();
|
|
|
|
if (OB_FAIL(construct_array_obj(tmp_allocator, ctx, subschema_id, arr_obj))) {
|
|
LOG_WARN("construct array obj failed", K(ret));
|
|
}
|
|
for (int64_t i = 0; i < size && OB_SUCC(ret); i++) {
|
|
int64_t row_idx = i;
|
|
if (selector != nullptr) {
|
|
row_idx = selector[i];
|
|
}
|
|
if (stored_rows[i]->is_null(col_idx)) {
|
|
vec->set_null(row_idx);
|
|
set_expr_attrs_null(expr, ctx, row_idx);
|
|
} else {
|
|
const char *payload = NULL;
|
|
ObLength len = 0;
|
|
stored_rows[i]->get_cell_payload(row_meta, col_idx, payload, len);
|
|
ObLobCommon *lob_comm = (ObLobCommon*)(payload);
|
|
ObString array_data(len, payload);
|
|
if (lob_comm->is_valid()) {
|
|
if (OB_FAIL(ObTextStringHelper::read_real_string_data(&tmp_allocator,
|
|
ObLongTextType,
|
|
CS_TYPE_BINARY,
|
|
true,
|
|
array_data))) {
|
|
LOG_WARN("fail to get real data.", K(ret), K(array_data));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(arr_obj->init(array_data))) {
|
|
LOG_WARN("failed to init array", K(ret));
|
|
} else if (OB_FAIL(dispatch_array_attrs_rows(ctx, arr_obj, row_idx, expr.attrs_, expr.attrs_cnt_))) {
|
|
LOG_WARN("failed to dispatch array attrs rows", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::nested_expr_to_rows(const ObExpr &expr, ObEvalCtx &ctx, const sql::RowMeta &row_meta, sql::ObCompactRow **stored_rows,
|
|
const uint16_t selector[], const int64_t size, const int64_t col_idx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObIVector *vec = expr.get_vector(ctx);
|
|
VectorFormat format = vec->get_format();
|
|
for (int64_t i = 0; i < size; i++) {
|
|
int64_t row_idx = selector[i];
|
|
if (vec->is_null(row_idx)) {
|
|
stored_rows[i]->set_null(row_meta, col_idx);
|
|
} else {
|
|
int64_t pos = 0;
|
|
for (uint32_t i = 0; i < expr.attrs_cnt_ && OB_SUCC(ret); ++i) {
|
|
const char *payload = NULL;
|
|
ObLength payload_len = 0;
|
|
ObIVector *vec = expr.attrs_[i]->get_vector(ctx);
|
|
VectorFormat format = vec->get_format();
|
|
vec->get_payload(row_idx, payload, payload_len);
|
|
stored_rows[i]->append_cell_payload(row_meta, col_idx, payload, payload_len, pos);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObArrayExprUtils::nested_expr_to_row(const ObExpr &expr, ObEvalCtx &ctx, char *row_buf,
|
|
const int64_t col_offset, const uint64_t row_idx, int64_t &cell_len,
|
|
const int64_t *remain_size)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
uint32_t data_len = 0;
|
|
const uint16_t subschema_id = expr.obj_meta_.get_subschema_id();
|
|
ObSubSchemaValue meta;
|
|
bool is_vector = false;
|
|
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<const ObSqlCollectionInfo *>(meta.value_);
|
|
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(src_coll_info->collection_meta_);
|
|
is_vector = arr_type->type_id_ == ObNestedType::OB_VECTOR_TYPE;
|
|
if (is_vector) {
|
|
ObIVector *vec = expr.attrs_[2]->get_vector(ctx);
|
|
data_len += vec->get_length(row_idx);
|
|
} else {
|
|
for (uint32_t i = 0; i < expr.attrs_cnt_ && OB_SUCC(ret); ++i) {
|
|
if (i == 0) {
|
|
data_len += sizeof(uint32_t);
|
|
} else {
|
|
ObIVector *vec = expr.attrs_[i]->get_vector(ctx);
|
|
data_len += vec->get_length(row_idx);
|
|
}
|
|
}
|
|
}
|
|
ObString res_buf;
|
|
ObTextStringResult blob_res(ObLongTextType, true, nullptr);
|
|
if (OB_FAIL(blob_res.calc_buffer_len(data_len))) {
|
|
LOG_WARN("calc buffer len failed", K(ret), K(data_len));
|
|
} else if (remain_size != NULL && blob_res.get_buff_len() > *remain_size) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
LOG_WARN("row memory isn't enough", K(ret), K(blob_res.get_buff_len()), K(*remain_size));
|
|
} else if (FALSE_IT(res_buf.assign_ptr(row_buf + col_offset, blob_res.get_buff_len()))) {
|
|
} else if (OB_FAIL(blob_res.init(data_len, res_buf))) {
|
|
LOG_WARN("text string init failed", K(ret), K(data_len));
|
|
} else if (is_vector) {
|
|
const char *payload = NULL;
|
|
ObLength payload_len = 0;
|
|
ObIVector *vec = expr.attrs_[2]->get_vector(ctx);
|
|
vec->get_payload(row_idx, payload, payload_len);
|
|
if (OB_FAIL(blob_res.append(payload, payload_len))) {
|
|
LOG_WARN("failed to append realdata", K(ret), K(payload_len));
|
|
}
|
|
} else {
|
|
for (uint32_t i = 0; i < expr.attrs_cnt_ && OB_SUCC(ret); ++i) {
|
|
const char *payload = NULL;
|
|
ObLength payload_len = 0;
|
|
ObIVector *vec = expr.attrs_[i]->get_vector(ctx);
|
|
uint32_t len = 0;
|
|
if (i == 0) {
|
|
len = vec->get_uint32(row_idx);
|
|
payload = reinterpret_cast<const char *>(&len);
|
|
payload_len = sizeof(uint32_t);
|
|
} else {
|
|
vec->get_payload(row_idx, payload, payload_len);
|
|
}
|
|
if (OB_FAIL(blob_res.append(payload, payload_len))) {
|
|
LOG_WARN("failed to append realdata", K(ret), K(payload_len));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
cell_len = blob_res.get_buff_len();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObArrayExprUtils::set_expr_attrs_null(const ObExpr &expr, ObEvalCtx &ctx, const int64_t idx)
|
|
{
|
|
ObIVector *vec = expr.get_vector(ctx);
|
|
VectorFormat format = vec->get_format();
|
|
if (is_uniform_format(format)) {
|
|
// do nothing
|
|
} else {
|
|
for (uint32_t i = 0; i < expr.attrs_cnt_; ++i) {
|
|
ObIVector *vec = expr.attrs_[i]->get_vector(ctx);
|
|
vec->set_null(idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
int ObNestedVectorFunc::construct_attr_param(ObIAllocator &alloc, ObEvalCtx &ctx, ObExpr ¶m_expr,
|
|
const uint16_t meta_id, int64_t row_idx, ObIArrayType *¶m_obj)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (param_obj == NULL && OB_FAIL(ObArrayExprUtils::construct_array_obj(alloc, ctx, meta_id, param_obj))) {
|
|
LOG_WARN("construct array obj failed", K(ret));
|
|
} else if (OB_FAIL(ObArrayExprUtils::assemble_array_attrs(ctx, param_expr, row_idx, param_obj))) {
|
|
LOG_WARN("assemble array attrs failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNestedVectorFunc::construct_param(
|
|
ObIAllocator &alloc, ObEvalCtx &ctx, const uint16_t meta_id, ObString &str_data, ObIArrayType *¶m_obj)
|
|
{
|
|
return ObArrayExprUtils::get_array_obj(alloc, ctx, meta_id, str_data, param_obj);
|
|
}
|
|
|
|
int ObNestedVectorFunc::construct_res_obj(
|
|
ObIAllocator &alloc, ObEvalCtx &ctx, const uint16_t meta_id, ObIArrayType *&res_obj)
|
|
{
|
|
return ObArrayExprUtils::construct_array_obj(alloc, ctx, meta_id, res_obj, false);
|
|
}
|
|
|
|
int ObNestedVectorFunc::construct_params(ObIAllocator &alloc, ObEvalCtx &ctx, const uint16_t left_meta_id,
|
|
const uint16_t right_meta_id, const uint16_t res_meta_id, ObString &left, ObString right, ObIArrayType *&left_obj,
|
|
ObIArrayType *&right_obj, ObIArrayType *&res_obj)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(ObArrayExprUtils::get_array_obj(alloc, ctx, left_meta_id, left, left_obj))) {
|
|
SQL_ENG_LOG(WARN, "get array failed", K(ret));
|
|
} else if (OB_FAIL(ObArrayExprUtils::get_array_obj(alloc, ctx, right_meta_id, right, right_obj))) {
|
|
SQL_ENG_LOG(WARN, "get array failed", K(ret));
|
|
} else if (OB_FAIL(ObArrayExprUtils::construct_array_obj(alloc, ctx, res_meta_id, res_obj, false))) {
|
|
SQL_ENG_LOG(WARN, "construct res array failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
} // sql
|
|
} // oceanbase
|