|
| 1 | +/* |
| 2 | + * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | + * or more contributor license agreements. See the NOTICE file |
| 4 | + * distributed with this work for additional information |
| 5 | + * regarding copyright ownership. The ASF licenses this file |
| 6 | + * to you under the Apache License, Version 2.0 (the |
| 7 | + * "License"); you may not use this file except in compliance |
| 8 | + * with the License. You may obtain a copy of the License at |
| 9 | + * |
| 10 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | + * |
| 12 | + * Unless required by applicable law or agreed to in writing, |
| 13 | + * software distributed under the License is distributed on an |
| 14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | + * KIND, either express or implied. See the License for the |
| 16 | + * specific language governing permissions and limitations |
| 17 | + * under the License. |
| 18 | + */ |
| 19 | + |
| 20 | +#include "paimon/common/data/generic_array.h" |
| 21 | + |
| 22 | +#include <cstdint> |
| 23 | +#include <limits> |
| 24 | +#include <memory> |
| 25 | +#include <string> |
| 26 | +#include <string_view> |
| 27 | +#include <vector> |
| 28 | + |
| 29 | +#include "gtest/gtest.h" |
| 30 | +#include "paimon/common/data/binary_string.h" |
| 31 | +#include "paimon/common/data/generic_map.h" |
| 32 | +#include "paimon/common/data/generic_row.h" |
| 33 | +#include "paimon/data/decimal.h" |
| 34 | +#include "paimon/data/timestamp.h" |
| 35 | +#include "paimon/memory/bytes.h" |
| 36 | +#include "paimon/memory/memory_pool.h" |
| 37 | +#include "paimon/testing/utils/testharness.h" |
| 38 | + |
| 39 | +namespace paimon::test { |
| 40 | + |
| 41 | +TEST(GenericArrayTest, TestGetters) { |
| 42 | + const Decimal decimal(/*precision=*/10, /*scale=*/2, 12345); |
| 43 | + const Timestamp timestamp(/*millisecond=*/1234, /*nano_of_millisecond=*/567890); |
| 44 | + std::shared_ptr<InternalArray> nested_array = |
| 45 | + std::make_shared<GenericArray>(std::vector<VariantType>{int32_t{42}}); |
| 46 | + std::shared_ptr<InternalMap> map = std::make_shared<GenericMap>(nested_array, nested_array); |
| 47 | + auto row = std::make_shared<GenericRow>(1); |
| 48 | + row->SetField(0, int32_t{7}); |
| 49 | + GenericArray array({true, false, char{42}, int16_t{-1234}, int32_t{-56789}, |
| 50 | + int64_t{12345678900}, -1.5F, 2.25, decimal, timestamp, nested_array, map, |
| 51 | + std::shared_ptr<InternalRow>(row), NullType{}}); |
| 52 | + |
| 53 | + ASSERT_EQ(array.Size(), 14); |
| 54 | + for (int32_t i = 0; i < array.Size() - 1; ++i) { |
| 55 | + ASSERT_FALSE(array.IsNullAt(i)) << i; |
| 56 | + } |
| 57 | + ASSERT_TRUE(array.IsNullAt(13)); |
| 58 | + ASSERT_TRUE(array.GetBoolean(0)); |
| 59 | + ASSERT_FALSE(array.GetBoolean(1)); |
| 60 | + ASSERT_EQ(array.GetByte(2), char{42}); |
| 61 | + ASSERT_EQ(array.GetShort(3), -1234); |
| 62 | + ASSERT_EQ(array.GetInt(4), -56789); |
| 63 | + ASSERT_EQ(array.GetDate(4), -56789); |
| 64 | + ASSERT_EQ(array.GetLong(5), int64_t{12345678900}); |
| 65 | + ASSERT_FLOAT_EQ(array.GetFloat(6), -1.5F); |
| 66 | + ASSERT_DOUBLE_EQ(array.GetDouble(7), 2.25); |
| 67 | + ASSERT_EQ(array.GetDecimal(8, /*precision=*/10, /*scale=*/2), decimal); |
| 68 | + ASSERT_EQ(array.GetTimestamp(9, /*precision=*/9), timestamp); |
| 69 | + ASSERT_EQ(array.GetArray(10), nested_array); |
| 70 | + ASSERT_EQ(array.GetArray(10)->GetInt(0), 42); |
| 71 | + ASSERT_EQ(array.GetMap(11), map); |
| 72 | + ASSERT_EQ(array.GetMap(11)->ValueArray()->GetInt(0), 42); |
| 73 | + ASSERT_EQ(array.GetRow(12, /*num_fields=*/1), row); |
| 74 | + ASSERT_EQ(array.GetRow(12, /*num_fields=*/1)->GetInt(0), 7); |
| 75 | +} |
| 76 | + |
| 77 | +TEST(GenericArrayTest, TestStringAndBinaryRepresentations) { |
| 78 | + auto pool = GetDefaultPool(); |
| 79 | + for (const std::string& value : |
| 80 | + {std::string(), std::string("hello world"), std::string("a\0b", 3)}) { |
| 81 | + SCOPED_TRACE(value); |
| 82 | + BinaryString string = BinaryString::FromString(value, pool.get()); |
| 83 | + std::shared_ptr<Bytes> bytes = Bytes::AllocateBytes(value, pool.get()); |
| 84 | + GenericArray array({string, bytes, std::string_view(value)}); |
| 85 | + |
| 86 | + ASSERT_EQ(array.Size(), 3); |
| 87 | + for (int32_t i = 0; i < array.Size(); ++i) { |
| 88 | + ASSERT_FALSE(array.IsNullAt(i)); |
| 89 | + ASSERT_EQ(array.GetString(i).ToString(), value) << i; |
| 90 | + ASSERT_EQ(array.GetStringView(i), value) << i; |
| 91 | + auto result = array.GetBinary(i); |
| 92 | + ASSERT_TRUE(result); |
| 93 | + ASSERT_EQ(*result, *bytes) << i; |
| 94 | + } |
| 95 | + ASSERT_EQ(array.GetBinary(1), bytes); |
| 96 | + ASSERT_EQ(array.GetStringView(2).data(), value.data()); |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +TEST(GenericArrayTest, TestHoldersKeepBorrowedValuesAlive) { |
| 101 | + auto pool = GetDefaultPool(); |
| 102 | + const std::string string_value = "string owned by the source array"; |
| 103 | + const std::string binary_value("binary\0value", 12); |
| 104 | + std::weak_ptr<InternalArray> source_ref; |
| 105 | + std::unique_ptr<GenericArray> array; |
| 106 | + { |
| 107 | + std::shared_ptr<Bytes> bytes = Bytes::AllocateBytes(binary_value, pool.get()); |
| 108 | + auto source = std::make_shared<GenericArray>( |
| 109 | + std::vector<VariantType>{BinaryString::FromString(string_value, pool.get()), bytes}); |
| 110 | + source_ref = source; |
| 111 | + array = std::make_unique<GenericArray>( |
| 112 | + std::vector<VariantType>{source->GetStringView(0), source->GetStringView(1)}, |
| 113 | + std::vector<std::shared_ptr<InternalArray>>{source}); |
| 114 | + } |
| 115 | + |
| 116 | + ASSERT_FALSE(source_ref.expired()); |
| 117 | + ASSERT_EQ(array->GetStringView(0), string_value); |
| 118 | + ASSERT_EQ(array->GetString(0).ToString(), string_value); |
| 119 | + auto bytes = array->GetBinary(1); |
| 120 | + ASSERT_TRUE(bytes); |
| 121 | + ASSERT_EQ(std::string(bytes->data(), bytes->size()), binary_value); |
| 122 | + array.reset(); |
| 123 | + ASSERT_TRUE(source_ref.expired()); |
| 124 | + ASSERT_EQ(std::string(bytes->data(), bytes->size()), binary_value); |
| 125 | +} |
| 126 | + |
| 127 | +TEST(GenericArrayTest, TestToPrimitiveArrays) { |
| 128 | + { |
| 129 | + GenericArray array({true, false, true}); |
| 130 | + ASSERT_OK_AND_ASSIGN(std::vector<char> result, array.ToBooleanArray()); |
| 131 | + ASSERT_EQ(result, (std::vector<char>{1, 0, 1})); |
| 132 | + } |
| 133 | + { |
| 134 | + GenericArray array({char{0}, char{42}, std::numeric_limits<char>::max()}); |
| 135 | + ASSERT_OK_AND_ASSIGN(std::vector<char> result, array.ToByteArray()); |
| 136 | + ASSERT_EQ(result, (std::vector<char>{0, 42, std::numeric_limits<char>::max()})); |
| 137 | + } |
| 138 | + { |
| 139 | + GenericArray array( |
| 140 | + {std::numeric_limits<int16_t>::min(), int16_t{0}, std::numeric_limits<int16_t>::max()}); |
| 141 | + ASSERT_OK_AND_ASSIGN(std::vector<int16_t> result, array.ToShortArray()); |
| 142 | + ASSERT_EQ(result, (std::vector<int16_t>{std::numeric_limits<int16_t>::min(), 0, |
| 143 | + std::numeric_limits<int16_t>::max()})); |
| 144 | + } |
| 145 | + { |
| 146 | + GenericArray array( |
| 147 | + {std::numeric_limits<int32_t>::min(), int32_t{0}, std::numeric_limits<int32_t>::max()}); |
| 148 | + ASSERT_OK_AND_ASSIGN(std::vector<int32_t> result, array.ToIntArray()); |
| 149 | + ASSERT_EQ(result, (std::vector<int32_t>{std::numeric_limits<int32_t>::min(), 0, |
| 150 | + std::numeric_limits<int32_t>::max()})); |
| 151 | + } |
| 152 | + { |
| 153 | + GenericArray array( |
| 154 | + {std::numeric_limits<int64_t>::min(), int64_t{0}, std::numeric_limits<int64_t>::max()}); |
| 155 | + ASSERT_OK_AND_ASSIGN(std::vector<int64_t> result, array.ToLongArray()); |
| 156 | + ASSERT_EQ(result, (std::vector<int64_t>{std::numeric_limits<int64_t>::min(), 0, |
| 157 | + std::numeric_limits<int64_t>::max()})); |
| 158 | + } |
| 159 | + { |
| 160 | + GenericArray array({-1.5F, 0.0F, 2.25F}); |
| 161 | + ASSERT_OK_AND_ASSIGN(std::vector<float> result, array.ToFloatArray()); |
| 162 | + ASSERT_EQ(result, (std::vector<float>{-1.5F, 0.0F, 2.25F})); |
| 163 | + } |
| 164 | + { |
| 165 | + GenericArray array({-1.5, 0.0, 2.25}); |
| 166 | + ASSERT_OK_AND_ASSIGN(std::vector<double> result, array.ToDoubleArray()); |
| 167 | + ASSERT_EQ(result, (std::vector<double>{-1.5, 0.0, 2.25})); |
| 168 | + } |
| 169 | +} |
| 170 | + |
| 171 | +TEST(GenericArrayTest, TestEmptyArray) { |
| 172 | + GenericArray array({}); |
| 173 | + ASSERT_EQ(array.Size(), 0); |
| 174 | + ASSERT_OK_AND_ASSIGN(std::vector<char> booleans, array.ToBooleanArray()); |
| 175 | + ASSERT_TRUE(booleans.empty()); |
| 176 | + ASSERT_OK_AND_ASSIGN(std::vector<char> bytes, array.ToByteArray()); |
| 177 | + ASSERT_TRUE(bytes.empty()); |
| 178 | + ASSERT_OK_AND_ASSIGN(std::vector<int16_t> shorts, array.ToShortArray()); |
| 179 | + ASSERT_TRUE(shorts.empty()); |
| 180 | + ASSERT_OK_AND_ASSIGN(std::vector<int32_t> ints, array.ToIntArray()); |
| 181 | + ASSERT_TRUE(ints.empty()); |
| 182 | + ASSERT_OK_AND_ASSIGN(std::vector<int64_t> longs, array.ToLongArray()); |
| 183 | + ASSERT_TRUE(longs.empty()); |
| 184 | + ASSERT_OK_AND_ASSIGN(std::vector<float> floats, array.ToFloatArray()); |
| 185 | + ASSERT_TRUE(floats.empty()); |
| 186 | + ASSERT_OK_AND_ASSIGN(std::vector<double> doubles, array.ToDoubleArray()); |
| 187 | + ASSERT_TRUE(doubles.empty()); |
| 188 | +} |
| 189 | + |
| 190 | +TEST(GenericArrayTest, TestPrimitiveArraysRejectNulls) { |
| 191 | + GenericArray null_array({NullType{}}); |
| 192 | + ASSERT_TRUE(null_array.IsNullAt(0)); |
| 193 | + const std::string message = "Primitive array must not contain a null value."; |
| 194 | + ASSERT_NOK_WITH_MSG(null_array.ToBooleanArray(), message); |
| 195 | + ASSERT_NOK_WITH_MSG(null_array.ToByteArray(), message); |
| 196 | + ASSERT_NOK_WITH_MSG(null_array.ToShortArray(), message); |
| 197 | + ASSERT_NOK_WITH_MSG(null_array.ToIntArray(), message); |
| 198 | + ASSERT_NOK_WITH_MSG(null_array.ToLongArray(), message); |
| 199 | + ASSERT_NOK_WITH_MSG(null_array.ToFloatArray(), message); |
| 200 | + ASSERT_NOK_WITH_MSG(null_array.ToDoubleArray(), message); |
| 201 | + |
| 202 | + GenericArray booleans({true, NullType{}, false}); |
| 203 | + ASSERT_NOK_WITH_MSG(booleans.ToBooleanArray(), message); |
| 204 | + GenericArray ints({int32_t{1}, NullType{}, int32_t{2}}); |
| 205 | + ASSERT_NOK_WITH_MSG(ints.ToIntArray(), message); |
| 206 | +} |
| 207 | + |
| 208 | +} // namespace paimon::test |
0 commit comments