| /* | |
| * 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/binary_row_writer.h" | |
| #include <string> | |
| #include <string_view> | |
| #include <variant> | |
| #include "arrow/type_fwd.h" | |
| #include "gtest/gtest.h" | |
| #include "paimon/common/data/binary_array.h" | |
| #include "paimon/common/data/binary_map.h" | |
| #include "paimon/common/data/binary_string.h" | |
| #include "paimon/common/data/internal_row.h" | |
| #include "paimon/common/utils/date_time_utils.h" | |
| #include "paimon/data/decimal.h" | |
| #include "paimon/data/timestamp.h" | |
| #include "paimon/memory/bytes.h" | |
| #include "paimon/memory/memory_pool.h" | |
| #include "paimon/status.h" | |
| #include "paimon/testing/utils/binary_row_generator.h" | |
| #include "paimon/testing/utils/testharness.h" | |
| namespace paimon::test { | |
| TEST(BinaryRowWriterTest, TestFieldSetter) { | |
| int32_t arity = 24; | |
| BinaryRow row(arity); | |
| BinaryRowWriter writer(&row, /*initial_size=*/0, GetDefaultPool().get()); | |
| writer.Reset(); | |
| auto pool = GetDefaultPool(); | |
| // set process | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter0, | |
| BinaryRowWriter::CreateFieldSetter(0, arrow::boolean())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter1, | |
| BinaryRowWriter::CreateFieldSetter(1, arrow::int8())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter2, | |
| BinaryRowWriter::CreateFieldSetter(2, arrow::int16())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter3, | |
| BinaryRowWriter::CreateFieldSetter(3, arrow::int32())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter4, | |
| BinaryRowWriter::CreateFieldSetter(4, arrow::int64())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter5, | |
| BinaryRowWriter::CreateFieldSetter(5, arrow::float32())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter6, | |
| BinaryRowWriter::CreateFieldSetter(6, arrow::float64())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter7, | |
| BinaryRowWriter::CreateFieldSetter(7, arrow::utf8())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter8, | |
| BinaryRowWriter::CreateFieldSetter(8, arrow::binary())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter9, | |
| BinaryRowWriter::CreateFieldSetter(9, arrow::date32())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter10, | |
| BinaryRowWriter::CreateFieldSetter(10, arrow::decimal128(5, 2))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter11, | |
| BinaryRowWriter::CreateFieldSetter(11, arrow::timestamp(arrow::TimeUnit::NANO))); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter12, | |
| BinaryRowWriter::CreateFieldSetter(12, arrow::utf8())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter13, | |
| BinaryRowWriter::CreateFieldSetter(13, arrow::binary())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter14, | |
| BinaryRowWriter::CreateFieldSetter(14, arrow::decimal128(37, 2))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter15, | |
| BinaryRowWriter::CreateFieldSetter(15, arrow::timestamp(arrow::TimeUnit::NANO))); | |
| // for timestamp type | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter16, | |
| BinaryRowWriter::CreateFieldSetter(16, arrow::timestamp(arrow::TimeUnit::SECOND))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter17, | |
| BinaryRowWriter::CreateFieldSetter(17, arrow::timestamp(arrow::TimeUnit::MILLI))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter18, | |
| BinaryRowWriter::CreateFieldSetter(18, arrow::timestamp(arrow::TimeUnit::MICRO))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter19, | |
| BinaryRowWriter::CreateFieldSetter(19, arrow::timestamp(arrow::TimeUnit::NANO))); | |
| auto timezone = DateTimeUtils::GetLocalTimezoneName(); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter20, | |
| BinaryRowWriter::CreateFieldSetter( | |
| 20, arrow::timestamp(arrow::TimeUnit::SECOND, timezone))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter21, | |
| BinaryRowWriter::CreateFieldSetter(21, arrow::timestamp(arrow::TimeUnit::MILLI, timezone))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter22, | |
| BinaryRowWriter::CreateFieldSetter(22, arrow::timestamp(arrow::TimeUnit::MICRO, timezone))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter23, | |
| BinaryRowWriter::CreateFieldSetter(23, arrow::timestamp(arrow::TimeUnit::NANO, timezone))); | |
| setter0(true, &writer); | |
| setter1(static_cast<char>(1), &writer); | |
| setter2(static_cast<int16_t>(2), &writer); | |
| setter3(static_cast<int32_t>(3), &writer); | |
| setter4(static_cast<int64_t>(4), &writer); | |
| setter5(static_cast<float>(5.5), &writer); | |
| setter6(6.66, &writer); | |
| std::string data = "abc"; | |
| setter7(std::string_view(data.data(), data.size()), &writer); | |
| setter8(std::string_view(data.data(), data.size()), &writer); | |
| setter9(9, &writer); | |
| setter10(Decimal(5, 2, 123), &writer); | |
| setter11(Timestamp(11, 12), &writer); | |
| setter12(BinaryString::FromString("hello", pool.get()), &writer); | |
| auto bytes = std::make_shared<Bytes>("world", pool.get()); | |
| setter13(bytes, &writer); | |
| setter14(NullType(), &writer); | |
| setter15(NullType(), &writer); | |
| setter16(Timestamp(1758030901000l, 0), &writer); | |
| setter17(Timestamp(1758030901001l, 0), &writer); | |
| setter18(NullType(), &writer); | |
| setter19(Timestamp(1758030901001l, 1001), &writer); | |
| setter20(NullType(), &writer); | |
| setter21(Timestamp(1758030902002l, 0), &writer); | |
| setter22(Timestamp(1758030902002l, 2000), &writer); | |
| setter23(Timestamp(1758030902002l, 2002), &writer); | |
| writer.Complete(); | |
| // get process | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter0, | |
| InternalRow::CreateFieldGetter(0, arrow::boolean(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter1, | |
| InternalRow::CreateFieldGetter(1, arrow::int8(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter2, | |
| InternalRow::CreateFieldGetter(2, arrow::int16(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter3, | |
| InternalRow::CreateFieldGetter(3, arrow::int32(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter4, | |
| InternalRow::CreateFieldGetter(4, arrow::int64(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter5, | |
| InternalRow::CreateFieldGetter(5, arrow::float32(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter6, | |
| InternalRow::CreateFieldGetter(6, arrow::float64(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter7, | |
| InternalRow::CreateFieldGetter(7, arrow::utf8(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter8, | |
| InternalRow::CreateFieldGetter(8, arrow::binary(), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter9, | |
| InternalRow::CreateFieldGetter(9, arrow::date32(), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN( | |
| InternalRow::FieldGetterFunc getter10, | |
| InternalRow::CreateFieldGetter(10, arrow::decimal128(5, 2), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter11, | |
| InternalRow::CreateFieldGetter(11, arrow::timestamp(arrow::TimeUnit::NANO), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter12, | |
| InternalRow::CreateFieldGetter(12, arrow::utf8(), /*use_view=*/false)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter13, | |
| InternalRow::CreateFieldGetter(13, arrow::binary(), | |
| /*use_view=*/false)); | |
| ASSERT_OK_AND_ASSIGN( | |
| InternalRow::FieldGetterFunc getter14, | |
| InternalRow::CreateFieldGetter(14, arrow::decimal128(37, 2), /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter15, | |
| InternalRow::CreateFieldGetter(15, arrow::timestamp(arrow::TimeUnit::NANO), | |
| /*use_view=*/true)); | |
| // for timestamp type | |
| ASSERT_OK_AND_ASSIGN( | |
| InternalRow::FieldGetterFunc getter16, | |
| InternalRow::CreateFieldGetter(16, arrow::timestamp(arrow::TimeUnit::SECOND), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN( | |
| InternalRow::FieldGetterFunc getter17, | |
| InternalRow::CreateFieldGetter(17, arrow::timestamp(arrow::TimeUnit::MILLI), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN( | |
| InternalRow::FieldGetterFunc getter18, | |
| InternalRow::CreateFieldGetter(18, arrow::timestamp(arrow::TimeUnit::MICRO), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter19, | |
| InternalRow::CreateFieldGetter(19, arrow::timestamp(arrow::TimeUnit::NANO), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN( | |
| InternalRow::FieldGetterFunc getter20, | |
| InternalRow::CreateFieldGetter(20, arrow::timestamp(arrow::TimeUnit::SECOND), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN( | |
| InternalRow::FieldGetterFunc getter21, | |
| InternalRow::CreateFieldGetter(21, arrow::timestamp(arrow::TimeUnit::MILLI), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN( | |
| InternalRow::FieldGetterFunc getter22, | |
| InternalRow::CreateFieldGetter(22, arrow::timestamp(arrow::TimeUnit::MICRO), | |
| /*use_view=*/true)); | |
| ASSERT_OK_AND_ASSIGN(InternalRow::FieldGetterFunc getter23, | |
| InternalRow::CreateFieldGetter(23, arrow::timestamp(arrow::TimeUnit::NANO), | |
| /*use_view=*/true)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<bool>(getter0(row)), true); | |
| ASSERT_EQ(DataDefine::GetVariantValue<char>(getter1(row)), static_cast<char>(1)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<int16_t>(getter2(row)), static_cast<int16_t>(2)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<int32_t>(getter3(row)), static_cast<int32_t>(3)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<int64_t>(getter4(row)), static_cast<int64_t>(4)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<float>(getter5(row)), static_cast<float>(5.5)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<double>(getter6(row)), static_cast<double>(6.66)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<std::string_view>(getter7(row)), std::string_view(data)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<std::string_view>(getter8(row)), std::string_view(data)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<int32_t>(getter9(row)), 9); | |
| ASSERT_EQ(DataDefine::GetVariantValue<Decimal>(getter10(row)), Decimal(5, 2, 123)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<Timestamp>(getter11(row)), Timestamp(11, 12)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<BinaryString>(getter12(row)).ToString(), "hello"); | |
| ASSERT_EQ(*DataDefine::GetVariantValue<std::shared_ptr<Bytes>>(getter13(row)), | |
| Bytes("world", pool.get())); | |
| ASSERT_TRUE(DataDefine::IsVariantNull(getter14(row))); | |
| ASSERT_TRUE(DataDefine::IsVariantNull(getter15(row))); | |
| ASSERT_EQ(DataDefine::GetVariantValue<Timestamp>(getter16(row)), Timestamp(1758030901000l, 0)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<Timestamp>(getter17(row)), Timestamp(1758030901001l, 0)); | |
| ASSERT_TRUE(DataDefine::IsVariantNull(getter18(row))); | |
| ASSERT_EQ(DataDefine::GetVariantValue<Timestamp>(getter19(row)), | |
| Timestamp(1758030901001l, 1001)); | |
| ASSERT_TRUE(DataDefine::IsVariantNull(getter20(row))); | |
| ASSERT_EQ(DataDefine::GetVariantValue<Timestamp>(getter21(row)), Timestamp(1758030902002l, 0)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<Timestamp>(getter22(row)), | |
| Timestamp(1758030902002l, 2000)); | |
| ASSERT_EQ(DataDefine::GetVariantValue<Timestamp>(getter23(row)), | |
| Timestamp(1758030902002l, 2002)); | |
| } | |
| TEST(BinaryRowWriterTest, TestFieldSetterWithNull) { | |
| int32_t arity = 5; | |
| BinaryRow row(arity); | |
| BinaryRowWriter writer(&row, /*initial_size=*/0, GetDefaultPool().get()); | |
| writer.Reset(); | |
| auto timezone = DateTimeUtils::GetLocalTimezoneName(); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter0, | |
| BinaryRowWriter::CreateFieldSetter(0, arrow::boolean())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter1, | |
| BinaryRowWriter::CreateFieldSetter(1, arrow::int8())); | |
| ASSERT_OK_AND_ASSIGN(BinaryRowWriter::FieldSetterFunc setter2, | |
| BinaryRowWriter::CreateFieldSetter(2, arrow::decimal128(5, 2))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter3, | |
| BinaryRowWriter::CreateFieldSetter(3, arrow::timestamp(arrow::TimeUnit::SECOND))); | |
| ASSERT_OK_AND_ASSIGN( | |
| BinaryRowWriter::FieldSetterFunc setter4, | |
| BinaryRowWriter::CreateFieldSetter(4, arrow::timestamp(arrow::TimeUnit::NANO, timezone))); | |
| setter0(true, &writer); | |
| setter1(NullType(), &writer); | |
| setter2(NullType(), &writer); | |
| setter3(NullType(), &writer); | |
| setter4(NullType(), &writer); | |
| writer.Complete(); | |
| ASSERT_EQ(row.GetBoolean(0), true); | |
| ASSERT_TRUE(row.IsNullAt(1)); | |
| ASSERT_TRUE(row.IsNullAt(2)); | |
| ASSERT_TRUE(row.IsNullAt(3)); | |
| ASSERT_TRUE(row.IsNullAt(4)); | |
| } | |
| TEST(BinaryRowWriterTest, TestWriteNested) { | |
| auto pool = GetDefaultPool(); | |
| BinaryRow inner_row = | |
| BinaryRowGenerator::GenerateRow({std::string("Alice"), 30, 12.1, NullType()}, pool.get()); | |
| BinaryArray inner_array = BinaryArray::FromIntArray({10, 20, 30}, pool.get()); | |
| auto key = BinaryArray::FromIntArray({1, 2, 3, 5}, pool.get()); | |
| auto value = BinaryArray::FromLongArray({100ll, 200ll, 300ll, 500ll}, pool.get()); | |
| auto inner_map = BinaryMap::ValueOf(key, value, pool.get()); | |
| BinaryRow row(3); | |
| BinaryRowWriter writer(&row, /*initial_size=*/1024, pool.get()); | |
| writer.WriteRow(0, inner_row); | |
| writer.WriteArray(1, inner_array); | |
| writer.WriteMap(2, *inner_map); | |
| writer.Complete(); | |
| ASSERT_EQ(3, row.GetFieldCount()); | |
| ASSERT_FALSE(row.IsNullAt(0)); | |
| auto de_row = row.GetRow(0, 4); | |
| ASSERT_EQ(std::dynamic_pointer_cast<BinaryRow>(de_row)->HashCode(), inner_row.HashCode()); | |
| ASSERT_EQ(4, de_row->GetFieldCount()); | |
| ASSERT_EQ(de_row->GetString(0).ToString(), "Alice"); | |
| ASSERT_EQ(de_row->GetInt(1), 30); | |
| ASSERT_EQ(de_row->GetDouble(2), 12.1); | |
| ASSERT_TRUE(de_row->IsNullAt(3)); | |
| auto de_array = row.GetArray(1); | |
| ASSERT_EQ(std::dynamic_pointer_cast<BinaryArray>(de_array)->HashCode(), inner_array.HashCode()); | |
| ASSERT_EQ(de_array->ToIntArray().value(), std::vector<int32_t>({10, 20, 30})); | |
| auto de_map = row.GetMap(2); | |
| ASSERT_EQ(std::dynamic_pointer_cast<BinaryArray>(de_map->KeyArray())->HashCode(), | |
| key.HashCode()); | |
| ASSERT_EQ(std::dynamic_pointer_cast<BinaryArray>(de_map->ValueArray())->HashCode(), | |
| value.HashCode()); | |
| ASSERT_EQ(de_map->KeyArray()->ToIntArray().value(), std::vector<int32_t>({1, 2, 3, 5})); | |
| ASSERT_EQ(de_map->ValueArray()->ToLongArray().value(), | |
| std::vector<int64_t>({100ll, 200ll, 300ll, 500ll})); | |
| } | |
| } // namespace paimon::test |