Skip to content

Commit 180486f

Browse files
committed
fix: address PR feedback for table requirement validations
Changes based on review feedback from @wgtmac: 1. AssertRefSnapshotID: Updated to match Java implementation logic - No longer requires base metadata (allows null for new tables) - Updated error messages to match Java version - Fixed logic flow to match Java's behavior 2. AssertLastAssignedFieldId: Allow null base metadata - Null base is now valid (for new tables) - Only validates if base exists 3. AssertLastAssignedPartitionId: Allow null base metadata - Null base is now valid (for new tables) - Only validates if base exists Updated all related tests to reflect the new behavior.
1 parent 35e88f7 commit 180486f

File tree

2 files changed

+30
-40
lines changed

2 files changed

+30
-40
lines changed

src/iceberg/table_requirement.cc

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,32 +55,32 @@ Status AssertRefSnapshotID::Validate(const TableMetadata* base) const {
5555
// Validate that a reference (branch or tag) points to the expected snapshot ID
5656

5757
if (base == nullptr) {
58-
return CommitFailed("Requirement failed: current table metadata is missing");
59-
}
60-
61-
auto it = base->refs.find(ref_name_);
62-
63-
// If snapshot_id is nullopt, the reference should not exist
64-
if (!snapshot_id_.has_value()) {
65-
if (it != base->refs.end()) {
58+
// For new tables (null base), only succeed if we're not expecting a specific snapshot
59+
if (snapshot_id_.has_value()) {
6660
return CommitFailed(
67-
"Requirement failed: reference '{}' should not exist but found snapshot ID {}",
68-
ref_name_, it->second->snapshot_id);
61+
"Requirement failed: branch or tag '{}' is missing, expected {}", ref_name_,
62+
snapshot_id_.value());
6963
}
7064
return {};
7165
}
7266

73-
// snapshot_id has a value, so the reference should exist and match
74-
if (it == base->refs.end()) {
75-
return CommitFailed("Requirement failed: reference '{}' is missing in table metadata",
76-
ref_name_);
77-
}
78-
79-
if (it->second->snapshot_id != snapshot_id_.value()) {
67+
auto it = base->refs.find(ref_name_);
68+
if (it != base->refs.end()) {
69+
// Reference exists
70+
if (!snapshot_id_.has_value()) {
71+
// A null snapshot ID means the ref should not exist already
72+
return CommitFailed(
73+
"Requirement failed: reference '{}' was created concurrently", ref_name_);
74+
} else if (snapshot_id_.value() != it->second->snapshot_id) {
75+
return CommitFailed(
76+
"Requirement failed: reference '{}' has changed: expected id {} != {}",
77+
ref_name_, snapshot_id_.value(), it->second->snapshot_id);
78+
}
79+
} else if (snapshot_id_.has_value()) {
80+
// Reference does not exist but snapshot_id is specified
8081
return CommitFailed(
81-
"Requirement failed: reference '{}' snapshot ID does not match (expected={}, "
82-
"actual={})",
83-
ref_name_, snapshot_id_.value(), it->second->snapshot_id);
82+
"Requirement failed: branch or tag '{}' is missing, expected {}", ref_name_,
83+
snapshot_id_.value());
8484
}
8585

8686
return {};
@@ -89,11 +89,7 @@ Status AssertRefSnapshotID::Validate(const TableMetadata* base) const {
8989
Status AssertLastAssignedFieldId::Validate(const TableMetadata* base) const {
9090
// Validate that the last assigned field ID matches the expected value
9191

92-
if (base == nullptr) {
93-
return CommitFailed("Requirement failed: current table metadata is missing");
94-
}
95-
96-
if (base->last_column_id != last_assigned_field_id_) {
92+
if (base && base->last_column_id != last_assigned_field_id_) {
9793
return CommitFailed(
9894
"Requirement failed: last assigned field ID does not match (expected={}, "
9995
"actual={})",
@@ -127,11 +123,7 @@ Status AssertCurrentSchemaID::Validate(const TableMetadata* base) const {
127123
Status AssertLastAssignedPartitionId::Validate(const TableMetadata* base) const {
128124
// Validate that the last assigned partition ID matches the expected value
129125

130-
if (base == nullptr) {
131-
return CommitFailed("Requirement failed: current table metadata is missing");
132-
}
133-
134-
if (base->last_partition_id != last_assigned_partition_id_) {
126+
if (base && base->last_partition_id != last_assigned_partition_id_) {
135127
return CommitFailed(
136128
"Requirement failed: last assigned partition ID does not match (expected={}, "
137129
"actual={})",

src/iceberg/test/table_metadata_builder_test.cc

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -299,23 +299,23 @@ TEST_F(TableMetadataBuilderTest, TableRequirementAssertRefSnapshotIDMismatch) {
299299

300300
auto status = requirement.Validate(base_metadata_.get());
301301
EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed));
302-
EXPECT_THAT(status, HasErrorMessage("snapshot ID does not match"));
302+
EXPECT_THAT(status, HasErrorMessage("has changed"));
303303
}
304304

305305
TEST_F(TableMetadataBuilderTest, TableRequirementAssertRefSnapshotIDRefMissing) {
306306
table::AssertRefSnapshotID requirement("missing-ref", 100);
307307

308308
auto status = requirement.Validate(base_metadata_.get());
309309
EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed));
310-
EXPECT_THAT(status, HasErrorMessage("missing in table metadata"));
310+
EXPECT_THAT(status, HasErrorMessage("is missing"));
311311
}
312312

313313
TEST_F(TableMetadataBuilderTest, TableRequirementAssertRefSnapshotIDNullBase) {
314314
table::AssertRefSnapshotID requirement("main", 100);
315315

316316
auto status = requirement.Validate(nullptr);
317317
EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed));
318-
EXPECT_THAT(status, HasErrorMessage("metadata is missing"));
318+
EXPECT_THAT(status, HasErrorMessage("is missing"));
319319
}
320320

321321
TEST_F(TableMetadataBuilderTest, TableRequirementAssertRefSnapshotIDNulloptSuccess) {
@@ -336,7 +336,7 @@ TEST_F(TableMetadataBuilderTest, TableRequirementAssertRefSnapshotIDNulloptButEx
336336

337337
auto status = requirement.Validate(base_metadata_.get());
338338
EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed));
339-
EXPECT_THAT(status, HasErrorMessage("should not exist"));
339+
EXPECT_THAT(status, HasErrorMessage("created concurrently"));
340340
}
341341

342342
TEST_F(TableMetadataBuilderTest, TableRequirementAssertLastAssignedFieldIdSuccess) {
@@ -358,9 +358,8 @@ TEST_F(TableMetadataBuilderTest, TableRequirementAssertLastAssignedFieldIdMismat
358358
TEST_F(TableMetadataBuilderTest, TableRequirementAssertLastAssignedFieldIdNullBase) {
359359
table::AssertLastAssignedFieldId requirement(10);
360360

361-
auto status = requirement.Validate(nullptr);
362-
EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed));
363-
EXPECT_THAT(status, HasErrorMessage("metadata is missing"));
361+
// Null base is allowed (for new tables)
362+
ASSERT_THAT(requirement.Validate(nullptr), IsOk());
364363
}
365364

366365
TEST_F(TableMetadataBuilderTest, TableRequirementAssertLastAssignedPartitionIdSuccess) {
@@ -382,9 +381,8 @@ TEST_F(TableMetadataBuilderTest, TableRequirementAssertLastAssignedPartitionIdMi
382381
TEST_F(TableMetadataBuilderTest, TableRequirementAssertLastAssignedPartitionIdNullBase) {
383382
table::AssertLastAssignedPartitionId requirement(5);
384383

385-
auto status = requirement.Validate(nullptr);
386-
EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed));
387-
EXPECT_THAT(status, HasErrorMessage("metadata is missing"));
384+
// Null base is allowed (for new tables)
385+
ASSERT_THAT(requirement.Validate(nullptr), IsOk());
388386
}
389387

390388
TEST_F(TableMetadataBuilderTest, TableRequirementAssertDefaultSpecIDSuccess) {

0 commit comments

Comments
 (0)