Gabriel39 commented on code in PR #66297:
URL: https://github.com/apache/doris/pull/66297#discussion_r3697681609
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java:
##########
@@ -943,20 +941,65 @@ public Optional<MvccSnapshot> loadSnapshots(TableIf
specificTable, Optional<Tabl
if (!(specificTable instanceof MvccTable)) {
return Optional.empty();
}
- MvccTableInfo mvccTableInfo = new MvccTableInfo(specificTable);
+ MvccTableInfo mvccTableInfo = new MvccTableInfo(specificTable,
+ versionKeyOf(tableSnapshot, scanParams));
MvccSnapshot snapshot;
- if (tableSnapshot.isPresent() || scanParams.isPresent()) {
+ if (scanParams != null && scanParams.isPresent() &&
scanParams.get().isOptions()) {
+ // OPTIONS defines a relation-scoped projection, so aliases with
the same selector
+ // reuse one handle while different selectors never overwrite each
other.
+ snapshot = snapshots.get(mvccTableInfo);
+ if (snapshot == null) {
+ MvccTable mvccTable = (MvccTable) specificTable;
+ if (mvccTable.requiresLatestSnapshotFence(tableSnapshot,
scanParams)) {
+ MvccTableInfo latestKey = new MvccTableInfo(specificTable);
+ MvccSnapshot latestFence =
latestSnapshotFences.computeIfAbsent(latestKey,
+ key -> latestSnapshots.containsKey(key)
+ ? latestSnapshots.get(key) :
mvccTable.loadLatestSnapshotFence());
+ // Planning options still need separate projections, but
their version selector
+ // must come from one statement fence rather than separate
live latest reads.
+ snapshot = mvccTable.loadSnapshot(tableSnapshot,
scanParams, Optional.of(latestFence));
+ } else {
+ snapshot = mvccTable.loadSnapshot(tableSnapshot,
scanParams);
+ }
+ snapshots.put(mvccTableInfo, snapshot);
+ scanParams.flatMap(TableScanParams::getResolvedMapParams)
+ .ifPresent(params ->
resolvedSnapshotScanParams.put(mvccTableInfo, params));
+ } else if (resolvedSnapshotScanParams.containsKey(mvccTableInfo)) {
+ // Snapshot de-duplication also de-duplicates dynamic option
resolution. Seed later
+ // aliases so their scan phase consumes the selector used by
the cached snapshot.
+
scanParams.get().reuseResolvedMapParams(resolvedSnapshotScanParams.get(mvccTableInfo));
+ }
+ } else if (tableSnapshot.isPresent() || scanParams.isPresent()) {
snapshot = ((MvccTable) specificTable).loadSnapshot(tableSnapshot,
scanParams);
} else {
// Keep latest metadata separate: a historical relation may
temporarily become the
// table-scoped snapshot, but it must not redefine what a later
latest relation sees.
snapshot = latestSnapshots.computeIfAbsent(mvccTableInfo,
- key -> ((MvccTable)
specificTable).loadSnapshot(tableSnapshot, scanParams));
+ key -> latestSnapshotFences.containsKey(key)
+ ? ((MvccTable)
specificTable).loadSnapshot(tableSnapshot, scanParams,
+ Optional.of(latestSnapshotFences.get(key)))
+ : ((MvccTable)
specificTable).loadSnapshot(tableSnapshot, scanParams));
+ // A full latest projection is also a valid version fence.
Recording it makes
+ // plain-first and options-first aliases pin the same statement
version.
+ latestSnapshotFences.putIfAbsent(mvccTableInfo, snapshot);
}
snapshots.put(mvccTableInfo, snapshot);
+ tableMetadataSnapshots.putIfAbsent(new MvccTableInfo(specificTable),
snapshot);
return Optional.of(snapshot);
}
+ /**
+ * Clear MVCC state retained by a prepared statement between executions. A
snapshot fence belongs
+ * to one EXECUTE only; carrying it forward would make a later commit
permanently invisible.
+ */
+ public void resetMvccSnapshots() {
Review Comment:
Addressed in f7365be387. resetMvccSnapshots now clears the execution-scoped
preload result while retaining preload candidates, with coverage for repeated
resets.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java:
##########
@@ -427,9 +427,16 @@ private Optional<LogicalPlan> handleMetaTable(TableIf
table, UnboundRelation unb
validatePaimonSystemTableScanParams(
(PaimonSysExternalTable) sysExternalTable,
unboundRelation.getScanParams());
}
- TableIf snapshotTable = sysExternalTable instanceof
IcebergSysExternalTable
- ? ((IcebergSysExternalTable)
sysExternalTable).getSourceTable()
- : sysExternalTable;
+ TableIf snapshotTable;
+ if (sysExternalTable instanceof IcebergSysExternalTable) {
+ snapshotTable = ((IcebergSysExternalTable)
sysExternalTable).getSourceTable();
+ } else if (sysExternalTable instanceof PaimonSysExternalTable) {
+ // Paimon system OPTIONS resolve against the data table too;
using the synthetic
+ // wrapper here bypasses the statement's common latest fence
and reopens live latest.
+ snapshotTable = ((PaimonSysExternalTable)
sysExternalTable).getSourceTable();
Review Comment:
Addressed in c36407eb27. Native Paimon system scans no longer take the
ordinary empty-data early return, and the empty-source metadata-table behavior
is covered.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteCommand.java:
##########
@@ -72,6 +72,7 @@ public void run(ConnectContext ctx, StmtExecutor executor)
throws Exception {
StatementContext statementContext = ctx.getStatementContext();
statementContext.setPrepareStage(false);
statementContext.setIsInsert(false);
+ statementContext.resetMvccSnapshots();
Review Comment:
Addressed in f7365be387. Prepared DELETE USING and MERGE expose their
retained relation roots so relation-local scan parameters are reset before
replanning, with focused coverage.
--
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]