github-actions[bot] commented on code in PR #66247:
URL: https://github.com/apache/doris/pull/66247#discussion_r3679531506


##########
fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/source/PaimonScanNode.java:
##########
@@ -995,18 +996,27 @@ private Table getProcessedTable() throws UserException {
             throw new UserException("Can not specify scan params and table 
snapshot at same time.");
         }
 
+        Table finalTable;
         if (theScanParams != null && theScanParams.incrementalRead()) {
             // System table handles are cached, so preserve query isolation by 
applying dynamic
             // options to a copied Paimon table instead of changing the shared 
handle.
-            return baseTable.copy(getIncrReadParams());
-        }
-        if (theScanParams != null && theScanParams.isOptions()) {
+            finalTable = baseTable.copy(getIncrReadParams());
+        } else if (theScanParams != null && theScanParams.isOptions()) {
             try {
-                return source.getPaimonTable(theScanParams);
+                finalTable = source.getPaimonTable(theScanParams);
             } catch (IllegalArgumentException e) {
                 throw new UserException(e.getMessage(), e);
             }
+        } else {
+            finalTable = baseTable;
+        }
+        try {
+            // This is the last common boundary before planning and 
serialization, including scans
+            // with no relation copy and incremental/system-table paths that 
bypass applyOptions.

Review Comment:
   [P1] Do not scan raw physical partitions during snapshot binding
   
   Before this method runs, statement snapshot loading follows 
`PaimonLatestSnapshotProjectionLoader` -> `PaimonPartitionInfoLoader` -> 
`PaimonExternalCatalog.getPaimonPartitions`, which calls raw 
`catalog.listPartitions`. Paimon 1.3.1 implements that by reloading the 
physical table and running `newScan().listPartitionEntries()`. A partitioned 
table with physical `scan.manifest.parallelism=0` can therefore block before 
this final guard rejects it, and a safe relation override cannot take effect 
because snapshot loading runs first; an oversized value can mutate the global 
pool. The new fixture is unpartitioned, so the loader returns `EMPTY` and 
misses this path. Please validate before enumerating the physical table (or 
skip this preload when relation options require it) and add a partitioned 
fixture. This is distinct pre-ScanNode metadata planning.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/source/PaimonScanNode.java:
##########
@@ -995,18 +996,27 @@ private Table getProcessedTable() throws UserException {
             throw new UserException("Can not specify scan params and table 
snapshot at same time.");
         }
 
+        Table finalTable;
         if (theScanParams != null && theScanParams.incrementalRead()) {
             // System table handles are cached, so preserve query isolation by 
applying dynamic
             // options to a copied Paimon table instead of changing the shared 
handle.
-            return baseTable.copy(getIncrReadParams());
-        }
-        if (theScanParams != null && theScanParams.isOptions()) {
+            finalTable = baseTable.copy(getIncrReadParams());
+        } else if (theScanParams != null && theScanParams.isOptions()) {
             try {
-                return source.getPaimonTable(theScanParams);
+                finalTable = source.getPaimonTable(theScanParams);
             } catch (IllegalArgumentException e) {
                 throw new UserException(e.getMessage(), e);
             }
+        } else {
+            finalTable = baseTable;
+        }
+        try {
+            // This is the last common boundary before planning and 
serialization, including scans

Review Comment:
   [P1] Guard row-count plans before this boundary
   
   This is not the last Paimon planning boundary. 
`PaimonExternalTable.fetchRowCount()` directly runs 
`getBasePaimonTable().newReadBuilder().newScan().plan()`, and is reached by 
`ExternalRowCountCache` (synchronously by default) and directly by 
`AnalysisManager`. With physical `scan.manifest.parallelism=0`, 
optimization/statistics can therefore block before 
`getProcessedTable()`—including a query whose relation override would make the 
final scan safe; an above-CPU value can replace the JVM-static pool first. 
Please validate the effective base handle at each row-count plan and cover 
cache/manual-analysis paths. This is distinct from the existing foreground-scan 
thread.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/PaimonScanParams.java:
##########
@@ -140,7 +144,11 @@ public static Table applyOptions(Table table, Map<String, 
String> options) {
                     .filter(key -> !tableOptions.containsKey(key))
                     .forEach(key -> isolatedOptions.put(key, null));
         }
-        return table.copy(isolatedOptions);
+        Table effectiveTable = table.copy(isolatedOptions);
+        // Validate after every copy so relation options participate in the 
documented
+        // relation > catalog > physical precedence before the effective value 
is judged.
+        
PaimonReaderOptions.validateEffectiveTableOptions(effectiveTable.options());

Review Comment:
   [P1] Validate the table hidden by read-only wrappers
   
   On a real `$partitions` table, `effectiveTable.options()` is always empty: 
Paimon 1.3.1's `ReadonlyTable` supplies `{}`, while `PartitionsTable.copy(...)` 
only updates its private `FileStoreTable`. `PartitionsRead.createReader` later 
calls that hidden table's `newScan().listPartitionEntries()`. Thus a physical 
`scan.manifest.parallelism=0` passes this check and the ScanNode check, then 
can block on Paimon's zero-permit executor. The new tests use generic `Table` 
mocks that expose the copied map, so they miss this contract. Please validate 
the underlying effective data table and add real `$partitions` no-override and 
safe-override coverage. This is the remaining wrapper case after discussion 
`3679236492`, not the foreground data-table path.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/source/PaimonScanNode.java:
##########
@@ -995,18 +996,27 @@ private Table getProcessedTable() throws UserException {
             throw new UserException("Can not specify scan params and table 
snapshot at same time.");
         }
 
+        Table finalTable;
         if (theScanParams != null && theScanParams.incrementalRead()) {
             // System table handles are cached, so preserve query isolation by 
applying dynamic
             // options to a copied Paimon table instead of changing the shared 
handle.
-            return baseTable.copy(getIncrReadParams());
-        }
-        if (theScanParams != null && theScanParams.isOptions()) {
+            finalTable = baseTable.copy(getIncrReadParams());
+        } else if (theScanParams != null && theScanParams.isOptions()) {
             try {
-                return source.getPaimonTable(theScanParams);
+                finalTable = source.getPaimonTable(theScanParams);
             } catch (IllegalArgumentException e) {
                 throw new UserException(e.getMessage(), e);
             }
+        } else {
+            finalTable = baseTable;
+        }
+        try {
+            // This is the last common boundary before planning and 
serialization, including scans
+            // with no relation copy and incremental/system-table paths that 
bypass applyOptions.
+            
PaimonReaderOptions.validateEffectiveTableOptions(finalTable.options());

Review Comment:
   [P1] Validate fallback branch options too
   
   `FallbackReadFileStoreTable.options()` exposes only its wrapped main branch, 
but `newScan()` creates both main and fallback scans and 
`FallbackReadScan.plan()` calls `fallbackScan.listPartitions()` before planning 
remaining fallback data. If the main branch is safe but the physical fallback 
branch has `scan.manifest.parallelism=0`, this line validates only the safe 
main map and planning can block; an above-CPU value can replace the shared 
executor. Please validate every option-bearing child handle after applicable 
copies and add a real fallback-branch fixture. This is distinct from the normal 
foreground table because the hidden child has independent schema options.



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