flyrain commented on code in PR #3719:
URL: https://github.com/apache/polaris/pull/3719#discussion_r2893266163


##########
runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java:
##########
@@ -330,6 +380,153 @@ public Table registerTable(TableIdentifier identifier, 
String metadataFileLocati
     return new BaseTable(ops, fullTableName(name(), identifier), 
metricsReporter());
   }
 
+  private Table overwriteRegisteredTable(
+      TableIdentifier identifier, String metadataFileLocation, String 
locationDir) {
+    LOGGER.debug(
+        "overwriteRegisteredTable called with identifier={}, 
metadataFileLocation={}, locationDir={}",
+        identifier,
+        metadataFileLocation,
+        locationDir);
+
+    /*
+     * High-level overview:
+     * - Resolve the authorized parent for the table so we know the storage 
context.
+     * - Validate and read the provided metadata file using a FileIO tied to 
that
+     *   storage context.
+     * - Ensure the target entity exists and is the correct table-like subtype.
+     * - Replace the stored entity properties (including metadata-location) 
with
+     *   values derived from the parsed TableMetadata and persist the change.
+     */
+
+    // Resolve the table path to obtain storage context for overwrite 
validation.
+    PolarisResolvedPathWrapper resolvedPath =
+        resolvedEntityView.getPassthroughResolvedPath(
+            identifier, PolarisEntityType.TABLE_LIKE, 
PolarisEntitySubType.ANY_SUBTYPE);
+    if (resolvedPath == null || resolvedPath.getRawLeafEntity() == null) {
+      LOGGER.debug("No resolved path or leaf entity found for identifier={}", 
identifier);
+      throw new NoSuchTableException("Table does not exist: %s", identifier);
+    }
+    LOGGER.debug(
+        "Resolved path for identifier={} -> leafEntityId={}, 
leafEntityName={}",
+        identifier,
+        resolvedPath.getRawLeafEntity().getId(),
+        resolvedPath.getRawLeafEntity().getName());
+
+    // Validate the supplied metadata file location against the resolved 
storage.
+    LOGGER.debug(
+        "Validating supplied metadataFileLocation={} against resolved storage 
for identifier={}",
+        metadataFileLocation,
+        identifier);
+    validateLocationForTableLike(identifier, metadataFileLocation, 
resolvedPath);
+
+    // Configure FileIO for the resolved storage and read the metadata file.
+    LOGGER.debug(
+        "Loading FileIO for identifier={} to read metadata at {}", identifier, 
locationDir);
+    FileIO fileIO =
+        loadFileIOForTableLike(
+            identifier,
+            Set.of(locationDir),
+            resolvedPath,
+            new HashMap<>(tableDefaultProperties),
+            Set.of(PolarisStorageActions.READ, PolarisStorageActions.LIST));
+
+    LOGGER.debug(
+        "Reading TableMetadata from metadataFileLocation={} using resolved 
FileIO",
+        metadataFileLocation);
+    TableMetadata metadata = TableMetadataParser.read(fileIO, 
metadataFileLocation);
+    LOGGER.debug(
+        "Parsed TableMetadata for identifier={} -> uuid={}, location={}",
+        identifier,
+        metadata.uuid(),
+        metadata.location());
+
+    LOGGER.debug(
+        "Validating metadata.location()={} for identifier={}", 
metadata.location(), identifier);
+    validateLocationForTableLike(identifier, metadata.location(), 
resolvedPath);
+    validateMetadataFileInTableDir(identifier, metadata);
+    LOGGER.debug(
+        "Metadata file validated to be within table directory for 
identifier={}", identifier);
+
+    List<PolarisEntity> resolvedNamespace = resolvedPath.getRawParentPath();
+    Set<String> dataLocations =
+        StorageUtil.getLocationsUsedByTable(metadata.location(), 
metadata.properties());
+    LOGGER.debug(
+        "Validating data locations {} for identifier={} against resolved 
storage entity",
+        dataLocations,
+        identifier);
+    // Mirror updateTable location validation to prevent invalid or 
overlapping locations.
+    CatalogUtils.validateLocationsForTableLike(
+        realmConfig, identifier, dataLocations, resolvedPath);
+    dataLocations.forEach(
+        location ->
+            validateNoLocationOverlap(
+                catalogEntity,
+                identifier,
+                resolvedNamespace,
+                location,
+                resolvedPath.getRawLeafEntity()));
+    LOGGER.debug("Location overlap validation completed for identifier={}", 
identifier);
+
+    // Ensure the raw entity is an Iceberg table-like entity (not a 
view/generic table).
+    PolarisEntity rawEntity = resolvedPath.getRawLeafEntity();
+    LOGGER.debug(
+        "Existing entity for identifier={} has subType={}", identifier, 
rawEntity.getSubType());
+    if (rawEntity.getSubType() == PolarisEntitySubType.ICEBERG_VIEW) {
+      LOGGER.debug(
+          "Existing entity is a view for identifier={} - cannot overwrite as 
table", identifier);
+      throw new AlreadyExistsException("View with same name already exists: 
%s", identifier);
+    } else if (rawEntity.getSubType() == PolarisEntitySubType.GENERIC_TABLE) {
+      LOGGER.debug(
+          "Existing entity is a generic table for identifier={} - cannot 
overwrite as iceberg table",
+          identifier);
+      throw new AlreadyExistsException(
+          "Generic table with same name already exists: %s", identifier);
+    }
+
+    IcebergTableLikeEntity existingEntity = 
IcebergTableLikeEntity.of(rawEntity);
+    if (existingEntity == null) {
+      LOGGER.debug(
+          "Failed to convert rawEntity to IcebergTableLikeEntity for 
identifier={}", identifier);
+      throw new NoSuchTableException("Table does not exist: %s", identifier);
+    }
+
+    // Build updated entity from parsed metadata and persist the update.
+    // NOTE: This updates the Iceberg table UUID to match the new metadata 
file's UUID
+    // (via buildTableMetadataPropertiesMap which extracts metadata.uuid()).
+    // The Polaris entity ID remains unchanged to preserve grants/permissions.
+    // See https://lists.apache.org/thread/b5k7vdng904zr3n3q8wv83y8l30rnd4c
+    // and https://lists.apache.org/thread/k3595bttvohb6c3ms36o16gppdfllqmp
+    Map<String, String> storedProperties = 
buildTableMetadataPropertiesMap(metadata);
+    LOGGER.debug(
+        "Built storedProperties for identifier={} with {} entries and 
metadata.uuid={}",
+        identifier,
+        storedProperties.size(),
+        storedProperties.get(IcebergTableLikeEntity.TABLE_UUID));
+    IcebergTableLikeEntity updatedEntity =
+        new IcebergTableLikeEntity.Builder(existingEntity)
+            .setInternalProperties(storedProperties)
+            .setMetadataLocation(metadataFileLocation)
+            .build();
+
+    LOGGER.debug(
+        "Updating stored entity for identifier={} (entityId={}) with new 
metadataLocation={}",
+        identifier,
+        existingEntity.getId(),
+        metadataFileLocation);
+    updateTableLike(identifier, updatedEntity);
+    LOGGER.debug("updateTableLike succeeded for identifier={}", identifier);
+
+    // Refresh TableOperations so the in-memory table reflects the new 
metadata.
+    LOGGER.debug("Refreshing TableOperations for identifier={}", identifier);
+    TableOperations ops = newTableOps(identifier);
+    ops.refresh();

Review Comment:
   I think this call isn't necessary, the ops.current() will automatically 
check if refresh is needed. 
   
https://github.com/apache/polaris/blob/daf62741ec4b63443b7a4519ae92f5879b31adcf/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java#L653



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to