Gabriel39 commented on code in PR #67904:
URL: https://github.com/apache/doris/pull/67904#discussion_r4012042667
##########
fe/fe-connector/fe-connector-paimon/src/main/java/org/apache/doris/connector/paimon/PaimonScanParams.java:
##########
@@ -196,14 +201,79 @@ public static FileStoreTable
applyOptionsWithoutTimeTravel(
.filter(key -> !tableOptions.containsKey(key))
.forEach(key -> isolatedOptions.put(key, null));
}
- // The statement fence already selected the schema generation.
Preserve that generation
- // while carrying only the resolved read selector and execution
options into this copy.
+ String schemaId = options.get(BOUND_SCHEMA_ID);
+ PaimonSchemaPin.validate(table, options);
+ if (schemaId != null) {
+ table = restoreBoundSchema(table, Long.parseLong(schemaId),
options, "");
+ }
FileStoreTable effectiveTable = (FileStoreTable)
PaimonReaderOptions.runtimeSafeTable(
- table.copyWithoutTimeTravel(isolatedOptions));
+ copyWithPinnedFallback(table, isolatedOptions, options, ""));
PaimonReaderOptions.validateEffectiveTable(effectiveTable);
return effectiveTable;
}
+ private static FileStoreTable copyWithPinnedFallback(FileStoreTable table,
Map<String, String> dynamicOptions,
+ Map<String, String> coordinates, String path) {
+ if (table instanceof FallbackReadFileStoreTable) {
+ FallbackReadFileStoreTable pair = (FallbackReadFileStoreTable)
table;
+ String fallbackPath = path + "fallback.";
+ String snapshotId =
PaimonSchemaPin.fallbackSnapshotId(coordinates, fallbackPath);
+ if (snapshotId != null) {
+ Map<String, String> fallbackOptions = new
HashMap<>(dynamicOptions);
+ // Keep branch policy, but never retranslate the main fence
against a later fallback history.
+ fallbackOptions.remove(CoreOptions.BUCKET.key());
+ fallbackOptions.put(CoreOptions.BRANCH.key(),
pair.fallback().coreOptions().branch());
+ fallbackOptions.put(CoreOptions.SCAN_SNAPSHOT_ID.key(),
snapshotId);
+ return new FallbackReadFileStoreTable(
+ copyWithPinnedFallback(pair.wrapped(), dynamicOptions,
coordinates, path),
+ copyWithPinnedFallback(pair.fallback(),
fallbackOptions, coordinates, fallbackPath));
+ }
+ }
+ if (table instanceof DelegatedFileStoreTable && !(table instanceof
FallbackReadFileStoreTable)) {
+ return PaimonTableDecorators.replaceWrapped(table,
copyWithPinnedFallback(
+ ((DelegatedFileStoreTable) table).wrapped(),
dynamicOptions, coordinates, path));
+ }
+ return table.copyWithoutTimeTravel(dynamicOptions);
+ }
+
+ private static FileStoreTable restoreBoundSchema(
+ FileStoreTable table, long schemaId, Map<String, String> options,
String path) {
+ if (table instanceof FallbackReadFileStoreTable) {
+ FallbackReadFileStoreTable pair = (FallbackReadFileStoreTable)
table;
+ // Each branch has its own schema history. Restore both children
at their captured
+ // coordinates, preserving compatibility without broadcasting the
main schema ID.
+ String fallbackPath = path + "fallback.";
+ long fallbackId = PaimonSchemaPin.fallbackSchemaId(options,
fallbackPath,
+ () ->
pair.fallback().schemaManager().latest().orElseThrow(IllegalStateException::new).id());
+ return new
FallbackReadFileStoreTable(restoreBoundSchema(pair.wrapped(), schemaId,
options, path),
+ restoreBoundSchema(pair.fallback(), fallbackId, options,
fallbackPath));
+ }
+ if (table instanceof DelegatedFileStoreTable) {
+ FileStoreTable wrapped = ((DelegatedFileStoreTable)
table).wrapped();
+ return PaimonTableDecorators.replaceWrapped(table,
restoreBoundSchema(wrapped, schemaId, options, path));
+ }
+ if (table.schema().id() == schemaId) {
Review Comment:
Fixed in 8c2b14c49d. Before either restoration branch, each physical leaf
now validates its retained schema against the persisted version at that
object's own schema ID. Comparing against its own history permits normal
schema-only ALTER, while rejecting the reversed DROP/CREATE ordering before
returning the object or deriving option deltas. The comparison retains
structural metadata (including IDs and creation time) and excludes dynamic
option overlays, which are legitimately different from physical options.
Existing recursion applies this to delegated/fallback children. The equal-ID
and different-ID race tests both failed before the fix; the full Paimon suite,
including option-precedence and privileged-fallback tests, passes.
--
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]