| /* |
| * 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/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 list_type = std::dynamic_pointer_cast<arrow::ListType>(type); |
| assert(list_type); |
| auto value_type = list_type->value_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 = std::dynamic_pointer_cast<arrow::MapType>(type); |
| assert(map_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 = std::dynamic_pointer_cast<arrow::StructType>(type); |
| assert(struct_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::DECIMAL && |
| 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 = arrow::internal::checked_pointer_cast<arrow::TimestampType>(type); |
| assert(timestamp_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::DECIMAL: { |
| auto* decimal_type = arrow::internal::checked_cast<arrow::Decimal128Type*>(type.get()); |
| assert(decimal_type); |
| 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: { |
| 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 |