zhangstar333 commented on PR #68349:
URL: https://github.com/apache/doris/pull/68349#issuecomment-6138566786

   hi, @wangzhaobo957-cloud have some review major point by AI Reviewer, maybe 
u could have a look.
   
   ### F-04 · Do not discard fragments when validating managed branch locations
   
   - **Severity**: Major
   - **Where**: 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceManifestPaths.java:151-153`
   - **Category**: correctness / caches / parallel paths
   
   ```java
           String stripped = 
StringUtils.substringBefore(StringUtils.substringBefore(location, "?"), "#");
           if (!URL_SCHEME.matcher(stripped).find()) {
               return normalizeObjectPath(StringUtils.strip(stripped, "/"));
   ```
   
   **What is wrong.** The new location equivalence admits a URI fragment that 
makes a branch read open the main dataset.
   
   **Why it happens.** 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceNamespaceClient.java:466-469`
 compares this normalized value, but retains the original `table_uri` for 
opening. 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceCatalogClient.java:621-625`
 joins `/tree/dev` before `?` only, producing 
`s3://bucket/t.lance#anchor/tree/dev`. The namespace version check at 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceCatalogClient.java:696-701`
 uses 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceManifestPaths.java:74-94`,
 which strips the fragment and accepts the dev manifest. The pinned Lance 12 
provider extracts `url.path()`, so opening the joined URI addresses `/t.lance`, 
not `/t.lance/tree/dev`. This PR removes the previous comparison that 
intentionally preserved fragments.
   
   **When it bites.** A supported REST namespace responds with 
managed_versioning=true, location=`s3://bucket/t.lance`, 
table_uri=`s3://bucket/t.lance#anchor`; dev and main both have version 3 with 
different rows. Doris authorizes dev v3 but opens main v3. This is a concrete 
response/input path, not a reproduced cluster result; providers that never 
return fragments avoid this trigger.
   
   **Suggested fix.** Reject fragments in the selected managed dataset URI 
before branch joining. If fragment support is needed, fix branch URI 
construction and FE/BE addressing together. Add a branch test with equal 
version numbers and different rows. A small guard in `loadTableAccess` is:
   
   ```diff
   --- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceNamespaceClient.java
   +++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceNamespaceClient.java
   @@
            if (managed) {
   +            if (datasetUri.indexOf('#') >= 0) {
   +                throw new RuntimeException("Lance managed table URI must 
not contain a fragment: " + tableId);
   +            }
   ```
   
   Pinned SDK evidence: [Lance 12 URI 
parsing](https://github.com/lance-format/lance/blob/v12.0.0/rust/lance-io/src/object_store.rs#L516-L524),
 [provider path 
extraction](https://github.com/lance-format/lance/blob/v12.0.0/rust/lance-io/src/object_store/providers.rs#L52-L59).
   
   ### F-05 · Resolve the REST rename source to its remote identity
   
   - **Severity**: Major
   - **Where**: 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceMetadataOps.java:304-307`
   - **Category**: correctness / caches / parallel paths
   
   ```java
           execute("Failed to rename Lance table " + dbName + "." + oldName + " 
to " + newName,
                   client -> {
                       client.renameTable(dbName, oldName, newName);
                       return null;
   ```
   
   **What is wrong.** REST rename fails for a table whose stored Doris name is 
case-folded.
   
   **Why it happens.** 
`fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java:424-427` passes 
local `getDbName()/getName()` through 
`fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java:1267`.
 This method forwards them unchanged; 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceNamespaceClient.java:227-235`
 constructs the remote ID directly. In contrast, DROP and column mutations use 
the resolved table’s remote names.
   
   **When it bites.** Set `lower_case_table_names=1` on a REST catalog 
containing case-sensitive remote table `Events`. Discovery exposes local 
`events` and retains remoteName=`Events`; `ALTER TABLE catalog.default.events 
RENAME renamed_events` nevertheless sends `[parent..., events]`. The request 
fails despite resolving a valid source table. Explicit alias mapping is not 
assumed: Lance inherits identity defaults for 
fromRemoteTableName/fromRemoteDatabaseName.
   
   **Suggested fix.** Resolve source DB/table before the SDK request, 
preserving caller/local identity for cache hooks and edit log. Leave newName as 
the requested new remote identifier. For example:
   
   ```diff
   --- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceMetadataOps.java
   +++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceMetadataOps.java
   @@
            if (!catalog.isRestCatalogConfigured()) {
                throw new DdlException("RENAME TABLE is not supported for Lance 
filesystem catalogs");
            }
   +        ExternalDatabase<?> db = catalog.getDbNullable(dbName);
   +        ExternalTable source = db == null ? null : 
db.getTableNullable(oldName);
   +        if (source == null) {
   +            throw new DdlException("Failed to resolve Lance rename source: 
" + dbName + "." + oldName);
   +        }
            execute("Failed to rename Lance table " + dbName + "." + oldName + 
" to " + newName,
                    client -> {
   -                    client.renameTable(dbName, oldName, newName);
   +                    client.renameTable(source.getRemoteDbName(), 
source.getRemoteName(), newName);
   ```
   
   ### F-06 · Retire a reused rename destination on leader and follower
   
   - **Severity**: Major
   - **Where**: 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceMetadataOps.java:315-317`
   - **Category**: correctness / caches / parallel paths
   
   ```java
           if (db.isPresent()) {
               db.get().unregisterTable(oldName);
               db.get().resetMetaCacheNames();
   ```
   
   **What is wrong.** A successful REST rename can leave the destination’s 
previous table object and schema visible.
   
   **Why it happens.** Only oldName is retired. 
`fe/fe-core/src/main/java/org/apache/doris/datasource/metacache/MetaCache.java:476-478`
 returns a resident object before reloading names, while its `resetNames` only 
clears the name snapshot. URI-cache invalidation does not evict destination 
schema. 
`fe/fe-core/src/main/java/org/apache/doris/catalog/RefreshManager.java:263-267` 
repeats the source-only retirement during replay; ordinary cold-source fallback 
invalidates database schema, so that branch is not claimed to retain stale DESC.
   
   **When it bites.** Warm `source(id INT)` and `destination(old STRING)` on an 
FE. An external client deletes destination; Doris then renames source to 
destination, which the remote namespace accepts. DESC destination still returns 
old STRING. MVCC query snapshots can reload fresh schema, so this finding does 
not claim every SELECT is stale. Rename validation does not veto the cached 
destination. A warm follower is affected too.
   
   **Suggested fix.** Use replay-safe retirement for both source and 
destination, including schema, routed caches and row-count fencing. Update 
refresh-log rename replay to retire the destination on warm-source replay as 
well; preserve cold-source fallback cleanup. A leader-only extra unregister is 
insufficient. Cover reuse with distinct schemas on two FEs.
   
   ### F-07 · Preserve explicit COMMENT flags on multi-column ADD
   
   - **Severity**: Major
   - **Where**: 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceMetadataOps.java:346-350`
   - **Category**: correctness / caches / parallel paths
   
   ```java
           for (Column column : columns) {
               validateAddColumn(column, null);
               entries.add(new AddColumnsEntry()
                       .name(column.getName())
                       
.expression(LanceTypeConverter.toAddColumnExpression(column.getType())));
   ```
   
   **What is wrong.** Multi-column ADD silently loses requested column comments 
instead of applying the advertised rejection.
   
   **Why it happens.** 
`fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AddColumnsOp.java:103-106`
 uses `translateToCatalogStyle`, which copies comment text but never sets 
`Column.commentSpecified`. 
`fe/fe-core/src/main/java/org/apache/doris/datasource/lance/LanceMetadataOps.java:478-480`
 rejects only that flag. This loop therefore passes validation, and its 
AddColumnsEntry carries only name/expression. Single-column ADD uses 
`translateToCatalogStyleForSchemaChange`, which preserves the flag.
   
   **When it bites.** `ALTER TABLE t ADD COLUMN (x INT NULL COMMENT 'abc', y 
INT NULL)` on a writable Lance namespace sends a successful ADD request and 
creates x without its comment. The corresponding single-column statement is 
rejected. No upstream batch-column validation rejects this comment.
   
   **Suggested fix.** Use the schema-change conversion for batch ADD so 
comment/default/nullability intent reaches connector validation. Add a 
parser-to-command batch negative test that verifies no remote mutation. The 
conversion below matches single ADD, but also changes realDefaultValue from 
cooked to raw for other connectors, which was not validated here. A narrower 
alternative is Lance command validation of AddColumnsOp 
ColumnDefinition.isCommentSpecified. The conversion fix is:
   
   ```diff
   --- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AddColumnsOp.java
   +++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AddColumnsOp.java
   @@
   -            Column col = columnDef.translateToCatalogStyle();
   +            Column col = columnDef.translateToCatalogStyleForSchemaChange();
   ```
   


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