diff --git a/src/iceberg/test/update_properties_test.cc b/src/iceberg/test/update_properties_test.cc index 886558153..2a22ff949 100644 --- a/src/iceberg/test/update_properties_test.cc +++ b/src/iceberg/test/update_properties_test.cc @@ -129,6 +129,53 @@ TEST_F(UpdatePropertiesTest, UpgradeFormatVersionUnsupported) { EXPECT_THAT(result, HasErrorMessage("unsupported format version")); } +TEST_F(UpdatePropertiesTest, SetReservedPropertyUuid) { + ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateProperties()); + update->Set("uuid", "some-uuid"); + + auto result = update->Apply(); + EXPECT_THAT(result, IsError(ErrorKind::kValidationFailed)); + EXPECT_THAT(result, HasErrorMessage("Cannot set reserved property")); +} + +TEST_F(UpdatePropertiesTest, SetReservedPropertyCurrentSchema) { + ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateProperties()); + update->Set("current-schema", R"({"type": "struct"})"); + + auto result = update->Apply(); + EXPECT_THAT(result, IsError(ErrorKind::kValidationFailed)); + EXPECT_THAT(result, HasErrorMessage("Cannot set reserved property")); +} + +TEST_F(UpdatePropertiesTest, SetReservedPropertyCurrentSnapshotId) { + ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateProperties()); + update->Set("current-snapshot-id", "12345"); + + auto result = update->Apply(); + EXPECT_THAT(result, IsError(ErrorKind::kValidationFailed)); + EXPECT_THAT(result, HasErrorMessage("Cannot set reserved property")); +} + +TEST_F(UpdatePropertiesTest, SetFormatVersionStillAllowed) { + ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateProperties()); + update->Set("format-version", "3"); + + ICEBERG_UNWRAP_OR_FAIL(auto result, update->Apply()); + EXPECT_TRUE(result.updates.empty()); + ASSERT_TRUE(result.format_version.has_value()); + EXPECT_EQ(result.format_version.value(), 3); +} + +TEST_F(UpdatePropertiesTest, SetValidAndReservedProperties) { + ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateProperties()); + update->Set("valid.key", "valid.value"); + update->Set("snapshot-count", "10"); + + auto result = update->Apply(); + EXPECT_THAT(result, IsError(ErrorKind::kValidationFailed)); + EXPECT_THAT(result, HasErrorMessage("Cannot set reserved property")); +} + TEST_F(UpdatePropertiesTest, CommitSuccess) { ICEBERG_UNWRAP_OR_FAIL(auto empty_update, table_->NewUpdateProperties()); EXPECT_THAT(empty_update->Commit(), IsOk()); diff --git a/src/iceberg/update/update_properties.cc b/src/iceberg/update/update_properties.cc index 1837ab009..d2e75c301 100644 --- a/src/iceberg/update/update_properties.cc +++ b/src/iceberg/update/update_properties.cc @@ -50,10 +50,10 @@ UpdateProperties& UpdateProperties::Set(const std::string& key, "Cannot set property '{}' that is already marked for removal", key); - if (!TableProperties::reserved_properties().contains(key) || - key == TableProperties::kFormatVersion.key()) { - updates_.insert_or_assign(key, value); - } + ICEBERG_BUILDER_CHECK(!TableProperties::reserved_properties().contains(key) || + key == TableProperties::kFormatVersion.key(), + "Cannot set reserved property: '{}'", key); + updates_.insert_or_assign(key, value); return *this; } diff --git a/src/iceberg/update/update_properties.h b/src/iceberg/update/update_properties.h index dee923410..18eba427b 100644 --- a/src/iceberg/update/update_properties.h +++ b/src/iceberg/update/update_properties.h @@ -51,8 +51,9 @@ class ICEBERG_EXPORT UpdateProperties : public PendingUpdate { /// \brief Sets a property key to a specified value. /// - /// The key must not have been previously marked for removal and reserved property keys - /// will be ignored. + /// The key must not have been previously marked for removal and must not be a + /// reserved property key (except `format-version`). Setting a reserved property + /// will result in a validation error at Apply() time. /// /// \param key The property key to set /// \param value The property value to set