Skip to content

Commit ee3c959

Browse files
authored
fix(orc): support CHAR/VARCHAR compatibility and extend format compatibility tests (#362)
1 parent 143107e commit ee3c959

121 files changed

Lines changed: 1962 additions & 205 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.

‎src/paimon/format/orc/orc_file_batch_reader.cpp‎

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,36 @@
4747
namespace paimon::orc {
4848
namespace {
4949

50+
bool IsStringTypeCompatible(const ::orc::Type* src_type, const ::orc::Type* target_type) {
51+
::orc::TypeKind src_kind = src_type->getKind();
52+
return (src_kind == ::orc::TypeKind::CHAR || src_kind == ::orc::TypeKind::VARCHAR) &&
53+
target_type->getKind() == ::orc::TypeKind::STRING;
54+
}
55+
56+
bool IsCompleteTypeCompatible(const ::orc::Type* src_type, const ::orc::Type* target_type) {
57+
::orc::TypeKind src_kind = src_type->getKind();
58+
::orc::TypeKind target_kind = target_type->getKind();
59+
if (IsStringTypeCompatible(src_type, target_type)) {
60+
return true;
61+
}
62+
if (src_kind != target_kind || src_type->getSubtypeCount() != target_type->getSubtypeCount()) {
63+
return false;
64+
}
65+
if (src_type->getSubtypeCount() == 0) {
66+
return src_type->toString() == target_type->toString();
67+
}
68+
for (uint64_t i = 0; i < src_type->getSubtypeCount(); i++) {
69+
if (src_kind == ::orc::TypeKind::STRUCT &&
70+
src_type->getFieldName(i) != target_type->getFieldName(i)) {
71+
return false;
72+
}
73+
if (!IsCompleteTypeCompatible(src_type->getSubtype(i), target_type->getSubtype(i))) {
74+
return false;
75+
}
76+
}
77+
return true;
78+
}
79+
5080
void CollectAllColumnIds(const ::orc::Type* type, std::vector<uint64_t>* column_ids) {
5181
column_ids->push_back(type->getColumnId());
5282
for (uint64_t i = 0; i < type->getSubtypeCount(); ++i) {
@@ -208,7 +238,7 @@ Status OrcFileBatchReader::CollectTargetColumnIds(const ::orc::Type* src_type,
208238
std::vector<uint64_t>* target_column_ids) {
209239
auto src_kind = src_type->getKind();
210240
auto target_kind = target_type->getKind();
211-
if (src_kind != target_kind) {
241+
if (src_kind != target_kind && !IsStringTypeCompatible(src_type, target_type)) {
212242
return Status::Invalid(fmt::format("type kind mismatch: src {} vs target {}",
213243
src_type->toString(), target_type->toString()));
214244
}
@@ -235,7 +265,7 @@ Status OrcFileBatchReader::CollectTargetColumnIds(const ::orc::Type* src_type,
235265
// Partial field recall inside list/map types is unsupported, so the target must match
236266
// the complete source subtree. Include the container and every descendant because all
237267
// of their streams are recalled by the ORC reader.
238-
if (src_type->toString() != target_type->toString()) {
268+
if (!IsCompleteTypeCompatible(src_type, target_type)) {
239269
return Status::Invalid(fmt::format("type mismatch: src {} vs target {}",
240270
src_type->toString(), target_type->toString()));
241271
}

‎src/paimon/format/orc/orc_file_batch_reader_test.cpp‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,20 @@ TEST_F(OrcFileBatchReaderTest, TestCollectTargetColumnIdsPrimitiveMap) {
533533
ASSERT_EQ(target_column_ids, (std::vector<uint64_t>{1, 2, 3}));
534534
}
535535

536+
TEST_F(OrcFileBatchReaderTest, TestCollectTargetColumnIdsCompatibleStringKinds) {
537+
std::unique_ptr<::orc::Type> src_type = ::orc::Type::buildTypeFromString(
538+
"struct<char_value:char(3),varchar_value:varchar(64),"
539+
"nested:array<map<char(4),varchar(16)>>>");
540+
std::unique_ptr<::orc::Type> target_type = ::orc::Type::buildTypeFromString(
541+
"struct<char_value:string,varchar_value:string,nested:array<map<string,string>>>");
542+
std::vector<uint64_t> target_column_ids;
543+
544+
ASSERT_OK(OrcFileBatchReader::CollectTargetColumnIds(src_type.get(), target_type.get(),
545+
&target_column_ids));
546+
// char_value(1), varchar_value(2), nested-list(3), map(4), key(5), value(6)
547+
ASSERT_EQ(target_column_ids, (std::vector<uint64_t>{1, 2, 3, 4, 5, 6}));
548+
}
549+
536550
TEST_F(OrcFileBatchReaderTest, TestCollectTargetColumnIdsDeeplyNestedMap) {
537551
std::string schema =
538552
"struct<attributes:map<string,array<struct<score:double,tags:array<string>>>>>";

‎test/inte/paimon_read_compat_inte_test.cpp‎

Lines changed: 184 additions & 121 deletions
Large diffs are not rendered by default.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Schema: id INT NOT NULL, f_array_blob ARRAY<BLOB>.
2+
3+
Options:
4+
5+
bucket = -1
6+
file.format = avro
7+
blob-field = f_array_blob
8+
data-evolution.enabled = true
9+
row-tracking.enabled = true
10+
11+
The table is unpartitioned and has no primary key.
12+
13+
Add: (1, ["array-blob-value", null, ""])
14+
Add: (2, null)
15+
Add: (3, [])
16+
17+
Paimon C++ is expected to reject this table while ARRAY<BLOB> is unsupported.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"version" : 3,
3+
"id" : 0,
4+
"fields" : [ {
5+
"id" : 0,
6+
"name" : "id",
7+
"type" : "INT NOT NULL"
8+
}, {
9+
"id" : 1,
10+
"name" : "f_array_blob",
11+
"type" : {
12+
"type" : "ARRAY",
13+
"element" : "BLOB"
14+
}
15+
} ],
16+
"highestFieldId" : 1,
17+
"partitionKeys" : [ ],
18+
"primaryKeys" : [ ],
19+
"options" : {
20+
"bucket" : "-1",
21+
"blob-field" : "f_array_blob",
22+
"row-tracking.enabled" : "true",
23+
"data-evolution.enabled" : "true",
24+
"file.format" : "avro"
25+
},
26+
"timeMillis" : 1789549988349
27+
}

0 commit comments

Comments
 (0)