Skip to content

Commit f0f4228

Browse files
committed
fix: Correct errors in update Properties implementation
1 parent 25daf33 commit f0f4228

File tree

3 files changed

+93
-24
lines changed

3 files changed

+93
-24
lines changed

src/iceberg/test/update_properties_test.cc

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <gmock/gmock.h>
2727
#include <gtest/gtest.h>
2828

29+
#include "gmock/gmock.h"
2930
#include "iceberg/file_format.h"
3031
#include "iceberg/result.h"
3132
#include "iceberg/schema.h"
@@ -60,19 +61,18 @@ class UpdatePropertiesTest : public ::testing::Test {
6061
TableIdentifier identifier_;
6162
};
6263

63-
TEST_F(UpdatePropertiesTest, EmptyUpdates) {
64-
UpdateProperties update(identifier_, catalog_, metadata_);
65-
66-
auto result = update.Commit();
67-
EXPECT_THAT(result, IsOk());
68-
}
69-
7064
TEST_F(UpdatePropertiesTest, SetProperty) {
7165
UpdateProperties update(identifier_, catalog_, metadata_);
7266
update.Set("key1", "value1").Set("key2", "value2");
7367

7468
auto result = update.Apply();
7569
EXPECT_THAT(result, IsOk());
70+
71+
// Verify the actual pending updates
72+
const auto& pending_updates = update.GetPendingUpdates();
73+
EXPECT_EQ(pending_updates.size(), 2);
74+
EXPECT_EQ(pending_updates.at("key1"), "value1");
75+
EXPECT_EQ(pending_updates.at("key2"), "value2");
7676
}
7777

