| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| #include "paimon/common/data/serializer/binary_serializer_utils.h" | |
| #include "paimon/common/data/binary_array_writer.h" | |
| #include "paimon/common/data/binary_row_writer.h" | |
| #include "paimon/common/utils/checked_cast.h" | |
| #include "paimon/common/utils/date_time_utils.h" | |
| namespace paimon { | |
| Result<std::shared_ptr<BinaryArray>> BinarySerializerUtils::WriteBinaryArray( | |
| const std::shared_ptr<InternalArray>& value, const std::shared_ptr<arrow::DataType>& type, | |
| MemoryPool* pool) { | |
| if (auto binary_array = std::dynamic_pointer_cast<BinaryArray>(value)) { | |
| return binary_array; | |
| } | |
| auto binary_array = std::make_shared<BinaryArray>(); | |
| auto value_type = type->field(0)->type(); | |
| // TODO(xinyu.lxy): reuse BinaryWriter | |
| BinaryArrayWriter binary_writer(binary_array.get(), value->Size(), | |
| BinaryArrayWriter::GetElementSize(value_type->id()), pool); | |
| for (int32_t i = 0; i < value->Size(); i++) { | |
| PAIMON_RETURN_NOT_OK(WriteBinaryData(value_type, value.get(), i, &binary_writer, pool)); | |
| } | |
| binary_writer.Complete(); | |
| return binary_array; | |
| } | |
| Result<std::shared_ptr<BinaryMap>> BinarySerializerUtils::WriteBinaryMap( | |
| const std::shared_ptr<InternalMap>& value, const std::shared_ptr<arrow::DataType>& type, | |
| MemoryPool* pool) { | |
| if (auto binary_map = std::dynamic_pointer_cast<BinaryMap>(value)) { | |
| return binary_map; | |
| } | |
| auto map_type = checked_pointer_cast<arrow::MapType>(type); | |
| auto key_type = map_type->key_type(); | |
| auto value_type = map_type->item_type(); | |
| auto key_array = value->KeyArray(); | |
| auto value_array = value->ValueArray(); | |
| assert(key_array && value_array); | |
| assert(key_array->Size() == value_array->Size()); | |
| BinaryArray binary_key_array; | |
| BinaryArrayWriter binary_key_writer(&binary_key_array, key_array->Size(), | |
| BinaryArrayWriter::GetElementSize(key_type->id()), pool); | |
| BinaryArray binary_value_array; | |
| BinaryArrayWriter binary_value_writer(&binary_value_array, value_array->Size(), | |
| BinaryArrayWriter::GetElementSize(value_type->id()), | |
| pool); | |
| for (int32_t i = 0; i < key_array->Size(); i++) { | |
| PAIMON_RETURN_NOT_OK( | |
| WriteBinaryData(key_type, key_array.get(), i, &binary_key_writer, pool)); | |
| PAIMON_RETURN_NOT_OK( | |
| WriteBinaryData(value_type, value_array.get(), i, &binary_value_writer, pool)); | |
| } | |
| binary_key_writer.Complete(); | |
| binary_value_writer.Complete(); | |
| return BinaryMap::ValueOf(binary_key_array, binary_value_array, pool); | |
| } | |
| Result<std::shared_ptr<BinaryRow>> BinarySerializerUtils::WriteBinaryRow( | |
| const std::shared_ptr<InternalRow>& value, const std::shared_ptr<arrow::DataType>& type, | |
| MemoryPool* pool) { | |
| if (auto binary_row = std::dynamic_pointer_cast<BinaryRow>(value)) { | |
| return binary_row; | |
| } | |
| auto struct_type = checked_pointer_cast<arrow::StructType>(type); | |
| auto field_count = struct_type->num_fields(); | |
| auto binary_row = std::make_shared<BinaryRow>(field_count); | |
| BinaryRowWriter binary_writer(binary_row.get(), /*initial_size=*/1024, pool); | |
| for (int32_t i = 0; i < field_count; i++) { | |
| PAIMON_RETURN_NOT_OK( | |
| WriteBinaryData(struct_type->field(i)->type(), value.get(), i, &binary_writer, pool)); | |
| } | |
| binary_writer.Complete(); | |
| return binary_row; | |
| } | |
| Status BinarySerializerUtils::WriteBinaryData(const std::shared_ptr<arrow::DataType>& type, | |
| const DataGetters* getter, int32_t pos, | |
| BinaryWriter* writer, MemoryPool* pool) { | |
| assert(getter && writer && pool); | |
| arrow::Type::type type_id = type->id(); | |
| auto array_writer = dynamic_cast<BinaryArrayWriter*>(writer); | |
| if (getter->IsNullAt(pos)) { | |
| // compatible with Java Paimon | |
| if (array_writer) { | |
| array_writer->SetNullAt(pos, type_id); | |
| return Status::OK(); | |
| } else if (type_id != arrow::Type::type::DECIMAL128 && | |
| type_id != arrow::Type::type::TIMESTAMP) { | |
| // if row writer, exclude decimal and timestamp when set null | |
| writer->SetNullAt(pos); | |
| return Status::OK(); | |
| } | |
| } | |
| switch (type_id) { | |
| case arrow::Type::type::BOOL: { | |
| writer->WriteBoolean(pos, getter->GetBoolean(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::INT8: { | |
| writer->WriteByte(pos, getter->GetByte(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::INT16: { | |
| writer->WriteShort(pos, getter->GetShort(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::DATE32: { | |
| writer->WriteInt(pos, getter->GetDate(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::INT32: { | |
| writer->WriteInt(pos, getter->GetInt(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::INT64: { | |
| writer->WriteLong(pos, getter->GetLong(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::FLOAT: { | |
| writer->WriteFloat(pos, getter->GetFloat(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::DOUBLE: { | |
| writer->WriteDouble(pos, getter->GetDouble(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::STRING: { | |
| writer->WriteStringView(pos, getter->GetStringView(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::BINARY: { | |
| writer->WriteStringView(pos, getter->GetStringView(pos)); | |
| break; | |
| } | |
| case arrow::Type::type::TIMESTAMP: { | |
| auto timestamp_type = checked_pointer_cast<arrow::TimestampType>(type); | |
| int32_t precision = DateTimeUtils::GetPrecisionFromType(timestamp_type); | |
| if (getter->IsNullAt(pos)) { | |
| // compatible with Java Paimon | |
| if (!Timestamp::IsCompact(precision)) { | |
| writer->WriteTimestamp(pos, std::nullopt, precision); | |
| } else { | |
| writer->SetNullAt(pos); | |
| } | |
| } else { | |
| writer->WriteTimestamp(pos, getter->GetTimestamp(pos, precision), precision); | |
| } | |
| break; | |
| } | |
| case arrow::Type::type::DECIMAL128: { | |
| auto* decimal_type = checked_cast<arrow::Decimal128Type*>(type.get()); | |
| auto precision = decimal_type->precision(); | |
| auto scale = decimal_type->scale(); | |
| if (getter->IsNullAt(pos)) { | |
| // compatible with Java Paimon | |
| if (!Decimal::IsCompact(precision)) { | |
| writer->WriteDecimal(pos, std::nullopt, precision); | |
| } else { | |
| writer->SetNullAt(pos); | |
| } | |
| } else { | |
| writer->WriteDecimal(pos, getter->GetDecimal(pos, precision, scale), precision); | |
| } | |
| break; | |
| } | |
| case arrow::Type::type::LIST: | |
| case arrow::Type::type::FIXED_SIZE_LIST: { | |
| auto internal_array = getter->GetArray(pos); | |
| PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<BinaryArray> binary_array, | |
| WriteBinaryArray(internal_array, type, pool)); | |
| writer->WriteArray(pos, *binary_array); | |
| break; | |
| } | |
| case arrow::Type::type::MAP: { | |
| auto internal_map = getter->GetMap(pos); | |
| PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<BinaryMap> binary_map, | |
| WriteBinaryMap(internal_map, type, pool)); | |
| writer->WriteMap(pos, *binary_map); | |
| break; | |
| } | |
| case arrow::Type::type::STRUCT: { | |
| auto internal_row = getter->GetRow(pos, type->num_fields()); | |
| PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<BinaryRow> binary_row, | |
| WriteBinaryRow(internal_row, type, pool)); | |
| writer->WriteRow(pos, *binary_row); | |
| break; | |
| } | |
| default: | |
| return Status::Invalid( | |
| fmt::format("type {} not support in WriteBinaryData in binary serializer utils", | |
| type->ToString())); | |
| } | |
| return Status::OK(); | |
| } | |
| } // namespace paimon |