|
20 | 20 |
|
21 | 21 | #include <algorithm> |
22 | 22 | #include <cstdint> |
| 23 | +#include <cstring> |
23 | 24 | #include <map> |
24 | 25 | #include <optional> |
25 | 26 | #include <string> |
@@ -61,7 +62,7 @@ class AppendBucketPruningTest : public testing::Test { |
61 | 62 | const std::shared_ptr<Predicate>& predicate, |
62 | 63 | const std::optional<int32_t>& bucket = std::nullopt) const { |
63 | 64 | auto arrow_schema = DataField::ConvertDataFieldsToArrowSchema( |
64 | | - {DataField(0, arrow::field("rowkey", arrow::utf8())), |
| 65 | + {DataField(0, arrow::field("rowkey", rowkey_type_)), |
65 | 66 | DataField(1, arrow::field("value", arrow::int32()))}); |
66 | 67 | PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<TableSchema> schema, |
67 | 68 | TableSchema::Create(schema_id_, arrow_schema, {}, {}, options_)); |
@@ -101,6 +102,33 @@ class AppendBucketPruningTest : public testing::Test { |
101 | 102 | Literal(FieldType::STRING, "key", 3)); |
102 | 103 | } |
103 | 104 |
|
| 105 | + template <typename T> |
| 106 | + void CheckMatchingValue(FieldType field_type, const T& query_value, const T& stored_value) { |
| 107 | + options_[Options::BUCKET] = "17"; |
| 108 | + auto predicate = PredicateBuilder::Equal(0, "rowkey", field_type, Literal(query_value)); |
| 109 | + ASSERT_OK_AND_ASSIGN(auto comparison, |
| 110 | + Literal(query_value).CompareTo(Literal(stored_value))); |
| 111 | + ASSERT_EQ(comparison, 0); |
| 112 | + BinaryRow stored_key = BinaryRowGenerator::GenerateRow({stored_value}, pool_.get()); |
| 113 | + BinaryRow query_key = BinaryRowGenerator::GenerateRow({query_value}, pool_.get()); |
| 114 | + int32_t bucket = DefaultBucketFunction().Bucket(stored_key, 17); |
| 115 | + ASSERT_NE(bucket, DefaultBucketFunction().Bucket(query_key, 17)); |
| 116 | + SimpleStats stats = BinaryRowGenerator::GenerateStats( |
| 117 | + {stored_value, 0}, {stored_value, 100}, {0, 0}, pool_.get()); |
| 118 | + ASSERT_OK_AND_ASSIGN( |
| 119 | + auto file, |
| 120 | + DataFileMeta::ForAppend("data.parquet", 100, 10, stats, 0, 9, 0, std::nullopt, |
| 121 | + std::nullopt, std::nullopt, std::nullopt, std::nullopt)); |
| 122 | + ManifestEntry entry(FileKind::Add(), BinaryRow::EmptyRow(), bucket, 17, file); |
| 123 | + ASSERT_OK_AND_ASSIGN(auto stats_scan, CreateScan(predicate, bucket)); |
| 124 | + ASSERT_OK_AND_ASSIGN(bool stats_match, stats_scan->FilterByStats(entry)); |
| 125 | + ASSERT_TRUE(stats_match); |
| 126 | + ASSERT_OK_AND_ASSIGN(auto scan, CreateScan(predicate)); |
| 127 | + ASSERT_OK_AND_ASSIGN(bool keep, scan->FilterManifestEntry(entry)); |
| 128 | + ASSERT_TRUE(keep); |
| 129 | + } |
| 130 | + |
| 131 | + std::shared_ptr<arrow::DataType> rowkey_type_ = arrow::utf8(); |
104 | 132 | static constexpr int32_t kNumBuckets = 4; |
105 | 133 | int64_t schema_id_ = 0; |
106 | 134 | std::shared_ptr<SchemaManager> schema_manager_; |
@@ -149,6 +177,23 @@ TEST_F(AppendBucketPruningTest, DoesNotPruneDifferentSchema) { |
149 | 177 | CheckBuckets(KeyEquals(), std::nullopt); |
150 | 178 | } |
151 | 179 |
|
| 180 | +TEST_F(AppendBucketPruningTest, PreservesCrossScaleDecimalMatch) { |
| 181 | + rowkey_type_ = arrow::decimal128(10, 2); |
| 182 | + CheckMatchingValue(FieldType::DECIMAL, Decimal::FromUnscaledLong(12, 10, 1), |
| 183 | + Decimal::FromUnscaledLong(120, 10, 2)); |
| 184 | +} |
| 185 | + |
| 186 | +TEST_F(AppendBucketPruningTest, PreservesDifferentNaNPayloadMatch) { |
| 187 | + rowkey_type_ = arrow::float64(); |
| 188 | + uint64_t query_bits = 0x7ff8000000000000ULL; |
| 189 | + uint64_t stored_bits = 0x7ff8000000000001ULL; |
| 190 | + double query_value; |
| 191 | + double stored_value; |
| 192 | + std::memcpy(&query_value, &query_bits, sizeof(query_value)); |
| 193 | + std::memcpy(&stored_value, &stored_bits, sizeof(stored_value)); |
| 194 | + CheckMatchingValue(FieldType::DOUBLE, query_value, stored_value); |
| 195 | +} |
| 196 | + |
152 | 197 | TEST(AppendOnlyFileStoreScanTest, TestReconstructPredicateWithNonCastedFields) { |
153 | 198 | std::string table_root = |
154 | 199 | paimon::test::GetDataDir() + |
|
0 commit comments