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


##########
fe/be-java-extensions/paimon-scanner/src/main/java/org/apache/doris/paimon/PaimonJniScanner.java:
##########
@@ -523,64 +628,156 @@ static Optional<Long> parseDataSizeBytes(String value) {
         if (value == null || value.trim().isEmpty()) {
             return Optional.empty();
         }
-        String normalized = value.trim().toLowerCase(Locale.ROOT).replace("_", 
"").replace(" ", "");
-        int unitStart = 0;
-        while (unitStart < normalized.length()
-                && (Character.isDigit(normalized.charAt(unitStart)) || 
normalized.charAt(unitStart) == '.')) {
-            unitStart++;
-        }
-        if (unitStart == 0) {
-            return Optional.empty();
-        }
         try {
-            double number = Double.parseDouble(normalized.substring(0, 
unitStart));
-            String unit = normalized.substring(unitStart);
-            long multiplier;
-            switch (unit) {
-                case "":
-                case "b":
-                case "byte":
-                case "bytes":
-                    multiplier = 1L;
-                    break;
-                case "k":
-                case "kb":
-                case "kib":
-                    multiplier = 1024L;
-                    break;
-                case "m":
-                case "mb":
-                case "mib":
-                    multiplier = 1024L * 1024L;
-                    break;
-                case "g":
-                case "gb":
-                case "gib":
-                    multiplier = 1024L * 1024L * 1024L;
-                    break;
-                case "t":
-                case "tb":
-                case "tib":
-                    multiplier = 1024L * 1024L * 1024L * 1024L;
-                    break;
-                default:
-                    return Optional.empty();
-            }
-            return Optional.of((long) (number * multiplier));
-        } catch (NumberFormatException e) {
+            // Keep the BE guard's accepted grammar identical to the Paimon 
option parser that will
+            // consume this value; accepting a superset lets invalid 
serialized options reach scans.
+            return Optional.of(MemorySize.parse(value).getBytes());
+        } catch (IllegalArgumentException e) {
             return Optional.empty();
         }
     }
 
     private void initTable() {
         Preconditions.checkState(params.containsKey("serialized_table"));
         table = PaimonUtils.deserialize(params.get("serialized_table"));
+        String encodedSystemSource = params.get(PAIMON_OPTION_PREFIX + 
DORIS_SERIALIZED_SYSTEM_SOURCE);
+        FileStoreTable systemSource = encodedSystemSource == null
+                ? null : PaimonUtils.deserialize(encodedSystemSource);
+        table = applyBackendManifestParallelism(table,
+                params.get(PAIMON_OPTION_PREFIX + 
DORIS_MANIFEST_PARALLELISM_CAP),
+                Runtime.getRuntime().availableProcessors(), systemSource,
+                params.get(PAIMON_OPTION_PREFIX + DORIS_SYSTEM_TABLE_TYPE));
+        validateSerializedReaderOptions(table);

Review Comment:
   [P1] Backstop fallback options hidden by legacy system wrappers
   
   With an older FE, the auxiliary system source is absent. For a reader-backed 
view such as `$audit_log`, `$binlog`, or `$row_tracking` over a 
`FallbackReadFileStoreTable`, the outer wrapper exposes only the pair's main 
options, so this validates the safe main branch and cannot descend to the 
fallback child. `newRead()` then delegates through the wrapper and constructs 
both readers, allowing a fallback-only `read.batch-size=0` or out-of-range 
async threshold to reach the reader path. Please add a legacy system-wrapper 
backstop for fallback-only reader options and a real serialized wrapper test. 
The live split-target thread covers a different option.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java:
##########
@@ -636,6 +637,18 @@ private Optional<LogicalPlan> handleMetaTable(TableIf 
table, UnboundRelation unb
         if (sysTablePlan.isNative()) {
             List<String> qualifierWithoutTableName = 
qualifiedTableName.subList(0, qualifiedTableName.size() - 1);
             ExternalTable sysExternalTable = 
sysTablePlan.getSysExternalTable();
+            if (sysExternalTable instanceof PluginDrivenSysExternalTable) {
+                Optional<TableSnapshot> tableSnapshot = 
unboundRelation.getTableSnapshot();
+                Optional<TableScanParams> scanParams = 
Optional.ofNullable(unboundRelation.getScanParams());
+                StatementContext statementContext = 
cascadesContext.getStatementContext();
+                ((PluginDrivenSysExternalTable) 
sysExternalTable).resolveScanPin(

Review Comment:
   [P2] Use the system relation's pin for row-count statistics
   
   This stores the source snapshot only in the transient system table's private 
memo. `PluginDrivenSysExternalTable` is intentionally not an `MvccTable`, so 
its inherited `getRowCount()` cannot retrieve this entry from 
`StatementContext`; it falls through to the latest-keyed cache and Paimon's 
two-argument statistics path, while schema and scan initialization consume the 
memoized pin. Thus `$ro@options('scan.snapshot-id'='S')` can execute S but be 
costed at S+1 (and an empty fence can be costed after the first commit). Please 
thread this same memoized connector snapshot into the three-argument statistics 
call, or return UNKNOWN rather than reopen latest, and cover positive plus 
empty system pins.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteCommand.java:
##########
@@ -95,22 +96,25 @@ public void run(ConnectContext ctx, StmtExecutor executor) 
throws Exception {
         // per-statement scope so a prior execution's cached tables/state 
never leak into this one (the
         // scope key's queryId is a second line of defense). See 
StatementContext#resetConnectorStatementScope.
         statementContext.resetConnectorStatementScope();
+        statementContext.resetMvccSnapshots();
         LogicalPlan logicalPlan = prepareCommand.getLogicalPlan();
-        LogicalPlan relationRoot = logicalPlan;
+        List<LogicalPlan> relationRoots = new ArrayList<>();
         if (logicalPlan instanceof InsertIntoTableCommand) {
-            relationRoot = ((InsertIntoTableCommand) 
logicalPlan).getLogicalQuery();
+            relationRoots.add(((InsertIntoTableCommand) 
logicalPlan).getLogicalQuery());
         } else if (logicalPlan instanceof InsertOverwriteTableCommand) {
-            relationRoot = ((InsertOverwriteTableCommand) 
logicalPlan).getLogicalQuery();
+            relationRoots.add(((InsertOverwriteTableCommand) 
logicalPlan).getLogicalQuery());
         } else if (logicalPlan instanceof UpdateCommand) {
-            relationRoot = ((UpdateCommand) logicalPlan).getLogicalQuery();
-        } else if (logicalPlan instanceof Command) {
-            // Non-DML commands deliberately have no traversable children; 
they cannot own a
-            // relation scan tree whose resolved state needs resetting.
-            relationRoot = null;
+            relationRoots.add(((UpdateCommand) logicalPlan).getLogicalQuery());
+        } else if (logicalPlan instanceof DeleteFromUsingCommand) {

Review Comment:
   [P1] Reset retained OPTIONS state in prepared base DELETE subqueries
   
   This arm covers only `DeleteFromUsingCommand`. The parser still builds the 
base `DeleteFromCommand` for DELETE without USING/CTE/order-limit, and that 
command retains its `logicalQuery`; all other Commands are skipped here. Its 
external relations occur in predicate subqueries, whose 
`SubqueryExpr.queryPlan` also is not reached by ordinary Plan-child traversal. 
Consequently a prepared `DELETE ... WHERE id IN (SELECT id FROM 
source@options('scan.mode'='latest'))` can keep the first EXECUTE's 
`resolvedMapParams` after a commit and mutate against the stale snapshot even 
though the StatementContext maps were cleared. Reset the base DELETE root and 
recursively visit retained subquery plans, then add a repeated-EXECUTE 
regression.



##########
fe/fe-connector/fe-connector-paimon/src/main/java/org/apache/doris/connector/paimon/PaimonScanPlanProvider.java:
##########
@@ -1226,6 +1288,12 @@ private Table resolveSchemaDictTable(Table table, 
PaimonTableHandle handle) {
             return table;
         }
         if (table instanceof ReadOptimizedTable) {
+            FileStoreTable pinnedSource = handle.getSysBaseTable();

Review Comment:
   [P1] Build the `$ro` dictionary from the option-applied source
   
   `withScanOptions` deliberately leaves `sysBaseTable` unchanged, while 
`resolveScanTable` applies an explicit historical OPTIONS selector to the `$ro` 
wrapper/source. Returning the handle's original latest source here pairs the 
pinned scan with a different schema dictionary. After `old` is renamed to 
`new`, `$ro@options('scan.snapshot-id'='S')` binds `old`, but both schemas 
consulted by `resolveCurrentSchemaFields` come from the latest source and the 
scan fails that `old` is absent (or can attach later field/type metadata to 
pinned files). Retain/recover the exact effective source used by the final 
wrapper for dictionary construction and test a historical `$ro` across 
rename/type evolution.



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