OIiveirra commented on code in PR #69408:
URL: https://github.com/apache/doris/pull/69408#discussion_r4360119342


##########
fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java:
##########
@@ -967,17 +966,198 @@ public void dropColumn(ExternalTable dorisTable, 
ColumnPath columnPath, long upd
             dropColumn(dorisTable, columnPath.getTopLevelName(), updateTime);
             return;
         }
+        SessionContext context = SessionContext.current();
         try (IcebergExternalMetaCache.WritableTableLease lease = 
acquireWritableTable(dorisTable)) {
-            Table icebergTable = lease.getTable();
-            ResolvedColumnPath resolvedPath = 
validateNestedStructFieldPath(icebergTable.schema(), columnPath, "drop");
+            dropColumnSafely(lease, dorisTable, columnPath, context);
+        }
+        refreshAfterColumnDrop(dorisTable, updateTime);
+    }
 
-            UpdateSchema updateSchema = icebergTable.updateSchema();
-            updateSchema.deleteColumn(resolvedPath.getFullPath());
-            commitTableUpdate(lease, updateSchema::commit,
-                    "Failed to drop nested column: " + 
columnPath.getFullPath() + " from table: "
-                            + icebergTable.name());
+    private void dropColumnSafely(IcebergExternalMetaCache.WritableTableLease 
lease,
+            ExternalTable dorisTable, ColumnPath path, SessionContext context)
+            throws UserException {
+        try {
+            // A refresh can perform authenticated catalog IO just like the 
eventual commit. Keep target
+            // validation, refresh and commit inside the one catalog 
generation retained by this lease.
+            lease.getAuthenticator().execute(() -> {
+                commitColumnDrop(lease, dorisTable, path, context);
+                return null;
+            });
+        } catch (UserException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new UserException("Failed to drop column: " + 
path.getFullPath() + ", error message is: "
+                    + ExceptionUtils.getRootCauseMessage(e), e);
+        }
+    }
+
+    private void refreshAfterColumnDrop(ExternalTable dorisTable, long 
updateTime) throws UserException {
+        try {
+            refreshTable(dorisTable, updateTime);
+        } catch (RuntimeException e) {
+            throw new UserException("Iceberg column DROP committed, but Doris 
metadata refresh failed for "
+                    + dorisTable.getRemoteDbName() + "." + 
dorisTable.getRemoteName()
+                    + "; refresh the table before another operation: " + 
e.getMessage(), e);
+        }
+    }
+
+    private void commitColumnDrop(IcebergExternalMetaCache.WritableTableLease 
lease,
+            ExternalTable dorisTable, ColumnPath path, SessionContext context) 
throws UserException {
+        Table table = lease.getTable();
+        if (!path.isNested()) {
+            validateRowLineageColumnMutation(table, path.getTopLevelName(), 
"drop");
+        }
+        TableOperations operations = ((HasTableOperations) table).operations();
+        TableMetadata loaded = operations.current();
+        if (loaded == null) {
+            throw new UserException("Cannot drop column from an unloaded 
Iceberg table: " + table.name());
+        }
+        ResolvedColumnPath loadedPath = resolveDropPath(loaded.schema(), path);
+        Set<Integer> loadedSubtreeIds = fieldSubtreeIds(loadedPath);
+
+        TableMetadata base = operations.refresh();
+        ResolvedColumnPath resolvedPath = validatePinnedDropIdentity(
+                table.name(), path, loaded, loadedSubtreeIds, base);
+        validateNotUsedByRetainedPartitionSpec(base, resolvedPath);
+
+        // Stage the standard SDK update against exactly the validated base. 
Recapturing operations.current()
+        // here could instead delete a same-name replacement published on a 
shared handle after refresh.
+        CapturingTableOperations schemaCapture = new 
CapturingTableOperations(operations, base);
+        Table stagedTable = new BaseTable(schemaCapture, table.name());
+        if (!path.isNested()) {
+            validateRowLineageColumnMutation(stagedTable, 
path.getTopLevelName(), "drop");
+        }
+        
stagedTable.updateSchema().deleteColumn(resolvedPath.getFullPath()).commit();
+        TableMetadata schemaUpdate = schemaCapture.committed();
+        if (isRestTableOperations(operations)) {
+            // No retained spec references the target, so a new SDK partition 
reference must allocate a field ID.

Review Comment:
   The PR has been narrowed to the original direct-catalog requirement in 
`552536c9fe61fbc0f787aa3be0ca6aff2c119f94`.
   
   The REST low-ID/stale-writer issue remains valid and is now tracked 
separately in #69544; narrowing this PR does not fix that issue. REST keeps 
branch-4.2's ordinary SDK table-update endpoint, loaded-table credentials and 
cache/handle behavior. The transaction-specific adapter and the numeric 
partition-history restriction have been removed from the final diff, and the 
affected REST regression suites are restored to the fixed base. Three real-HTTP 
compatibility cases verify that ordinary REST drops do not require the 
transaction endpoint, that unrelated columns on partitioned tables remain 
droppable, and that loaded-table credentials are retained.
   
   For catalogs with complete metadata CAS, the DROP uses all retained specs, 
pins UUID/subtree identity and stages against exactly the validated base before 
one CAS commit. Low-ID restoration tests cover both currently partitioned and 
now-unpartitioned tables. The metadata-file UUID reread also catches Hadoop's 
known cached-version reuse after recreation, following the existing transaction 
pattern; it is not claimed to replace Hadoop's underlying numeric-version 
protocol with a full atomic UUID fence.
   
   Validation: 370 focused FE tests and Checkstyle passed; the final standard 
ASAN BE+FE build and all three complete native suites passed with stable 
source/artifact/process identity, zero failed/fatal/skipped suites, and fresh 
task state. The local ASAN process cap was raised from 8GiB to 32GiB after an 
initial process-limit cancellation; assertions and source were unchanged. 
Please assess the current direct-catalog scope separately from the explicitly 
tracked REST follow-up.
   



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to