7878
TEST_F(UpdatePropertiesTest, RemoveProperty) {
@@ -81,6 +81,12 @@ TEST_F(UpdatePropertiesTest, RemoveProperty) {
8181

8282
auto result = update.Apply();
8383
EXPECT_THAT(result, IsOk());
84+
85+
// Verify the actual pending removals
86+
const auto& pending_removals = update.GetPendingRemovals();
87+
EXPECT_EQ(pending_removals.size(), 2);
88+
EXPECT_TRUE(pending_removals.contains("key1"));
89+
EXPECT_TRUE(pending_removals.contains("key2"));
8490
}
8591

8692
TEST_F(UpdatePropertiesTest, SetRemoveConflict) {
@@ -113,6 +119,15 @@ TEST_F(UpdatePropertiesTest, UpgradeFormatVersion) {
113119

114120
auto result = update.Apply();
115121
EXPECT_THAT(result, IsOk());
122+
123+
// Verify the format version is set correctly
124+
const auto& format_version = update.GetPendingFormatVersion();
125+
ASSERT_TRUE(format_version.has_value());
126+
EXPECT_EQ(format_version.value(), 2);
127+
128+
// format-version should be removed from pending updates after Apply()
129+
const auto& pending_updates = update.GetPendingUpdates();
130+
EXPECT_FALSE(pending_updates.contains("format-version"));
116131
}
117132

118133
{
@@ -151,10 +166,15 @@ TEST_F(UpdatePropertiesTest, InvalidTable) {
151166
{
152167
// catalog is null
153168
UpdateProperties update(identifier_, nullptr, metadata_);
154-
155-
auto result = update.Apply();
156-
EXPECT_THAT(result, IsError(ErrorKind::kInvalidArgument));
157-
EXPECT_THAT(result, HasErrorMessage("Catalog is required"));
169+
update.Set("key1", "value1");
170+
auto apply_result = update.Apply();
171+
EXPECT_THAT(apply_result, IsOk());
172+
173+
// Commit should fail since catalog is required
174+
auto commit_result = update.Commit();
175+
EXPECT_THAT(commit_result, IsError(ErrorKind::kInvalidArgument));
176+
EXPECT_THAT(commit_result,
177+
HasErrorMessage("Catalog is required to commit property updates"));
158178
}
159179

160180
{
@@ -201,6 +221,15 @@ TEST_F(UpdatePropertiesTest, FluentInterface) {
201221

202222
auto result = update.Apply();
203223
EXPECT_THAT(result, IsOk());
224+
225+
// Verify the actual pending updates and removals
226+
const auto& pending_updates = update.GetPendingUpdates();
227+
EXPECT_EQ(pending_updates.size(), 1);
228+
EXPECT_EQ(pending_updates.at("key1"), "value1");
229+
230+
const auto& pending_removals = update.GetPendingRemovals();
231+
EXPECT_EQ(pending_removals.size(), 1);
232+
EXPECT_TRUE(pending_removals.contains("key2"));
204233
}
205234

206235
} // namespace iceberg

src/iceberg/update/update_properties.cc

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,25 @@ UpdateProperties& UpdateProperties::Remove(const std::string& key) {
7171
}
7272

7373
Status UpdateProperties::Apply() {
74-
if (!catalog_) {
75-
return InvalidArgument("Catalog is required to apply property updates");
76-
}
7774
if (!base_metadata_) {
7875
return InvalidArgument("Base table metadata is required to apply property updates");
7976
}
8077

8178
ICEBERG_RETURN_UNEXPECTED(CheckErrors());
8279

83-
auto iter = updates_.find(TableProperties::kFormatVersion.key());
84-
if (iter != updates_.end()) {
80+
std::unordered_map<std::string, std::string> new_properties;
81+
for (const auto& [key, value] : base_metadata_->properties.configs()) {
82+
if (!removals_.contains(key)) {
83+
new_properties[key] = value;
84+
}
85+
}
86+
87+
for (const auto& [key, value] : updates_) {
88+
new_properties[key] = value;
89+
}
90+
91+
auto iter = new_properties.find(TableProperties::kFormatVersion.key());
92+
if (iter != new_properties.end()) {
8593
try {
8694
int parsed_version = std::stoi(iter->second);
8795
if (parsed_version > TableMetadata::kSupportedTableFormatVersion) {
@@ -97,19 +105,23 @@ Status UpdateProperties::Apply() {
97105
return InvalidArgument("Format version '{}' is out of range", iter->second);
98106
}
99107

100-
updates_.erase(iter);
108+
updates_.erase(TableProperties::kFormatVersion.key());
101109
}
102110

103111
if (auto schema = base_metadata_->Schema(); schema.has_value()) {
104112
ICEBERG_RETURN_UNEXPECTED(
105-
MetricsConfig::VerifyReferencedColumns(updates_, *schema.value()));
113+
MetricsConfig::VerifyReferencedColumns(new_properties, *schema.value()));
106114
}
107115
return {};
108116
}
109117

110118
Status UpdateProperties::Commit() {
111119
ICEBERG_RETURN_UNEXPECTED(Apply());
112120

121+
if (!catalog_) {
122+
return InvalidArgument("Catalog is required to commit property updates");
123+
}
124+
113125
std::vector<std::unique_ptr<TableUpdate>> updates;
114126
if (!updates_.empty()) {
115127
updates.emplace_back(std::make_unique<table::SetProperties>(std::move(updates_)));
@@ -131,4 +143,17 @@ Status UpdateProperties::Commit() {
131143
return {};
132144
}
133145

146+
const std::unordered_map<std::string, std::string>& UpdateProperties::GetPendingUpdates()
147+
const {
148+
return updates_;
149+
}
150+
151+
const std::unordered_set<std::string>& UpdateProperties::GetPendingRemovals() const {
152+
return removals_;
153+
}
154+
155+
const std::optional<int8_t>& UpdateProperties::GetPendingFormatVersion() const {
156+
return format_version_;
157+
}
158+
134159
} // namespace iceberg

src/iceberg/update/update_properties.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include <unordered_map>
2525
#include <unordered_set>
2626

27-
#include "iceberg/file_format.h"
2827
#include "iceberg/iceberg_export.h"
2928
#include "iceberg/pending_update.h"
3029
#include "iceberg/table_identifier.h"
@@ -45,14 +44,15 @@ class ICEBERG_EXPORT UpdateProperties : public PendingUpdate {
4544

4645
/// \brief Sets a property key to a specified value.
4746
///
48-
/// The key can not be marked for previous removal and reserved property keys will be
49-
/// ignored.
47+
/// The key must not have been previously marked for removal and reserved property keys
48+
/// will be ignored.
49+
/// \param key The property key to set
50+
/// \param value The property value to set
51+
/// \return Reference to this UpdateProperties for chaining
5052
UpdateProperties& Set(const std::string& key, const std::string& value);
5153

5254
/// \brief Marks a property for removal.
5355
///
54-
/// The key can not be already marked for removal.
55-
///
5656
/// \param key The property key to remove
5757
/// \return Reference to this UpdateProperties for chaining
5858
UpdateProperties& Remove(const std::string& key);
@@ -69,9 +69,24 @@ class ICEBERG_EXPORT UpdateProperties : public PendingUpdate {
6969
///
7070
/// Validates the changes and applies them to the table through the catalog.
7171
///
72-
/// \return OK if the changes are valid and committed successfully, or an error
72+
/// \return Status::OK if the changes are valid and committed successfully, or an error.
7373
Status Commit() override;
7474

75+
/// \brief Get the pending property updates after applying changes.
76+
///
77+
/// \return The map of property updates
78+
const std::unordered_map<std::string, std::string>& GetPendingUpdates() const;
79+
80+
/// \brief Get the pending property removals after applying changes.
81+
///
82+
/// \return The set of property keys to remove
83+
const std::unordered_set<std::string>& GetPendingRemovals() const;
84+
85+
/// \brief Get the pending format version upgrade after applying changes.
86+
///
87+
/// \return The optional format version
88+
const std::optional<int8_t>& GetPendingFormatVersion() const;
89+
7590
private:
7691
TableIdentifier identifier_;
7792
std::shared_ptr<Catalog> catalog_;

0 commit comments

Comments
 (0)