Skip to content

Commit 23a87fa

Browse files
authored
feat(blob view): support multi-thread reading upstream table & add inte test (#341)
1 parent 21b5fac commit 23a87fa

87 files changed

Lines changed: 1128 additions & 254 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

include/paimon/catalog/catalog.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ class PAIMON_EXPORT Catalog {
169169
/// @note This does not check whether the table actually exists.
170170
///
171171
/// @param identifier The table identifier containing database and table name.
172-
/// @return A string representing the expected location of the table.
173-
virtual std::string GetTableLocation(const Identifier& identifier) const = 0;
172+
/// @return A result containing the expected location of the table, or an error status on
173+
/// failure.
174+
virtual Result<std::string> GetTableLocation(const Identifier& identifier) const = 0;
174175

175176
/// Returns the root path of the catalog.
176177
///

include/paimon/defs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,13 @@ struct PAIMON_EXPORT Options {
390390
/// "blob-external-storage-path" - The external storage path where raw BLOB data from fields
391391
/// configured by 'blob-external-storage-field' is written at write time. Orphan file cleanup is
392392
/// not applied to this path. No default value.
393+
/// @note: this option differs from the Java paimon and will be deprecated once
394+
/// RestCatalog is supported.
393395
static const char BLOB_EXTERNAL_STORAGE_PATH[];
396+
/// "blob-view-upstream-warehouse" - Since the catalog capabilities are partially missing, when
397+
/// Blob View is enabled, cpp paimon cannot automatically obtain the upstream table warehouse
398+
/// path and requires manual configuration by the user. No default value.
399+
static const char BLOB_VIEW_UPSTREAM_WAREHOUSE[];
394400
/// "global-index.enabled" - Whether to enable global index for scan. Default value is "true".
395401
static const char GLOBAL_INDEX_ENABLED[];
396402
/// "global-index.thread-num" - The maximum number of concurrent scanner for global index. No

include/paimon/executor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ class PAIMON_EXPORT Executor {
5454

5555
/// Shutdown the executor immediately, discarding all pending tasks.
5656
virtual void ShutdownNow() = 0;
57+
58+
/// Get thread number.
59+
virtual uint32_t GetThreadNum() const = 0;
5760
};
5861

5962
} // namespace paimon

src/paimon/common/data/blob_utils.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "fmt/format.h"
2727
#include "paimon/common/data/blob_defs.h"
2828
#include "paimon/common/data/blob_descriptor.h"
29+
#include "paimon/common/data/blob_view_struct.h"
2930
#include "paimon/common/types/data_field.h"
3031
#include "paimon/common/utils/arrow/status_utils.h"
3132
#include "paimon/common/utils/string_utils.h"
@@ -127,16 +128,18 @@ std::shared_ptr<arrow::Field> BlobUtils::ToArrowField(
127128
std::make_shared<arrow::KeyValueMetadata>(metadata));
128129
}
129130

130-
Status BlobUtils::ValidateInlineBlobDescriptors(
131-
const std::shared_ptr<arrow::StructArray>& struct_array,
132-
const std::set<std::string>& inline_descriptor_fields) {
133-
if (inline_descriptor_fields.empty()) {
131+
Status BlobUtils::ValidateBlobInlineFields(const std::shared_ptr<arrow::StructArray>& struct_array,
132+
const std::set<std::string>& field_names,
133+
const std::string& config_label) {
134+
if (field_names.empty()) {
134135
return Status::OK();
135136
}
136137
if (!struct_array) {
137-
return Status::Invalid("array in ValidateInlineBlobDescriptors must be a struct_array");
138+
return Status::Invalid("array in ValidateBlobInlineFields must be a struct_array");
138139
}
139-
for (const auto& field_name : inline_descriptor_fields) {
140+
141+
bool is_descriptor = (config_label == "blob-descriptor-field");
142+
for (const auto& field_name : field_names) {
140143
auto field_array = struct_array->GetFieldByName(field_name);
141144
if (!field_array) {
142145
continue;
@@ -152,12 +155,13 @@ Status BlobUtils::ValidateInlineBlobDescriptors(
152155
continue;
153156
}
154157
auto value = binary_array->GetView(row);
155-
PAIMON_ASSIGN_OR_RAISE(bool is_descriptor,
156-
BlobDescriptor::IsBlobDescriptor(value.data(), value.size()));
157-
if (!is_descriptor) {
158+
Result<bool> valid = is_descriptor
159+
? BlobDescriptor::IsBlobDescriptor(value.data(), value.size())
160+
: BlobViewStruct::IsBlobViewStruct(value.data(), value.size());
161+
PAIMON_ASSIGN_OR_RAISE(bool is_valid, std::move(valid));
162+
if (!is_valid) {
158163
return Status::Invalid(fmt::format(
159-
"BLOB inline field {} configured by blob-descriptor-field or blob-view-field "
160-
"require values to be a BlobDescriptor or BlobViewStruct.",
164+
"BLOB inline field {} require values to be set as corresponding type.",
161165
field_name));
162166
}
163167
}

src/paimon/common/data/blob_utils.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ class PAIMON_EXPORT BlobUtils {
7676
const std::string& field_name, bool nullable = false,
7777
std::unordered_map<std::string, std::string> metadata = {});
7878

79-
static Status ValidateInlineBlobDescriptors(
80-
const std::shared_ptr<arrow::StructArray>& struct_array,
81-
const std::set<std::string>& inline_descriptor_fields);
79+
static Status ValidateBlobInlineFields(const std::shared_ptr<arrow::StructArray>& struct_array,
80+
const std::set<std::string>& field_names,
81+
const std::string& config_label);
8282

8383
/// Converts inline blob DataFields from large_binary to binary type.
8484
/// Inline blob fields use large_binary in the table schema (because they are BLOB type),

src/paimon/common/data/blob_utils_test.cpp

Lines changed: 102 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
#include "arrow/api.h"
2020
#include "arrow/c/bridge.h"
2121
#include "gtest/gtest.h"
22+
#include "paimon/catalog/identifier.h"
2223
#include "paimon/common/data/blob_defs.h"
2324
#include "paimon/common/data/blob_descriptor.h"
25+
#include "paimon/common/data/blob_view_struct.h"
2426
#include "paimon/common/types/data_field.h"
2527
#include "paimon/data/blob.h"
2628
#include "paimon/memory/memory_pool.h"
@@ -29,44 +31,47 @@
2931
namespace paimon::test {
3032

3133
class BlobUtilsTest : public ::testing::Test {
32-
private:
34+
public:
3335
std::shared_ptr<arrow::KeyValueMetadata> CreateBlobMetadata() {
3436
std::unordered_map<std::string, std::string> blob_metadata_map = {
3537
{BlobDefs::kExtensionTypeKey, BlobDefs::kExtensionTypeValue}};
3638
return std::make_shared<arrow::KeyValueMetadata>(blob_metadata_map);
3739
}
40+
41+
private:
42+
std::shared_ptr<MemoryPool> pool_ = GetDefaultPool();
3843
};
3944

4045
TEST_F(BlobUtilsTest, IsBlobMetadata) {
4146
auto correct_metadata = CreateBlobMetadata();
42-
EXPECT_TRUE(BlobUtils::IsBlobMetadata(correct_metadata));
43-
EXPECT_FALSE(BlobUtils::IsBlobMetadata(nullptr));
47+
ASSERT_TRUE(BlobUtils::IsBlobMetadata(correct_metadata));
48+
ASSERT_FALSE(BlobUtils::IsBlobMetadata(nullptr));
4449
std::unordered_map<std::string, std::string> wrong_metadata_map = {
4550
{BlobDefs::kExtensionTypeKey, "paimon.type.varchar"}};
4651
auto wrong_metadata = std::make_shared<arrow::KeyValueMetadata>(wrong_metadata_map);
47-
EXPECT_FALSE(BlobUtils::IsBlobMetadata(wrong_metadata));
52+
ASSERT_FALSE(BlobUtils::IsBlobMetadata(wrong_metadata));
4853
std::unordered_map<std::string, std::string> no_extension_metadata_map = {
4954
{"other_key", BlobDefs::kExtensionTypeValue}};
5055
auto no_extension_metadata =
5156
std::make_shared<arrow::KeyValueMetadata>(no_extension_metadata_map);
52-
EXPECT_FALSE(BlobUtils::IsBlobMetadata(no_extension_metadata));
57+
ASSERT_FALSE(BlobUtils::IsBlobMetadata(no_extension_metadata));
5358
}
5459

5560
TEST_F(BlobUtilsTest, IsBlobField) {
5661
std::shared_ptr<arrow::Field> blob_field = BlobUtils::ToArrowField("f1", true);
57-
EXPECT_TRUE(BlobUtils::IsBlobField(blob_field));
62+
ASSERT_TRUE(BlobUtils::IsBlobField(blob_field));
5863

5964
auto int_field = arrow::field("i_int", arrow::int32());
60-
EXPECT_FALSE(BlobUtils::IsBlobField(int_field));
65+
ASSERT_FALSE(BlobUtils::IsBlobField(int_field));
6166

6267
auto binary_field_no_meta = arrow::field("b_no_meta", arrow::large_binary());
63-
EXPECT_FALSE(BlobUtils::IsBlobField(binary_field_no_meta));
68+
ASSERT_FALSE(BlobUtils::IsBlobField(binary_field_no_meta));
6469

6570
auto wrong_meta = std::make_shared<arrow::KeyValueMetadata>(
6671
std::unordered_map<std::string, std::string>{{"other_key", "value"}});
6772
auto binary_field_wrong_meta =
6873
arrow::field("b_wrong_meta", arrow::large_binary(), false, wrong_meta);
69-
EXPECT_FALSE(BlobUtils::IsBlobField(binary_field_wrong_meta));
74+
ASSERT_FALSE(BlobUtils::IsBlobField(binary_field_wrong_meta));
7075
}
7176

7277
TEST_F(BlobUtilsTest, SeparateBlobSchema) {
@@ -233,7 +238,7 @@ TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsEmptyFields) {
233238
auto struct_array =
234239
arrow::StructArray::Make({array}, {BlobUtils::ToArrowField("b0")}).ValueOrDie();
235240
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
236-
ASSERT_OK(BlobUtils::ValidateInlineBlobDescriptors(sa, {}));
241+
ASSERT_OK(BlobUtils::ValidateBlobInlineFields(sa, {}, "blob-descriptor-field"));
237242
}
238243

239244
TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsFieldNotPresent) {
@@ -245,22 +250,21 @@ TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsFieldNotPresent) {
245250
arrow::StructArray::Make({int_array}, {arrow::field("f0", arrow::int32())}).ValueOrDie();
246251
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
247252
// "b0" does not exist in the struct -> should pass
248-
ASSERT_OK(BlobUtils::ValidateInlineBlobDescriptors(sa, {"b0"}));
253+
ASSERT_OK(BlobUtils::ValidateBlobInlineFields(sa, {"b0"}, "blob-descriptor-field"));
249254
}
250255

251256
TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsWithValidDescriptor) {
252257
// Valid BlobDescriptor bytes -> OK
253-
auto pool = GetDefaultPool();
254258
ASSERT_OK_AND_ASSIGN(auto descriptor, BlobDescriptor::Create("file:///tmp/test.bin", 0, 100));
255-
auto serialized = descriptor->Serialize(pool);
259+
auto serialized = descriptor->Serialize(pool_);
256260

257261
arrow::LargeBinaryBuilder builder;
258262
ASSERT_TRUE(builder.Append(serialized->data(), serialized->size()).ok());
259263
auto blob_array = builder.Finish().ValueOrDie();
260264
auto struct_array =
261265
arrow::StructArray::Make({blob_array}, {BlobUtils::ToArrowField("b0")}).ValueOrDie();
262266
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
263-
ASSERT_OK(BlobUtils::ValidateInlineBlobDescriptors(sa, {"b0"}));
267+
ASSERT_OK(BlobUtils::ValidateBlobInlineFields(sa, {"b0"}, "blob-descriptor-field"));
264268
}
265269

266270
TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsWithNullValue) {
@@ -271,7 +275,7 @@ TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsWithNullValue) {
271275
auto struct_array =
272276
arrow::StructArray::Make({blob_array}, {BlobUtils::ToArrowField("b0")}).ValueOrDie();
273277
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
274-
ASSERT_OK(BlobUtils::ValidateInlineBlobDescriptors(sa, {"b0"}));
278+
ASSERT_OK(BlobUtils::ValidateBlobInlineFields(sa, {"b0"}, "blob-descriptor-field"));
275279
}
276280

277281
TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsWithRawBytes) {
@@ -282,36 +286,29 @@ TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsWithRawBytes) {
282286
auto struct_array =
283287
arrow::StructArray::Make({blob_array}, {BlobUtils::ToArrowField("b0")}).ValueOrDie();
284288
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
285-
ASSERT_NOK_WITH_MSG(
286-
BlobUtils::ValidateInlineBlobDescriptors(sa, {"b0"}),
287-
"BLOB inline field b0 configured by blob-descriptor-field or blob-view-field "
288-
"require values to be a BlobDescriptor or BlobViewStruct.");
289+
ASSERT_NOK_WITH_MSG(BlobUtils::ValidateBlobInlineFields(sa, {"b0"}, "blob-descriptor-field"),
290+
"BLOB inline field b0 require values to be set as corresponding type.");
289291
}
290292

291293
TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsMixedValidAndInvalid) {
292294
// First row is valid descriptor, second row is raw bytes -> error on row 1
293-
auto pool = GetDefaultPool();
294295
ASSERT_OK_AND_ASSIGN(auto descriptor, BlobDescriptor::Create("file:///tmp/test.bin", 0, 100));
295-
auto serialized = descriptor->Serialize(pool);
296-
296+
auto serialized = descriptor->Serialize(pool_);
297297
arrow::LargeBinaryBuilder builder;
298298
ASSERT_TRUE(builder.Append(serialized->data(), serialized->size()).ok());
299299
ASSERT_TRUE(builder.Append("raw_bytes_not_descriptor").ok());
300300
auto blob_array = builder.Finish().ValueOrDie();
301301
auto struct_array =
302302
arrow::StructArray::Make({blob_array}, {BlobUtils::ToArrowField("b0")}).ValueOrDie();
303303
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
304-
ASSERT_NOK_WITH_MSG(
305-
BlobUtils::ValidateInlineBlobDescriptors(sa, {"b0"}),
306-
"BLOB inline field b0 configured by blob-descriptor-field or blob-view-field "
307-
"require values to be a BlobDescriptor or BlobViewStruct.");
304+
ASSERT_NOK_WITH_MSG(BlobUtils::ValidateBlobInlineFields(sa, {"b0"}, "blob-descriptor-field"),
305+
"BLOB inline field b0 require values to be set as corresponding type.");
308306
}
309307

310308
TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsMultipleFields) {
311309
// Two inline fields: b0 is valid, b1 has raw bytes -> error on b1
312-
auto pool = GetDefaultPool();
313310
ASSERT_OK_AND_ASSIGN(auto descriptor, BlobDescriptor::Create("file:///tmp/test.bin", 0, 100));
314-
auto serialized = descriptor->Serialize(pool);
311+
auto serialized = descriptor->Serialize(pool_);
315312

316313
arrow::LargeBinaryBuilder b0_builder;
317314
ASSERT_TRUE(b0_builder.Append(serialized->data(), serialized->size()).ok());
@@ -327,9 +324,83 @@ TEST_F(BlobUtilsTest, ValidateInlineBlobDescriptorsMultipleFields) {
327324
.ValueOrDie();
328325
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
329326
ASSERT_NOK_WITH_MSG(
330-
BlobUtils::ValidateInlineBlobDescriptors(sa, {"b0", "b1"}),
331-
"BLOB inline field b1 configured by blob-descriptor-field or blob-view-field "
332-
"require values to be a BlobDescriptor or BlobViewStruct.");
327+
BlobUtils::ValidateBlobInlineFields(sa, {"b0", "b1"}, "blob-descriptor-field"),
328+
"BLOB inline field b1 require values to be set as corresponding type.");
329+
}
330+
331+
TEST_F(BlobUtilsTest, ValidateBlobViewFieldsEmptyFields) {
332+
// Empty view_fields -> always OK
333+
arrow::LargeBinaryBuilder builder;
334+
ASSERT_TRUE(builder.Append("random_data").ok());
335+
auto array = builder.Finish().ValueOrDie();
336+
auto struct_array =
337+
arrow::StructArray::Make({array}, {BlobUtils::ToArrowField("view")}).ValueOrDie();
338+
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
339+
ASSERT_OK(BlobUtils::ValidateBlobInlineFields(sa, {}, "blob-view-field"));
340+
}
341+
342+
TEST_F(BlobUtilsTest, ValidateBlobViewFieldsFieldNotPresent) {
343+
// Field not in struct_array -> skip, OK
344+
arrow::Int32Builder int_builder;
345+
ASSERT_TRUE(int_builder.Append(42).ok());
346+
auto int_array = int_builder.Finish().ValueOrDie();
347+
auto struct_array =
348+
arrow::StructArray::Make({int_array}, {arrow::field("f0", arrow::int32())}).ValueOrDie();
349+
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
350+
ASSERT_OK(BlobUtils::ValidateBlobInlineFields(sa, {"view"}, "blob-view-field"));
351+
}
352+
353+
TEST_F(BlobUtilsTest, ValidateBlobViewFieldsWithValidViewStruct) {
354+
// A BlobViewStruct value is accepted for a view field.
355+
BlobViewStruct view_struct(Identifier("db", "tbl"), /*field_id=*/2, /*row_id=*/5);
356+
auto serialized = view_struct.Serialize(pool_);
357+
358+
arrow::LargeBinaryBuilder builder;
359+
ASSERT_TRUE(builder.Append(serialized->data(), serialized->size()).ok());
360+
auto blob_array = builder.Finish().ValueOrDie();
361+
auto struct_array =
362+
arrow::StructArray::Make({blob_array}, {BlobUtils::ToArrowField("view")}).ValueOrDie();
363+
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
364+
ASSERT_OK(BlobUtils::ValidateBlobInlineFields(sa, {"view"}, "blob-view-field"));
365+
}
366+
367+
TEST_F(BlobUtilsTest, ValidateBlobViewFieldsWithNullValue) {
368+
// Null values in view column -> skip, OK
369+
arrow::LargeBinaryBuilder builder;
370+
ASSERT_TRUE(builder.AppendNull().ok());
371+
auto blob_array = builder.Finish().ValueOrDie();
372+
auto struct_array =
373+
arrow::StructArray::Make({blob_array}, {BlobUtils::ToArrowField("view")}).ValueOrDie();
374+
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
375+
ASSERT_OK(BlobUtils::ValidateBlobInlineFields(sa, {"view"}, "blob-view-field"));
376+
}
377+
378+
TEST_F(BlobUtilsTest, ValidateBlobViewFieldsWithRawBytes) {
379+
// Raw bytes -> error
380+
arrow::LargeBinaryBuilder builder;
381+
ASSERT_TRUE(builder.Append("raw_bytes_not_view").ok());
382+
auto blob_array = builder.Finish().ValueOrDie();
383+
auto struct_array =
384+
arrow::StructArray::Make({blob_array}, {BlobUtils::ToArrowField("view")}).ValueOrDie();
385+
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
386+
ASSERT_NOK_WITH_MSG(BlobUtils::ValidateBlobInlineFields(sa, {"view"}, "blob-view-field"),
387+
"BLOB inline field view require values to be set as corresponding type.");
388+
}
389+
390+
TEST_F(BlobUtilsTest, ValidateBlobViewFieldsRejectsBlobDescriptor) {
391+
// A BlobDescriptor value is NOT accepted for a view field.
392+
auto pool = GetDefaultPool();
393+
ASSERT_OK_AND_ASSIGN(auto descriptor, BlobDescriptor::Create("file:///tmp/test.bin", 0, 100));
394+
auto serialized = descriptor->Serialize(pool);
395+
396+
arrow::LargeBinaryBuilder builder;
397+
ASSERT_TRUE(builder.Append(serialized->data(), serialized->size()).ok());
398+
auto blob_array = builder.Finish().ValueOrDie();
399+
auto struct_array =
400+
arrow::StructArray::Make({blob_array}, {BlobUtils::ToArrowField("view")}).ValueOrDie();
401+
auto sa = std::dynamic_pointer_cast<arrow::StructArray>(struct_array);
402+
ASSERT_NOK_WITH_MSG(BlobUtils::ValidateBlobInlineFields(sa, {"view"}, "blob-view-field"),
403+
"BLOB inline field view require values to be set as corresponding type.");
333404
}
334405

335406
TEST_F(BlobUtilsTest, TestConvertBlobInlineDataFields) {

src/paimon/common/data/blob_view_struct_test.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,50 @@ TEST_F(BlobViewStructTest, TestEqual) {
106106
}
107107
}
108108

109+
TEST_F(BlobViewStructTest, TestIsBlobViewStructValid) {
110+
auto serialized = view_struct_.Serialize(pool_);
111+
ASSERT_OK_AND_ASSIGN(bool result,
112+
BlobViewStruct::IsBlobViewStruct(serialized->data(), serialized->size()));
113+
ASSERT_TRUE(result);
114+
}
115+
116+
TEST_F(BlobViewStructTest, TestIsBlobViewStructWithTooShortBuffer) {
117+
// Buffer shorter than 9 bytes should return false
118+
std::vector<char> short_buffer = {0x02, 0x43, 0x53, 0x45, 0x44, 0x42, 0x4F, 0x4C};
119+
ASSERT_OK_AND_ASSIGN(
120+
bool result, BlobViewStruct::IsBlobViewStruct(short_buffer.data(), short_buffer.size()));
121+
ASSERT_FALSE(result);
122+
123+
// Empty buffer
124+
ASSERT_OK_AND_ASSIGN(bool empty_result, BlobViewStruct::IsBlobViewStruct(nullptr, 0));
125+
ASSERT_FALSE(empty_result);
126+
}
127+
128+
TEST_F(BlobViewStructTest, TestIsBlobViewStructWithFutureVersion) {
129+
// Version > CURRENT_VERSION should return false (not an error)
130+
auto serialized = view_struct_.Serialize(pool_);
131+
(*serialized)[0] = '\x02'; // set version to 2 (> CURRENT_VERSION)
132+
ASSERT_OK_AND_ASSIGN(bool result,
133+
BlobViewStruct::IsBlobViewStruct(serialized->data(), serialized->size()));
134+
ASSERT_FALSE(result);
135+
}
136+
137+
TEST_F(BlobViewStructTest, TestIsBlobViewStructWithWrongMagic) {
138+
// Wrong magic number should return false
139+
auto serialized = view_struct_.Serialize(pool_);
140+
// Corrupt the magic bytes (bytes 1-8)
141+
(*serialized)[1] = '\x00';
142+
(*serialized)[2] = '\x00';
143+
ASSERT_OK_AND_ASSIGN(bool result,
144+
BlobViewStruct::IsBlobViewStruct(serialized->data(), serialized->size()));
145+
ASSERT_FALSE(result);
146+
}
147+
148+
TEST_F(BlobViewStructTest, TestIsBlobViewStructWithRandomData) {
149+
// Random data that doesn't match format
150+
std::vector<char> random_data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
151+
ASSERT_OK_AND_ASSIGN(bool result,
152+
BlobViewStruct::IsBlobViewStruct(random_data.data(), random_data.size()));
153+
ASSERT_FALSE(result);
154+
}
109155
} // namespace paimon::test

0 commit comments

Comments
 (0)