@@ -286,6 +286,59 @@ def test_hive_critical_properties_always_from_iceberg(catalog: Catalog) -> None:
286286 assert new_metadata_location != original_metadata_location , "metadata_location should be updated!"
287287
288288
289+ @pytest .mark .integration
290+ @pytest .mark .parametrize ("catalog" , [pytest .lazy_fixture ("session_catalog_hive" )])
291+ def test_hive_native_properties_cannot_be_deleted_via_iceberg (catalog : Catalog ) -> None :
292+ """Test that HMS-native properties (set outside Iceberg) cannot be deleted via Iceberg.
293+
294+ HMS-native properties are not visible to Iceberg, so remove_properties has no effect on them.
295+ However, if you first SET an HMS property via Iceberg (making it tracked in Iceberg metadata),
296+ it can then be deleted via Iceberg.
297+ """
298+ table = create_table (catalog )
299+ hive_client : _HiveClient = _HiveClient (catalog .properties ["uri" ])
300+
301+ # Set an HMS-native property directly (not through Iceberg)
302+ with hive_client as open_client :
303+ hive_table = open_client .get_table (* TABLE_NAME )
304+ hive_table .parameters ["hms_native_prop" ] = "native_value"
305+ open_client .alter_table (TABLE_NAME [0 ], TABLE_NAME [1 ], hive_table )
306+
307+ # Verify the HMS-native property exists
308+ with hive_client as open_client :
309+ hive_table = open_client .get_table (* TABLE_NAME )
310+ assert hive_table .parameters .get ("hms_native_prop" ) == "native_value"
311+
312+ # Attempt to remove the HMS-native property via Iceberg - should have no effect
313+ # because it's not tracked in Iceberg metadata (not visible to Iceberg)
314+ table .transaction ().remove_properties ("hms_native_prop" ).commit_transaction ()
315+
316+ # HMS-native property should still exist (cannot be deleted via Iceberg)
317+ with hive_client as open_client :
318+ hive_table = open_client .get_table (* TABLE_NAME )
319+ assert hive_table .parameters .get ("hms_native_prop" ) == "native_value" , (
320+ "HMS-native property should NOT be deletable via Iceberg since it's not visible to Iceberg!"
321+ )
322+
323+ # Now SET the same property via Iceberg (this makes it tracked in Iceberg metadata)
324+ table .transaction ().set_properties ({"hms_native_prop" : "iceberg_value" }).commit_transaction ()
325+
326+ # Verify it's updated
327+ with hive_client as open_client :
328+ hive_table = open_client .get_table (* TABLE_NAME )
329+ assert hive_table .parameters .get ("hms_native_prop" ) == "iceberg_value"
330+
331+ # Now we CAN delete it via Iceberg (because it's now tracked in Iceberg metadata)
332+ table .transaction ().remove_properties ("hms_native_prop" ).commit_transaction ()
333+
334+ # Property should be deleted from HMS
335+ with hive_client as open_client :
336+ hive_table = open_client .get_table (* TABLE_NAME )
337+ assert hive_table .parameters .get ("hms_native_prop" ) is None , (
338+ "Property should be deletable after being SET via Iceberg (making it tracked)!"
339+ )
340+
341+
289342@pytest .mark .integration
290343@pytest .mark .parametrize ("catalog" , [pytest .lazy_fixture ("session_catalog_hive" ), pytest .lazy_fixture ("session_catalog" )])
291344def test_table_properties_dict (catalog : Catalog ) -> None :
0 commit comments