Files
oceanbase/src/sql/engine/expr/ob_expr_sql_udt_utils.cpp
wanghangQ 5cbd86c9e6 [FEAT MERGE] Vector Index & Array Type
Co-authored-by: helloamateur <magiccheery@163.com>
Co-authored-by: skylhd <dickylhd@gmail.com>
Co-authored-by: JLY2015 <1623359870@qq.com>
2024-08-29 07:52:22 +00:00

1631 lines
71 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 is for implement of expr sql udt utils
*/
#define USING_LOG_PREFIX SQL_ENG
#include "lib/ob_errno.h"
#include "sql/engine/ob_exec_context.h"
#include "sql/engine/expr/ob_expr_sql_udt_utils.h"
#include "sql/engine/expr/ob_expr_lob_utils.h"
#include "pl/ob_pl.h"
#include "pl/ob_pl_user_type.h"
#include "src/pl/ob_pl_resolver.h"
#include "lib/udt/ob_array_type.h"
using namespace oceanbase::common;
using namespace oceanbase::sql;
namespace oceanbase
{
namespace sql
{
bool ObSqlUdtNullBitMap::is_valid()
{
return (OB_NOT_NULL(bitmap_) && bitmap_len_ > 0);
}
int ObSqlUdtNullBitMap::check_bitmap_pos(uint32_t pos, bool &is_set)
{
int ret = OB_SUCCESS;
is_set = false;
uint32 index = pos / 8;
uint32 byte_index = pos % 8;
if (index >= bitmap_len_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("check udt bitmap overflow", K(ret), K(*this), K(index), K(byte_index), K(pos));
} else {
is_set = bitmap_[index] & (1 << byte_index);
}
return ret;
}
int ObSqlUdtNullBitMap::check_current_bitmap_pos(bool &is_set)
{
return check_bitmap_pos(pos_, is_set);
}
int ObSqlUdtNullBitMap::set_bitmap_pos(uint32_t pos)
{
int ret = OB_SUCCESS;
uint32 index = pos / 8;
uint32 byte_index = pos % 8;
if (index >= bitmap_len_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("set udt bitmap overflow", K(ret), K(*this), K(index), K(byte_index), K(pos));
} else {
bitmap_[index] |= (1 << byte_index);
}
return ret;
}
int ObSqlUdtNullBitMap::set_current_bitmap_pos()
{
return set_bitmap_pos(pos_);
}
int ObSqlUdtNullBitMap::reset_bitmap_pos(uint32_t pos)
{
int ret = OB_SUCCESS;
uint32 index = pos / 8;
uint32 byte_index = pos % 8;
if (index >= bitmap_len_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("reset udt bitmap overflow", K(ret), K(*this), K(index), K(byte_index), K(pos));
} else {
bitmap_[index] &= ~(1 << byte_index);
}
return ret;
}
int ObSqlUdtNullBitMap::reset_current_bitmap_pos()
{
return reset_bitmap_pos(pos_);
}
int ObSqlUdtNullBitMap::assign(ObSqlUdtNullBitMap &src, uint32_t pos, uint32_t bit_len)
{
int ret = OB_SUCCESS;
uint32_t src_pos = src.get_pos();
for (int i = 0; i < bit_len && OB_SUCC(ret); i++) {
bool is_set = false;
if (OB_FAIL(src.check_bitmap_pos(pos + i, is_set))) {
LOG_WARN("failed to check nested udt bitmap", K(ret));
} else if (is_set && OB_FAIL(set_current_bitmap_pos())) {
LOG_WARN("failed to set nested udt bitmap", K(ret));
} else {
get_pos()++;
}
}
src.set_bitmap_pos(src_pos);
return ret;
}
int ObSqlUdtUtils::ob_udt_flattern_varray(const ObObj **flattern_objs,
const int32_t &flattern_object_count,
int32_t &pos,
const ObObj *obj,
ObExecContext &exec_context,
ObSqlUDT &sql_udt)
{
int ret = OB_SUCCESS;
flattern_objs[pos++] = obj; // varray in sql udt is a single obj
return ret;
}
int ObSqlUdtUtils::ob_udt_flattern_record(const ObObj **flattern_objs,
const int32_t &flattern_object_count,
int32_t &pos,
ObSqlUdtNullBitMap &nested_udt_bitmap,
const ObObj *obj,
ObExecContext &exec_context,
ObSqlUDT &sql_udt) {
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
bool is_null_result = false;
pl::ObPLRecord *record = NULL;
if (OB_ISNULL(obj) || obj->get_ext() == 0) {
is_null_result = true;
} else if (FALSE_IT(record = reinterpret_cast<pl::ObPLRecord *>(obj->get_ext()))) {
} else if (record->is_null()) {
is_null_result = true;
} else {
const ObObj *elements = record->get_element();
const ObObj *cur_element = NULL;
ObSqlUDTAttrMeta *&attrs = sql_udt.get_udt_meta().child_attrs_meta_;
if (OB_ISNULL(attrs)) {
ret = OB_BAD_NULL_ERROR;
LOG_WARN("Unexpected NULL toplevel attributes meta", K(ret));
} else {
uint32_t toplevel_attrs_count = sql_udt.get_udt_meta().child_attr_cnt_;
for (int32_t i = 0; OB_SUCC(ret) && i < toplevel_attrs_count; i++) {
ObObjType element_type = attrs[i].type_info_.get_type();
cur_element = &elements[i];
if (element_type >= ObMaxType) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Unexpected record element type", K(ret), K(element_type));
} else if (ob_is_user_defined_sql_type(element_type) || // nested udt type
ob_is_collection_sql_type(element_type)) {
const uint16_t subschema_id = attrs[i].type_info_.get_subschema_id();
ObSqlUDTMeta udt_meta;
ObSqlUDT sql_udt;
if (OB_FAIL(exec_context.get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) {
LOG_WARN("failed to get udt meta", K(ret), K(subschema_id));
} else if (udt_meta.udt_id_ == T_OBJ_XML) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("nested xmltype not supported", K(ret), K(udt_meta.udt_id_));
} else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_WARN("inconsistent datatypes", K(ret), K(subschema_id), K(udt_meta.udt_id_));
} else {
sql_udt.set_udt_meta(udt_meta);
int32_t element_pos = 0; // Notice: udt leaf is flattern
if (OB_FAIL(ob_udt_flattern_pl_extend(&flattern_objs[pos],
udt_meta.leaf_attr_cnt_,
element_pos,
nested_udt_bitmap,
cur_element,
exec_context,
sql_udt))) {
LOG_WARN("failed to flattern nested record", K(ret), K(subschema_id), K(udt_meta.udt_id_));
} else {
pos += element_pos;
}
}
} else if (cur_element == NULL || cur_element->is_null()) { // basic type with null value
flattern_objs[pos] = NULL;
pos++;
} else if (!ob_udt_util_check_same_type(element_type, cur_element->get_type())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("record element type mismarch", K(ret), K(element_type), K(cur_element->get_type()));
} else {
flattern_objs[pos] = cur_element;
pos++;
}
}
}
}
if (OB_SUCC(ret) && is_null_result) {
// Notice: 1. null extend data is null UDT; 2. bitmap pos is 1 + nested_udt_number_
for (int32_t i = 0; OB_SUCC(ret) && i <= sql_udt.get_udt_meta().nested_udt_number_; i++) {
if (OB_FAIL(nested_udt_bitmap.set_current_bitmap_pos())) {
LOG_WARN("failed to set nested udt bitmap", K(ret));
} else {
nested_udt_bitmap.get_pos()++;
}
}
for (int32_t i = 0; OB_SUCC(ret) && i < sql_udt.get_udt_meta().attribute_cnt_; i++) {
if (pos >= flattern_object_count) {
ret = OB_INDEX_OUT_OF_RANGE;
LOG_WARN("flatter objs number error", K(ret), K(pos), K(flattern_object_count));
} else {
flattern_objs[pos] = NULL;
pos++;
}
}
}
#endif
return ret;
}
int ObSqlUdtUtils::ob_udt_flattern_pl_extend(const ObObj **flattern_objs,
const int32_t &flattern_object_count,
int32_t &pos,
ObSqlUdtNullBitMap &nested_udt_bitmap,
const ObObj *obj,
ObExecContext &exec_context,
ObSqlUDT &sql_udt)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
if (sql_udt.get_udt_meta().udt_id_ == T_OBJ_XML) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("nested xmltype not supported", K(ret));
} else if (sql_udt.get_udt_meta().pl_type_ == pl::PL_RECORD_TYPE) {
if (OB_FAIL(ob_udt_flattern_record(flattern_objs, flattern_object_count, pos,
nested_udt_bitmap,
obj, exec_context, sql_udt))) {
LOG_WARN("failed to cast sql record to pl record", K(ret), K(sql_udt.get_udt_meta().udt_id_));
}
} else if (sql_udt.get_udt_meta().pl_type_ == pl::PL_VARRAY_TYPE) {
if (OB_FAIL(ob_udt_flattern_varray(flattern_objs, flattern_object_count, pos,
obj, exec_context, sql_udt))) {
LOG_WARN("failed to cast sql varray to pl varrayd",
K(ret), K(sql_udt.get_udt_meta().udt_id_));
}
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_WARN("inconsistent datatypes", K(ret), K(sql_udt.get_udt_meta().udt_id_));
}
#endif
return ret;
}
int ObSqlUdtUtils::ob_udt_reordering_leaf_objects(const ObObj **flattern_objs,
const ObObj **sorted_objs,
const int32_t &flattern_object_count,
ObSqlUDT &sql_udt)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; i < flattern_object_count; i++) {
int64_t index = sql_udt.get_udt_meta().leaf_attrs_meta_[i].order_;
sorted_objs[i] = flattern_objs[index];
}
return ret;
}
int ObSqlUdtUtils::ob_udt_calc_sql_varray_length(const ObObj *cur_obj,
int64_t &sql_udt_total_len,
bool with_lob_header)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
uint32_t count = 0;
uint32_t varray_len = 0;
pl::ObPLVArray *varray = reinterpret_cast<pl::ObPLVArray *>(cur_obj->get_ext());
if (OB_ISNULL(varray) || OB_ISNULL(varray->get_data())) {
// empty array, do nothing
} else {
count = varray->get_count();
// count length
varray_len += sizeof(uint32);
// null count
varray_len += sizeof(uint32);
// null bitmap length
varray_len += ObSqlUDT::get_offset_array_len(count);
// offset array length
varray_len += ObSqlUDT::get_null_bitmap_len(count);
// elements length
const ObObj *cur_obj = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < count; i++) {
cur_obj = &varray->get_data()[i];
if (cur_obj == NULL || cur_obj->is_null()) {
// do nothing
} else if (cur_obj->is_ext() || cur_obj->is_user_defined_sql_type()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("varray with udt type is not supported", K(ret), K(cur_obj));
} else { // serialize basic types
int64_t val_len = 0;
if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_get_serialize_size(*cur_obj, val_len))) {
LOG_WARN("Failed to calc object val length", K(ret), K(*cur_obj));
} else {
varray_len += val_len;
}
}
}
// varray is a lob, calc lob locator len
int64_t templob_len = 0;
if (OB_FAIL(ret)) {
} else if (!with_lob_header) {
sql_udt_total_len += varray_len;
} else {
if (OB_FAIL(ObTextStringResult::calc_inrow_templob_len(varray_len, templob_len))) {
LOG_WARN("calc sql varray lob length failed", K(ret), K(*cur_obj));
} else {
sql_udt_total_len += templob_len;
}
}
}
#endif
return ret;
}
int ObSqlUdtUtils::ob_udt_calc_total_len(const ObObj **sorted_objs,
const int32_t &flattern_object_count,
int64_t &sql_udt_total_len,
ObSqlUDT &sql_udt)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
if (OB_ISNULL(sorted_objs) || flattern_object_count == 0) {
ret = OB_BAD_NULL_ERROR;
LOG_WARN("null objs", K(ret), KP(sorted_objs), K(flattern_object_count));
} else {
int64_t leaf_attr_count = sql_udt.get_udt_meta().leaf_attr_cnt_ + 1;
if (sql_udt.get_udt_meta().pl_type_ == pl::PL_RECORD_TYPE) {
sql_udt_total_len += sql_udt.get_null_bitmap_len(leaf_attr_count);
sql_udt_total_len += sql_udt.get_offset_array_len(leaf_attr_count);
}
const ObObj *cur_obj = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < flattern_object_count; i++) {
cur_obj = sorted_objs[i];
if (cur_obj == NULL) {
} else if (cur_obj->is_ext()) {
pl::ObPLType pl_type = static_cast<pl::ObPLType>(cur_obj->get_meta().get_extend_type());
if (pl_type == pl::PL_VARRAY_TYPE) {
if (OB_FAIL(ob_udt_calc_sql_varray_length(cur_obj, sql_udt_total_len))) {
LOG_WARN("Failed to calc sql varray length", K(ret), K(i), K(pl_type));
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("Unexpected supported pl type", K(ret), K(i), K(pl_type));
}
} else { // serialize basic types
int64_t val_len = 0;
if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_get_serialize_size(*cur_obj, val_len))) {
LOG_WARN("Failed to calc object val length", K(ret), K(*cur_obj));
} else {
sql_udt_total_len += val_len;
}
}
}
}
#endif
return ret;
}
int ObSqlUdtUtils::ob_udt_convert_pl_varray_to_sql_varray(const ObObj *cur_obj,
char *buf,
const int64_t buf_len,
int64_t &pos,
bool with_lob_header)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
uint32_t count = 0;
pl::ObPLVArray *varray = reinterpret_cast<pl::ObPLVArray *>(cur_obj->get_ext());
if (OB_ISNULL(varray) || OB_ISNULL(varray->get_data())) {
// empty array, do nothing
} else {
int64_t locator_header_offset = pos;
int64_t locator_header_len = with_lob_header
? ObTextStringResult::calc_inrow_templob_locator_len()
: 0;
// reserve length for templob header;
pos += locator_header_len;
// related_start for calculating array element offset
int64_t related_start = pos;
// encoding count
count = varray->get_count();
*(reinterpret_cast<uint32_t *>(&buf[pos])) = count;
// null count
pos += sizeof(uint32_t);
uint32_t null_count_offset = pos;
*(reinterpret_cast<uint32_t *>(&buf[pos])) = 0;
// bitmap
pos += sizeof(uint32_t);
char *leaf_bitmap_ptr = buf + pos;
uint32_t leaf_bitmap_len = ObSqlUDT::get_null_bitmap_len(count);
MEMSET(leaf_bitmap_ptr, 0, leaf_bitmap_len);
// reserve bitmap
pos += leaf_bitmap_len;
uint32_t *offset_ptr = reinterpret_cast<uint32_t *>(buf + pos);
// reserve offset array
pos += ObSqlUDT::get_offset_array_len(count);
// elements length
const ObObj *cur_obj = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < count; i++) {
cur_obj = &varray->get_data()[i];
if (cur_obj == NULL|| cur_obj->is_null()) {
offset_ptr[i] = pos - related_start;
if (OB_FAIL(ObSqlUDT::set_null_bitmap_pos(leaf_bitmap_ptr, leaf_bitmap_len, i))) {
LOG_WARN("Failed to set varray element null bitmap",
K(ret), K(leaf_bitmap_ptr), K(leaf_bitmap_len), K(i));
} else {
ObSqlUDT::increase_varray_null_count(buf + null_count_offset);
}
} else if (cur_obj->is_ext() || cur_obj->is_user_defined_sql_type()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("varray with udt type is not supported", K(ret), K(cur_obj));
} else { // serialize basic types
uint64_t offset = pos - related_start;
if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_serialize(*cur_obj, buf, buf_len, pos))) {
LOG_WARN("Failed to serialize object value", K(ret), K(*cur_obj));
} else {
offset_ptr[i] = offset;
}
}
}
if (with_lob_header) {
int64_t templob_inrow_data_len = pos - locator_header_len - locator_header_offset;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObTextStringResult::fill_inrow_templob_header(templob_inrow_data_len,
buf + locator_header_offset,
pos - locator_header_offset))) {
LOG_WARN("Failed to set templob header for sql varray", K(ret), K(*cur_obj));
}
}
}
#endif
return ret;
}
// convert pl extend to sql udt by type
int ObSqlUdtUtils::ob_udt_convert_sorted_objs_array_to_udf_format(const ObObj **sorted_objs,
char *buf,
const int64_t buf_len,
int64_t &pos,
ObSqlUDT &sql_udt)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
if (OB_ISNULL(sorted_objs)) {
ret = OB_BAD_NULL_ERROR;
LOG_WARN("Unexpected NULL element", K(ret));
} else { // record
int64_t leaf_attr_count = sql_udt.get_udt_meta().leaf_attr_cnt_ + 1;
char *leaf_bitmap_ptr = buf + pos;
uint32_t leaf_bitmap_len = ObSqlUDT::get_null_bitmap_len(leaf_attr_count);
MEMSET(leaf_bitmap_ptr, 0, leaf_bitmap_len);
pos += sql_udt.get_null_bitmap_len(leaf_attr_count);
uint32_t *offset_ptr = reinterpret_cast<uint32_t *>(buf + pos);
pos += sql_udt.get_offset_array_len(leaf_attr_count);
if (pos > buf_len) { // pos could equal to buf_len, when all elements are NULL
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Buffer overflow", K(ret), K(pos), K(buf_len));
}
const ObObj *cur_element = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < leaf_attr_count; i++) {
cur_element = sorted_objs[i];
ObObjType cur_element_type = ObMaxType;
offset_ptr[i] = 0;
if (OB_ISNULL(cur_element)) {
offset_ptr[i] = pos;
if (OB_FAIL(ObSqlUDT::set_null_bitmap_pos(leaf_bitmap_ptr, leaf_bitmap_len, i))) {
LOG_WARN("Failed to set varray element null bitmap",
K(ret), K(leaf_bitmap_ptr), K(leaf_bitmap_len), K(i));
}
} else if (FALSE_IT(cur_element_type = cur_element->get_type())) {
} else if (cur_element_type == ObUserDefinedSQLType
|| cur_element_type == ObCollectionSQLType
|| cur_element_type >= ObMaxType) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Unexpected record element type", K(ret), K(cur_element_type));
} else if (cur_element_type == ObExtendType) {
pl::ObPLType pl_type = static_cast<pl::ObPLType>(cur_element->get_meta().get_extend_type());
if (pl_type == pl::PL_VARRAY_TYPE) {
uint64_t offset = pos;
if (OB_FAIL(ob_udt_convert_pl_varray_to_sql_varray(cur_element, buf, buf_len, pos))) {
LOG_WARN("convert pl varray to sql varray failed", K(ret), K(i), K(pl_type));
} else {
offset_ptr[i] = offset;
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("Unexpected supported pl type", K(ret), K(i), K(pl_type));
}
} else {
// serialize basic types
uint64_t offset = pos;
if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_serialize(*cur_element, buf, buf_len, pos))) {
LOG_WARN("Failed to serialize object value", K(ret), K(*cur_element));
} else {
offset_ptr[i] = offset;
}
}
}
if (OB_SUCC(ret) && (pos != buf_len)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sql udt content length error", K(ret), K(pos), K(buf_len));
}
}
#endif
return ret;
}
// convert sql_udt to string by type
int ObSqlUdtUtils::covert_sql_udt_varray_to_string(ObStringBuffer &buf,
ObString &udt_varray_buf,
ObSqlUDTMeta &root_meta)
{
int ret = OB_SUCCESS;
ObSqlUDT varray_handler;
varray_handler.set_udt_meta(root_meta);
ObString varray_data = udt_varray_buf;
ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID());
if (OB_FAIL(ObTextStringHelper::read_real_string_data(&lob_allocator,
ObLongTextType,
CS_TYPE_BINARY,
true, varray_data))) {
LOG_WARN("fail to get real string data", K(ret), K(varray_data));
} else if (FALSE_IT(varray_handler.set_data(varray_data))) {
} else if (varray_data.empty()) {
if (OB_FAIL(buf.append("NULL"))) {
LOG_WARN("fail to print empty value", K(ret));
}
} else if (OB_FAIL(buf.append(varray_handler.get_udt_meta().udt_name_,
varray_handler.get_udt_meta().udt_name_len_))) {
LOG_WARN("fail to print varray name start", K(ret));
} else if (OB_FAIL(buf.append("("))){
LOG_WARN("fail to print (", K(ret));
} else {
uint64_t element_count = varray_handler.get_varray_element_count();
ObString ser_element_data;
char number_buff[256];
for (int64_t i = 0; OB_SUCC(ret) && i < element_count; i++) {
if (OB_FAIL(varray_handler.access_attribute(i, ser_element_data, true))) {
LOG_WARN("fail to access attribute buffer", K(ret));
} else if (ser_element_data.empty()) {
if (OB_FAIL(buf.append("NULL"))) {
LOG_WARN("fail to print empty value", K(ret));
}
} else {
ObObj obj;
obj.set_meta_type(varray_handler.get_udt_meta().child_attrs_meta_[0].type_info_);
int64_t pos = 0;
if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj,
ser_element_data.ptr(),
ser_element_data.length(),
pos))) {
LOG_WARN("Failed to serialize object value", K(ret), K(ser_element_data));
} else {
// ToDo: different types
if (obj.get_type_class() == ObNumberTC) {
int64_t str_len = 0;
const number::ObNumber &val = obj.get_number();
int16_t scale = obj.get_scale();
if (OB_FAIL(val.format(number_buff, sizeof(number_buff), str_len, scale))) {
LOG_WARN("fail to format number with oracle limit", K(ret), K(str_len), K(scale));
} else if (OB_FAIL(buf.append(number_buff, str_len))) {
LOG_WARN("fail to print number value", K(ret), K(val));
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported udt element type", K(ret), K(obj));
}
}
}
if (OB_SUCC(ret)) {
if ((i < element_count - 1) && OB_FAIL(buf.append(", "))) {
LOG_WARN("fail to print ,", K(ret));
}
}
}
if (OB_SUCC(ret) && OB_FAIL(buf.append(")"))) {
LOG_WARN("fail to print )", K(ret));
}
}
return ret;
}
int ObSqlUdtUtils::convert_sql_udt_attributes_to_string(ObStringBuffer &buf,
ObString *attrs,
int64_t &pos,
sql::ObExecContext *exec_context,
ObSqlUDTMeta &root_meta,
ObSqlUdtNullBitMap &nested_udt_bitmap)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
if (OB_FAIL(buf.append(root_meta.udt_name_, root_meta.udt_name_len_))) {
LOG_WARN("fail to print point type start", K(ret));
} else if (OB_FAIL(buf.append("("))){
LOG_WARN("fail to print (", K(ret));
} else {
ObObj obj;
char number_buff[256];
for (int64_t i = 0; OB_SUCC(ret) && i < root_meta.child_attr_cnt_; i++) {
ObObjType type = root_meta.child_attrs_meta_[i].type_info_.get_type();
obj.reset();
obj.set_meta_type(root_meta.child_attrs_meta_[i].type_info_);
bool is_nested_record = false;
if (type == ObUserDefinedSQLType ||
(type == ObCollectionSQLType && root_meta.child_attr_cnt_ > 1)) {
const uint16_t subschema_id = obj.get_meta().get_subschema_id();
ObSqlUDTMeta udt_meta;
// should be varray or record
bool is_udt_null = false;
if (OB_FAIL(exec_context->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) {
LOG_WARN("failed to get udt meta", K(ret), K(subschema_id));
} else if (nested_udt_bitmap.is_valid()
&& OB_FAIL(nested_udt_bitmap.check_current_bitmap_pos(is_udt_null))) {
LOG_WARN("failed to get nested udt null bit", K(ret), K(nested_udt_bitmap));
} else if (is_udt_null) {
if (OB_FAIL(buf.append("NULL"))) {
LOG_WARN("fail to print empty value", K(ret));
} else {
pos += udt_meta.leaf_attr_cnt_;
nested_udt_bitmap.get_pos() += (udt_meta.nested_udt_number_ + 1); // count the nested udt itself
is_nested_record = true;
}
} else if (udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) {
if (OB_FAIL(covert_sql_udt_varray_to_string(buf,
attrs[pos],
udt_meta))) {
LOG_WARN("failed to convert sql udt varray to string failed",
K(ret), K(i), K(pos), K(subschema_id));
}
} else if (udt_meta.pl_type_ == pl::PL_RECORD_TYPE) {
if (OB_FAIL(convert_sql_udt_attributes_to_string(buf,
attrs,
pos,
exec_context,
udt_meta,
nested_udt_bitmap))) {
LOG_WARN("failed to convert to string", K(ret), K(udt_meta.pl_type_));
}
is_nested_record = true;
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Unexpected type to convert pl udt to sql udt format", K(ret), K(udt_meta.pl_type_));
}
} else { // basic types
int64_t buf_pos = 0;
if (OB_ISNULL(attrs[pos])) {
if (OB_FAIL(buf.append("NULL"))) {
LOG_WARN("fail to print empty value", K(ret));
}
} else if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj,
attrs[pos].ptr(),
attrs[pos].length(),
buf_pos))) {
LOG_WARN("Failed to serialize object value", K(ret), K(attrs[pos]));
} else {
// ToDo: @gehao, different basic types
int64_t str_len = 0;
const number::ObNumber &val = obj.get_number();
int16_t scale = obj.get_scale();
if (OB_FAIL(val.format(number_buff, sizeof(number_buff), str_len, scale))) {
LOG_WARN("fail to format number with oracle limit", K(ret), K(str_len), K(scale));
} else if (OB_FAIL(buf.append(number_buff, str_len))) {
LOG_WARN("fail to print number value", K(ret), K(val));
}
}
}
if (OB_SUCC(ret)) { // Notice: not use pos for ',' and ')'
if ((i < root_meta.child_attr_cnt_ - 1) && OB_FAIL(buf.append(", "))) {
LOG_WARN("fail to print ,", K(ret));
} else if ((i == root_meta.child_attr_cnt_ - 1) && OB_FAIL(buf.append(")"))) {
LOG_WARN("fail to print )", K(ret));
} else {
pos += (is_nested_record ? 0 : 1);
}
}
}
}
#endif
return ret;
}
int ObSqlUdtUtils::rearrange_sql_udt_record(ObString &sql_udt_data,
ObSqlUDTMeta udt_meta,
common::ObIAllocator *allocator,
ObSqlUdtNullBitMap &nested_udt_bitmap,
ObString *&attrs,
bool &is_null)
{
int ret = OB_SUCCESS;
ObString udt_data = sql_udt_data;
if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, ObLongTextType, CS_TYPE_BINARY, true, udt_data))) {
LOG_WARN("fail to get real string data", K(ret), K(udt_data));
} else {
ObSqlUDT sql_udt;
sql_udt.set_udt_meta(udt_meta);
sql_udt.set_data(udt_data);
ObString *temp_leaf_attrs = NULL;
ObString *leaf_attrs = NULL;
ObSqlUDTAttrMeta *top_attrs_meta = udt_meta.child_attrs_meta_;
ObSqlUDTAttrMeta *leaf_attrs_meta = udt_meta.leaf_attrs_meta_;
int64_t leaf_attr_count = udt_meta.leaf_attr_cnt_;
if (OB_ISNULL(top_attrs_meta) || OB_ISNULL(leaf_attrs_meta) || (leaf_attr_count == 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid udt meta", K(ret), KP(top_attrs_meta), KP(leaf_attrs_meta), K(leaf_attr_count));
} else {
uint64_t alloc_len = sizeof(ObString) * leaf_attr_count;
if (OB_ISNULL(temp_leaf_attrs = reinterpret_cast<ObString *>(allocator->alloc(alloc_len)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to allocate memory for attributes", K(ret), K(alloc_len));
} else if (OB_ISNULL(leaf_attrs = reinterpret_cast<ObString *>(allocator->alloc(alloc_len)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to allocate memory for rearranged attributes", K(ret), K(alloc_len));
} else {
ObString attribute_data;
bool root_udt_is_null = false;
ObObj udt_null_bitmap;
udt_null_bitmap.reset();
udt_null_bitmap.set_type(ObHexStringType);
int64_t buf_pos = 0;
// get first attribute(nested udt null bitmpa)
if (OB_FAIL(sql_udt.access_attribute(0, attribute_data))) {
LOG_WARN("fail to access null bitmap attribute", K(ret));
} else if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(udt_null_bitmap,
attribute_data.ptr(),
attribute_data.length(),
buf_pos))) {
LOG_WARN("Failed to serialize object value", K(ret), K(attribute_data));
} else {
nested_udt_bitmap.set_bitmap(udt_null_bitmap.get_string().ptr(),
udt_null_bitmap.get_string().length());
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(nested_udt_bitmap.check_bitmap_pos(0, root_udt_is_null))) {
LOG_WARN("Failed to get root null bit", K(ret));
} else if (root_udt_is_null) {
is_null = root_udt_is_null;
} else {
nested_udt_bitmap.get_pos()++;
// flattern all attribuites
for (int64_t i = 1; OB_SUCC(ret) && i < leaf_attr_count + 1; i++) {
if (OB_FAIL(sql_udt.access_attribute(i, attribute_data))) {
LOG_WARN("fail to access attribute buffer", K(ret));
} else {
temp_leaf_attrs[i - 1] = attribute_data;
}
}
// rearrange attributes to original order
for (int64_t i = 0; OB_SUCC(ret) && i < leaf_attr_count; i++) {
leaf_attrs[i] = temp_leaf_attrs[leaf_attrs_meta[i].order_];
}
}
}
if (OB_SUCC(ret)) {
attrs = leaf_attrs;
}
}
}
return ret;
}
int ObSqlUdtUtils::convert_sql_udt_to_string(ObObj &sql_udt_obj,
common::ObIAllocator *allocator,
sql::ObExecContext *exec_context,
ObSqlUDT &sql_udt,
ObString &res_str)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
ObSqlUDTMeta &udt_meta = sql_udt.get_udt_meta();
ObStringBuffer buf(allocator);
ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID());
ObString udt_data = sql_udt_obj.get_string();
ObSqlUdtNullBitMap nested_udt_bitmap;
bool is_null_record = false;
ObString *attrs = NULL;
if (udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) { // single varray
if (udt_meta.child_attr_cnt_ != 1) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("varray udt meta error", K(ret), K(udt_meta.child_attr_cnt_));
} else if (OB_FAIL(covert_sql_udt_varray_to_string(buf, udt_data, udt_meta))) {
LOG_WARN("failed to convert sql udt varray to string failed", K(ret));
}
} else { // record
if (OB_FAIL(rearrange_sql_udt_record(udt_data,
udt_meta,
&lob_allocator,
nested_udt_bitmap,
attrs,
is_null_record))) {
LOG_WARN("failed to rearrange sql udt record", K(ret));
} else if (OB_ISNULL(attrs) || is_null_record) {
if (OB_FAIL(buf.append("NULL"))) {
LOG_WARN("fail to print empty value", K(ret));
}
} else {
int64_t pos = 0;
if (OB_FAIL(convert_sql_udt_attributes_to_string(buf,
attrs,
pos,
exec_context,
udt_meta,
nested_udt_bitmap))) {
LOG_WARN("fail to convert sql udt attributes to string", K(ret));
} else if (pos != udt_meta.leaf_attr_cnt_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("leaf element count mismarch",
K(ret), K(pos), K(udt_meta.leaf_attr_cnt_));
}
}
}
if (OB_SUCC(ret)) {
res_str.assign_ptr(buf.ptr(), buf.length());
}
#endif
return ret;
}
int ObSqlUdtUtils::convert_collection_to_string(ObObj &coll_obj, const ObSqlCollectionInfo &coll_meta,
common::ObIAllocator *allocator, ObString &res_str)
{
int ret = OB_SUCCESS;
ObIArrayType *arr_obj = NULL;
ObString coll_data = coll_obj.get_string();
ObStringBuffer buf(allocator);
ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID());
ObCollectionArrayType *arr_type = static_cast<ObCollectionArrayType *>(coll_meta.collection_meta_);
if (OB_FAIL(ObTextStringHelper::read_real_string_data(&lob_allocator,
ObLongTextType,
CS_TYPE_BINARY,
true, coll_data))) {
LOG_WARN("fail to get real string data", K(ret), K(coll_data));
} else if (OB_FAIL(ObArrayTypeObjFactory::construct(*allocator, *arr_type, arr_obj, true))) {
LOG_WARN("construct array obj failed", K(ret), K(coll_meta));
} else {
if (OB_FAIL(arr_obj->init(coll_data))) {
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;
}
int ObSqlUdtUtils::cast_pl_varray_to_sql_varray(common::ObIAllocator &res_allocator,
ObString &res,
const ObObj root_obj,
bool with_lob_header)
{
int ret = OB_SUCCESS;
// for single varray
int64_t total_len = 0;
char *res_ptr = NULL;
int64_t pos = 0;
if (OB_FAIL(ob_udt_calc_sql_varray_length(&root_obj, total_len, with_lob_header))) {
LOG_WARN("Failed to calc sql varray length", K(ret), K(root_obj));
} else if (OB_ISNULL(res_ptr = static_cast<char *>(res_allocator.alloc(total_len)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate memory failed", K(ret), K(total_len));
} else if (OB_FAIL(ob_udt_convert_pl_varray_to_sql_varray(&root_obj, res_ptr, total_len, pos, with_lob_header))) {
LOG_WARN("convert pl varray to sql varray failed", K(ret), K(pos));
} else if (total_len != pos) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("covert single varray failed, length error", K(ret), K(total_len), K(pos));
} else {
res.assign_ptr(res_ptr, total_len);
}
return ret;
}
int ObSqlUdtUtils::cast_pl_record_to_sql_record(common::ObIAllocator &tmp_allocator,
common::ObIAllocator &res_allocator,
sql::ObExecContext *exec_ctx,
ObString &res,
ObSqlUDT &sql_udt,
const ObObj &root_obj)
{
int ret = OB_SUCCESS;
// root udt always has a nested udt bitmap, even if does not has any nested udt attributes
// the nested udt bitmap is a special attribute always at position 0
ObObj nested_udt_bitmap_obj;
nested_udt_bitmap_obj.set_type(ObHexStringType);
int32_t leaf_attr_count = sql_udt.get_udt_meta().leaf_attr_cnt_ + 1;
uint32_t nested_udt_count = sql_udt.get_udt_meta().nested_udt_number_ + 1;
uint32_t nested_udt_bitmap_len = ObSqlUDT::get_null_bitmap_len(nested_udt_count);
int64_t sql_udt_total_len = 0;
char * bitmap_buffer = reinterpret_cast<char *>(tmp_allocator.alloc(nested_udt_bitmap_len));
const ObObj **flattern_objs =
reinterpret_cast<const ObObj **>(tmp_allocator.alloc(sizeof(ObObj *) * (leaf_attr_count)));
const ObObj **sorted_objs =
reinterpret_cast<const ObObj **>(tmp_allocator.alloc(sizeof(ObObj *) * (leaf_attr_count)));
if (OB_ISNULL(flattern_objs) || OB_ISNULL(sorted_objs) || OB_ISNULL(bitmap_buffer)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc memory for pl extend cast to udt",
K(ret), KP(flattern_objs), KP(sorted_objs), KP(bitmap_buffer));
} else {
MEMSET(bitmap_buffer, 0, nested_udt_bitmap_len);
}
ObSqlUdtNullBitMap nested_udt_bitmap(bitmap_buffer, nested_udt_bitmap_len);
nested_udt_bitmap.get_pos()++; // first bit is used by root udt
int32_t pos = 1;
int32_t reorder_start_pos = 1;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ob_udt_flattern_pl_extend(flattern_objs, leaf_attr_count, pos,
nested_udt_bitmap, &root_obj,
*exec_ctx, sql_udt))) {
LOG_WARN("failed to flattern pl extend", K(ret), K(root_obj), K(leaf_attr_count));
} else if (OB_FAIL(ob_udt_reordering_leaf_objects(&flattern_objs[reorder_start_pos],
&sorted_objs[reorder_start_pos],
leaf_attr_count - reorder_start_pos,
sql_udt))) {
LOG_WARN("failed to reorder pl extend", K(ret), K(root_obj), K(leaf_attr_count));
} else if (OB_FAIL(ob_udt_build_nested_udt_bitmap_obj(nested_udt_bitmap_obj,
nested_udt_bitmap))) {
LOG_WARN("failed to build nested udt bitmap object", K(ret), K(root_obj), K(leaf_attr_count));
} else if (FALSE_IT(sorted_objs[0] = &nested_udt_bitmap_obj)) {
} else if (OB_FAIL(ob_udt_calc_total_len(sorted_objs,leaf_attr_count,
sql_udt_total_len, sql_udt))) {
LOG_WARN("failed to calc total sql udt len", K(ret), K(root_obj), K(leaf_attr_count));
} else if (sql_udt_total_len == 0) {
res.reset();
} else {
ObTextStringResult blob_res(ObLongTextType, true, &res_allocator);
char *buf = NULL;
int64_t buf_len = 0;
int64_t buf_pos = 0;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(blob_res.init(sql_udt_total_len))) {
LOG_WARN("failed to alloc temp lob", K(ret), K(sql_udt_total_len));
} else if (OB_FAIL(blob_res.get_reserved_buffer(buf, buf_len))) {
LOG_WARN("failed to reserve temp lob buffer", K(ret), K(sql_udt_total_len));
} else if (sql_udt_total_len != buf_len) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get reserve len is invalid", K(ret), K(sql_udt_total_len), K(buf_len));
} else if (OB_FAIL(ob_udt_convert_sorted_objs_array_to_udf_format(sorted_objs, buf,
buf_len, buf_pos, sql_udt))) {
LOG_WARN("faild to convert pl extend to sql udt", K(ret), K(sql_udt.get_udt_meta().udt_id_));
} else if (OB_FAIL(blob_res.lseek(buf_pos, 0))) {
LOG_WARN("temp lob lseek failed", K(ret), K(blob_res), K(buf_pos));
} else {
blob_res.get_result_buffer(res);
}
}
return ret;
}
int ObSqlUdtUtils::build_empty_record(sql::ObExecContext *exec_ctx, ObObj &result, uint64_t udt_id)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
if (OB_ISNULL(exec_ctx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(udt_id));
}
ObSQLSessionInfo *session = exec_ctx->get_my_session();
ObIAllocator &alloc = exec_ctx->get_allocator();
pl::ObPLPackageGuard package_guard(session->get_effective_tenant_id());
pl::ObPLResolveCtx resolve_ctx(alloc,
*session,
*(exec_ctx->get_sql_ctx()->schema_guard_),
package_guard,
*(exec_ctx->get_sql_proxy()),
false);
pl::ObPLINS *ns = NULL;
if (NULL == session->get_pl_context()) {
OZ (package_guard.init());
OX (ns = &resolve_ctx);
} else {
ns = session->get_pl_context()->get_current_ctx();
}
if (OB_SUCC(ret)) {
ObObj new_composite;
int64_t ptr = 0;
int64_t init_size = OB_INVALID_SIZE;
ObArenaAllocator tmp_alloc;
const pl::ObUserDefinedType *user_type = NULL;
OZ (ns->get_user_type(udt_id, user_type, &tmp_alloc));
CK (OB_NOT_NULL(user_type));
OZ (user_type->newx(alloc, ns, ptr));
OZ (user_type->get_size(pl::PL_TYPE_INIT_SIZE, init_size));
OX (new_composite.set_extend(ptr, user_type->get_type(), init_size));
OX (result = new_composite);
}
#endif
return ret;
}
int ObSqlUdtUtils::cast_sql_udt_varray_to_pl_varray(sql::ObExecContext *exec_ctx,
ObString &udt_varray_buf,
ObSqlUDTMeta &udt_meta,
ObObj &res_obj)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
ObSqlUDT varray_handler;
ObString varray_data = udt_varray_buf;
ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID());
if (OB_ISNULL(exec_ctx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(udt_meta));
} else if (OB_FAIL(ObTextStringHelper::read_real_string_data(&lob_allocator,
ObLongTextType,
CS_TYPE_BINARY,
true, varray_data))) {
LOG_WARN("fail to get real string data", K(ret), K(varray_data));
}
ObIAllocator &alloc = exec_ctx->get_allocator();
varray_handler.set_data(varray_data);
varray_handler.set_udt_meta(udt_meta);
if (OB_FAIL(ret)) {
} else if (varray_data.empty()) {
res_obj.set_null();
} else {
// alloc collection(varray) hander
common::ObDataType elem_type;
pl::ObElemDesc elem_desc;
pl::ObPLCollection *coll = NULL;
if (OB_ISNULL(coll = static_cast<pl::ObPLVArray*>(alloc.alloc(sizeof(pl::ObPLVArray) + 8)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate memory for pl collection", K(ret), K(coll));
} else {
coll = new(coll)pl::ObPLVArray(udt_meta.udt_id_);
static_cast<pl::ObPLVArray*>(coll)->set_capacity(udt_meta.varray_capacity_);
elem_type.set_meta_type(udt_meta.child_attrs_meta_[0].type_info_);
elem_desc.set_data_type(elem_type); // Notice: accuracty and others not setted
elem_desc.set_field_count(1); // varray with basic type elements, field count is 1.
coll->set_element_desc(elem_desc);
coll->set_not_null(false); // should from udt meta
}
ObObj *varray_objs = NULL;
uint64_t element_count = varray_handler.get_varray_element_count();
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObSPIService::spi_set_collection(0, NULL, alloc, *coll, element_count))) {
LOG_WARN("failed to allocate memory for pl collection", K(ret), K(coll));
} else if (OB_ISNULL(varray_objs = coll->get_data())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("varray data is null", K(ret));
}
ObString attr_data;
for (int64_t i = 0; OB_SUCC(ret) && i < element_count; i++) {
if (OB_FAIL(varray_handler.access_attribute(i, attr_data, true))) {
LOG_WARN("fail to access attribute buffer", K(ret));
} else if (attr_data.empty()) {
// do nothing, all element objs in varray is set null in spi_set_collection
} else {
ObObj obj;
obj.set_meta_type(varray_handler.get_udt_meta().child_attrs_meta_[0].type_info_);
int64_t pos = 0;
if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj,
attr_data.ptr(),
attr_data.length(),
pos))) {
LOG_WARN("failed to serialize object value", K(ret), K(attr_data));
} else if (OB_FAIL(deep_copy_obj(*coll->get_allocator(), obj, varray_objs[i]))){
LOG_WARN("failed to deep copy element object value", K(ret), K(obj), K(i));
}
}
}
// is nested varray needs add to pl ctx? may not needed for obobj cast
if (OB_SUCC(ret)) {
res_obj.set_extend(reinterpret_cast<int64_t>(coll), coll->get_type());
if (OB_NOT_NULL(coll->get_allocator())) {
if (OB_ISNULL(exec_ctx->get_pl_ctx())) {
if (OB_FAIL(exec_ctx->init_pl_ctx() || OB_ISNULL(exec_ctx->get_pl_ctx()))) {
LOG_ERROR("fail to init pl ctx", K(ret));
}
}
if (OB_SUCC(ret) && OB_FAIL(exec_ctx->get_pl_ctx()->add(res_obj))) {
LOG_ERROR("fail to collect pl collection allocator, may be exist memory issue", K(ret));
}
}
}
}
#endif
return ret;
}
int ObSqlUdtUtils::cast_sql_udt_attributes_to_pl_record(sql::ObExecContext *exec_ctx,
ObString *attrs,
int64_t &pos,
ObSqlUDTMeta &udt_meta,
ObSqlUdtNullBitMap &nest_udt_bitmap,
ObObj &res_obj)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
if (OB_ISNULL(exec_ctx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(udt_meta));
} else {
ObIAllocator &allocator = exec_ctx->get_allocator();
// null root is handled by the caller
uint32_t top_level_attr_count = udt_meta.child_attr_cnt_;
pl::ObPLRecord *record =
static_cast<pl::ObPLRecord*>(allocator.alloc(pl::ObRecordType::get_init_size(top_level_attr_count)));
if (OB_ISNULL(record)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc memory", K(ret));
} else {
new(record)pl::ObPLRecord(udt_meta.udt_id_, top_level_attr_count);
}
ObObj obj;
for (int64_t i = 0; OB_SUCC(ret) && i < top_level_attr_count; i++) {
obj.reset();
obj.set_meta_type(udt_meta.child_attrs_meta_[i].type_info_);
ObObjType type = obj.get_type();
bool is_udt_null = false;
bool is_nested_record = false;
if (type == ObUserDefinedSQLType || type == ObCollectionSQLType) {
const uint16_t subschema_id = obj.get_meta().get_subschema_id();
ObSqlUDTMeta sub_udt_meta;
// should be varray or record
if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(subschema_id, sub_udt_meta))) {
LOG_WARN("failed to get udt meta", K(ret), K(subschema_id));
}
if (OB_FAIL(ret)) {
} else if (nest_udt_bitmap.is_valid()
&& OB_FAIL(nest_udt_bitmap.check_current_bitmap_pos(is_udt_null))) {
LOG_WARN("failed to get nested udt null bit", K(ret));
} else if (sub_udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) {
if (is_udt_null) {
obj.set_null();
} else if (OB_FAIL(cast_sql_udt_varray_to_pl_varray(exec_ctx, attrs[pos], sub_udt_meta, obj))) {
LOG_WARN("failed to convert nested sql udt varray to pl extend",
K(ret), K(i), K(pos), K(subschema_id), K(sub_udt_meta.udt_id_));
}
} else if (sub_udt_meta.pl_type_ == pl::PL_RECORD_TYPE) {
if (is_udt_null) {
if (OB_FAIL(build_empty_record(exec_ctx, obj, sub_udt_meta.udt_id_))) {
LOG_WARN("failed to create empty nested udt record", K(ret));
} else {
pl::ObPLRecord *child_null_record = reinterpret_cast<pl::ObPLRecord *>(obj.get_ext());
child_null_record->set_null();
pos += sub_udt_meta.leaf_attr_cnt_;
// count the nested udt itself
nest_udt_bitmap.get_pos() += (sub_udt_meta.nested_udt_number_ + 1);
}
} else if (OB_FAIL(cast_sql_udt_attributes_to_pl_record(exec_ctx,
attrs,
pos,
sub_udt_meta,
nest_udt_bitmap,
obj))) {
LOG_WARN("failed to convert nestd sql udt record to pl extend", K(ret), K(sub_udt_meta.pl_type_));
}
is_nested_record = true;
// pos is changed inside;
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Unexpected type to convert sql udt to pl udt format", K(ret), K(sub_udt_meta.pl_type_));
}
} else { // basic types
int64_t buf_pos = 0;
if (OB_ISNULL(attrs[pos])) {
obj.set_null();
} else if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj,
attrs[pos].ptr(),
attrs[pos].length(),
buf_pos))) {
LOG_WARN("Failed to serialize object value", K(ret), K(attrs[pos]));
}
}
if (OB_SUCC(ret)){
pos += (is_nested_record ? 0 : 1);
if (type == ObUserDefinedSQLType || type == ObCollectionSQLType) {
obj.meta_.set_ext();
obj.meta_.set_extend_type(type == ObUserDefinedSQLType ? pl::PL_RECORD_TYPE : pl::PL_VARRAY_TYPE);
}
record->get_element()[i] = obj;
}
}
if (OB_SUCC(ret)) {
res_obj.set_extend(reinterpret_cast<int64_t>(record),
pl::PL_RECORD_TYPE, pl::ObRecordType::get_init_size(top_level_attr_count));
}
}
#endif
return ret;
}
int ObSqlUdtUtils::cast_sql_record_to_pl_record(sql::ObExecContext *exec_ctx,
ObObj &result,
ObString &udt_data,
ObSqlUDTMeta &udt_meta)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
if (udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) { // single varray
if (udt_meta.child_attr_cnt_ != 1) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("varray udt meta error", K(ret), K(udt_meta.child_attr_cnt_));
} else if (OB_FAIL(cast_sql_udt_varray_to_pl_varray(exec_ctx, udt_data, udt_meta, result))) {
LOG_WARN("failed to convert sql udt varray to pl varray", K(ret));
}
} else {
// udt meta already set
bool is_null_record = false;
ObSqlUdtNullBitMap nested_udt_bitmap;
ObString *attrs = NULL;
ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID());
if (OB_FAIL(rearrange_sql_udt_record(udt_data,
udt_meta,
&lob_allocator,
nested_udt_bitmap,
attrs,
is_null_record))) {
LOG_WARN("failed to rearrange sql udt record", K(ret));
} else if (OB_ISNULL(attrs) || is_null_record) {
result.set_null();
} else {
int64_t pos = 0;
if (OB_FAIL(cast_sql_udt_attributes_to_pl_record(exec_ctx,
attrs,
pos,
udt_meta,
nested_udt_bitmap,
result))) {
LOG_WARN("fail to cast sql udt record to pl record", K(ret));
} else if (pos != udt_meta.leaf_attr_cnt_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("leaf element count mismarch",
K(ret), K(pos), K(udt_meta.leaf_attr_cnt_));
}
}
}
#endif
return ret;
}
int ObSqlUdtUtils::get_sqludt_meta_by_subschema_id(sql::ObExecContext *exec_ctx,
const uint16_t subschema_id,
ObSqlUDTMeta &udt_meta) {
int ret = OB_SUCCESS;
if (OB_ISNULL(exec_ctx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(subschema_id));
} else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) {
LOG_WARN("failed to get udt meta", K(ret), K(subschema_id));
}
return ret;
}
int ObSqlUdtMetaUtils::get_udt_meta_attr_info(ObSchemaGetterGuard *schema_guard,
uint64_t tenant_id,
const ObUDTTypeInfo *parent_udt_info,
uint32_t &nested_udt_number,
common::ObIArray<ObUDTTypeAttr *> &leaf_attr_meta)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(schema_guard) || OB_ISNULL(parent_udt_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null schema guard or parent udt info", K(ret), KP(schema_guard), KP(parent_udt_info));
} else {
uint32_t count = parent_udt_info->get_attrs_count();
for (uint32_t i = 0; i < count; i++) {
ObUDTTypeAttr *udt_attr = parent_udt_info->get_attrs().at(i);
if (udt_attr->get_type_attr_id() < ObMaxType) {
if (OB_FAIL(leaf_attr_meta.push_back(udt_attr))) {
LOG_WARN("failed to push back leaf attr pointer", K(i), K(count), K(leaf_attr_meta.count()));
}
} else {
uint64_t udt_id = udt_attr->get_type_attr_id();
const ObUDTTypeInfo *attr_udt_info = NULL;
if (OB_FAIL(schema_guard->get_udt_info(tenant_id, udt_id, attr_udt_info))) {
// pl::get_tenant_id_by_object_id
LOG_WARN("failed to get udt info", K(ret), K(tenant_id), K(udt_id));
} else if (OB_ISNULL(attr_udt_info) ) { // try system udt
ret = OB_ERR_UNEXPECTED;
LOG_WARN("udt info not found", K(ret), K(tenant_id), K(udt_id));
} else if (OB_FAIL(get_udt_meta_attr_info(schema_guard,
tenant_id,
attr_udt_info,
nested_udt_number,
leaf_attr_meta))) {
LOG_WARN("failed to get nested udt meta attr info",
K(ret), K(tenant_id), K(parent_udt_info->get_type_id()), K(udt_id));
} else if (attr_udt_info->is_object_type()) {
nested_udt_number++;
} else if (attr_udt_info->is_varray()) { // varray is special to other udts, it is a basic type in sql
if (OB_FAIL(leaf_attr_meta.push_back(udt_attr))) {
LOG_WARN("failed to push back leaf attr pointer", K(i), K(count), K(leaf_attr_meta.count()));
}
}
}
}
}
return ret;
}
int ObSqlUdtMetaUtils::fill_udt_meta_attr_info(ObSchemaGetterGuard *schema_guard,
ObSubSchemaCtx *subschema_ctx,
uint64_t tenant_id,
const common::ObIArray<ObUDTTypeAttr *> &src,
ObSqlUDTAttrMeta *dst,
const uint32 dst_cnt,
bool is_leaf)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(dst)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null src or dest for udt type attr", K(src), KP(dst));
} else if (src.count() != dst_cnt) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("attr count mismarch", K(src), K(src.count()), K(dst_cnt));
} else {
for (int32_t i = 0; OB_SUCC(ret) && i < dst_cnt; i++) {
ObUDTTypeAttr *udt_attr = src.at(i);
ObSqlUDTAttrMeta *udt_attr_meta = &dst[i];
udt_attr_meta->order_ = i; // order of orignal leaf attributes
udt_attr_meta->type_info_.reset();
if (OB_ISNULL(udt_attr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null udt attribute", K(i), K(src.count()));
} else if (udt_attr->get_type_attr_id() < ObMaxType) {
udt_attr_meta->type_info_.set_type(static_cast<ObObjType>(udt_attr->get_type_attr_id()));
udt_attr_meta->type_info_.set_collation_type(static_cast<const ObCollationType>(udt_attr->get_coll_type()));
udt_attr_meta->type_info_.set_scale(static_cast<ObScale>(udt_attr->get_scale()));
} else { // udt attributes
const ObUDTTypeInfo *attr_udt_info = NULL;
uint64_t udt_id = udt_attr->get_type_attr_id();
if (OB_ISNULL(schema_guard)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null schema guard", K(ret));
} else if (OB_FAIL(schema_guard->get_udt_info(tenant_id, udt_id, attr_udt_info))) {
LOG_WARN("failed to get udt info", K(ret), K(tenant_id), K(udt_id));
} else if (OB_ISNULL(attr_udt_info) ) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("udt info not found", K(ret), K(tenant_id), K(udt_id));
} else if (attr_udt_info->is_object_type()) {
udt_attr_meta->type_info_.set_type(ObUserDefinedSQLType);
} else if (attr_udt_info->is_varray()) {
udt_attr_meta->type_info_.set_type(ObCollectionSQLType);
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported udt type", K(ret), K(*attr_udt_info));
}
uint16_t subschema_id = ObMaxSystemUDTSqlType;
if (OB_FAIL(ret)) {
} else if (is_leaf
&& udt_attr->get_type_attr_id() > ObMaxType
&& !attr_udt_info->is_varray()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected non-leaf attrs", K(ret), K(*udt_attr), K(i), K(src.count()));
} else if (OB_ISNULL(subschema_ctx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null subschema ctx", K(ret));
} else if (OB_FAIL(subschema_ctx->get_subschema_id(udt_id,
OB_SUBSCHEMA_UDT_TYPE,
subschema_id))) {
// ToDo: @gehao, refine
if (OB_HASH_NOT_EXIST != ret) {
LOG_WARN("failed to get subschema id by udt_id", K(ret), K(udt_id));
} else { // build new meta
ret = OB_SUCCESS;
uint16 new_subschema_id = ObMaxSystemUDTSqlType;
ObSqlUDTMeta *udt_meta = NULL;
ObSubSchemaValue value;
ObIAllocator &allocator = subschema_ctx->get_allocator();
if (OB_ISNULL(schema_guard)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("No schema gurad to generate udt_meta", K(ret), K(udt_id));
} else if (FALSE_IT(udt_meta = reinterpret_cast<ObSqlUDTMeta *>(allocator.alloc(sizeof(ObSqlUDTMeta))))) {
} else if (OB_ISNULL(udt_meta)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc udt meta", K(ret), K(udt_id), K(sizeof(ObSqlUDTMeta)));
} else if (FALSE_IT(MEMSET(udt_meta, 0, sizeof(ObSqlUDTMeta)))) {
} else if (OB_FAIL(ObSqlUdtMetaUtils::generate_udt_meta_from_schema(schema_guard,
subschema_ctx,
allocator, // use allocator in physical plan
tenant_id,
udt_id,
*udt_meta))) {
LOG_WARN("generate udt_meta failed", K(ret), K(tenant_id), K(udt_id));
} else if (OB_FAIL(subschema_ctx->get_subschema_id_from_fields(udt_id, new_subschema_id))) {
LOG_WARN("failed to get subschema id from result fields", K(ret), K(tenant_id), K(udt_id));
} else if (new_subschema_id == ObInvalidSqlType // not get from fields, generate new
&& OB_FAIL(subschema_ctx->get_new_subschema_id(new_subschema_id))) {
LOG_WARN("failed to get new subschema id", K(ret), K(tenant_id), K(udt_id));
} else {
value.type_ = OB_SUBSCHEMA_UDT_TYPE;
value.signature_ = udt_id;
value.value_ = static_cast<void *>(udt_meta);
if (OB_FAIL(subschema_ctx->set_subschema(new_subschema_id, value))) {
LOG_WARN("failed to set new subschema", K(ret), K(new_subschema_id), K(udt_id), K(value));
} else {
subschema_id = new_subschema_id;
udt_attr_meta->type_info_.set_subschema_id(subschema_id);
}
}
}
} else {
udt_attr_meta->type_info_.set_subschema_id(subschema_id);
}
if (OB_FAIL(ret)) {
} else if (udt_attr_meta->type_info_.is_collection_sql_type()) {
udt_attr_meta->type_info_.set_inrow();
} else if (is_lob_storage(udt_attr_meta->type_info_.get_type())) {
udt_attr_meta->type_info_.set_has_lob_header();
}
}
}
}
return ret;
}
int ObSqlUdtMetaUtils::generate_udt_meta_from_schema(ObSchemaGetterGuard *schema_guard,
ObSubSchemaCtx *subschema_ctx,
common::ObIAllocator &allocator,
uint64_t tenant_id,
uint64_t udt_id,
ObSqlUDTMeta &udt_meta)
{
int ret = OB_SUCCESS;
#ifndef OB_BUILD_ORACLE_PL
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ret));
#else
const ObUDTTypeInfo *root_udt_info = NULL;
ObSEArray<ObUDTTypeAttr *, 4> temp_leaf_attr_meta;
uint32_t child_attrs_cnt = 0;
uint32_t leaf_attrs_cnt = 0;
uint32_t fixed_len_attr_cnt = 0;
uint32_t fixed_attr_cnt = 0; // not used leaf an empty interface
int32_t fixed_offset_ = 0;
int32_t pl_type = 0;
uint32_t nested_udt_number = 0;
uint32_t varray_capacity = 0;
ObString type_name;
if (is_inner_pl_object_id(udt_id)) {
tenant_id = OB_SYS_TENANT_ID;
}
if (OB_ISNULL(schema_guard)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null schema guard", K(ret));
} else if (OB_FAIL(schema_guard->get_udt_info(tenant_id, udt_id, root_udt_info))) {
// pl::get_tenant_id_by_object_id
LOG_WARN("failed to get udt info", K(ret), K(tenant_id), K(udt_id));
} else if (OB_ISNULL(root_udt_info) ) { // try system udt
ret = OB_ERR_UNEXPECTED;
LOG_WARN("udt info not found", K(ret), K(tenant_id), K(udt_id));
} else if (root_udt_info->get_type_name().empty()) { // copy name
ret = OB_ERR_UNEXPECTED;
LOG_WARN("udt info without name", K(ret), K(tenant_id), K(udt_id));
} else if (OB_FAIL(ob_write_string(allocator, root_udt_info->get_type_name(), type_name))) {
LOG_WARN("failed to copy udt name", K(ret), K(tenant_id), K(udt_id));
} else {
udt_meta.set_name(type_name);
udt_meta.udt_id_ = udt_id;
if (root_udt_info->is_object_type()) {
pl_type = static_cast<int32_t>(pl::PL_RECORD_TYPE);
child_attrs_cnt = root_udt_info->get_attributes();
} else if (root_udt_info->is_varray()) {
pl_type = static_cast<int32_t>(pl::PL_VARRAY_TYPE);
if (OB_NOT_NULL(root_udt_info->get_coll_info())) {
varray_capacity = root_udt_info->get_coll_info()->get_upper_bound();
}
child_attrs_cnt = 1;
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported udt type", K(ret), K(*root_udt_info));
}
if (OB_SUCC(ret)) {
udt_meta.varray_capacity_ = varray_capacity;
udt_meta.pl_type_ = pl_type;
udt_meta.child_attr_cnt_ = child_attrs_cnt;
if (OB_FAIL(get_udt_meta_attr_info(schema_guard,
tenant_id,
root_udt_info,
nested_udt_number,
temp_leaf_attr_meta))) {
LOG_WARN("failed to fill udt meta info");
} else {
leaf_attrs_cnt = temp_leaf_attr_meta.count();
udt_meta.nested_udt_number_ = nested_udt_number;
udt_meta.leaf_attr_cnt_ = leaf_attrs_cnt;
udt_meta.attribute_cnt_ = leaf_attrs_cnt;
udt_meta.fixed_attr_cnt_ = fixed_attr_cnt;
udt_meta.fixed_offset_ = fixed_offset_;
udt_meta.child_attrs_meta_ = NULL;
udt_meta.leaf_attrs_meta_ = NULL;
ObSqlUDTAttrMeta *leaf_attrs_meta = NULL;
uint32_t child_attrs_size = sizeof(ObSqlUDTAttrMeta) * child_attrs_cnt;
ObSqlUDTAttrMeta *child_attrs_meta
= reinterpret_cast<ObSqlUDTAttrMeta *>(allocator.alloc(child_attrs_size));
if (child_attrs_cnt > 0 && OB_ISNULL(child_attrs_meta)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate memory for child attrs failed",
K(ret), K(child_attrs_cnt), K(child_attrs_size));
} else if (root_udt_info->is_varray()) {
if (child_attrs_cnt != 1) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("error child attribute count for varray", K(ret), K(child_attrs_cnt));
} else {
ObObjType elem_type = static_cast<ObObjType>(root_udt_info->get_coll_info()->get_elem_type_id());
ObCollationType coll_type = static_cast<const ObCollationType>(
root_udt_info->get_coll_info()->get_coll_type());
child_attrs_meta->order_ = 0;
child_attrs_meta->type_info_.set_type(elem_type);
// child_attrs_meta->type_info_.set_collation_level(CS_LEVEL_IMPLICIT); // setted in set_type
child_attrs_meta->type_info_.set_collation_type(coll_type);
child_attrs_meta->type_info_.set_scale(static_cast<ObScale>(root_udt_info->get_coll_info()->get_scale()));
udt_meta.child_attrs_meta_ = child_attrs_meta;
}
} else if (OB_FAIL(fill_udt_meta_attr_info(schema_guard,
subschema_ctx,
tenant_id,
root_udt_info->get_attrs(),
child_attrs_meta,
child_attrs_cnt,
false))) { // record type
LOG_WARN("failed to fill udt meta attr info", K(ret), K(child_attrs_cnt), K(*root_udt_info));
} else {
udt_meta.child_attrs_meta_ = child_attrs_meta;
}
uint32_t leaf_attrs_size = sizeof(ObSqlUDTAttrMeta) * leaf_attrs_cnt;
if (OB_FAIL(ret) || leaf_attrs_cnt == 0) {
} else if (FALSE_IT(leaf_attrs_meta = reinterpret_cast<ObSqlUDTAttrMeta *>(
allocator.alloc(leaf_attrs_size)))) {
} else if (OB_ISNULL(leaf_attrs_meta)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate memory failed for leaf attrs failed",
K(ret), K(leaf_attrs_cnt), K(leaf_attrs_size));
} else if (OB_FAIL(fill_udt_meta_attr_info(schema_guard,
subschema_ctx,
tenant_id,
temp_leaf_attr_meta,
leaf_attrs_meta,
leaf_attrs_cnt,
true))) {
LOG_WARN("failed to fill udt meta attr info",
K(ret), K(leaf_attrs_cnt), K(temp_leaf_attr_meta));
} else {
udt_meta.leaf_attrs_meta_ = leaf_attrs_meta;
}
}
}
}
#endif
return ret;
}
}
}