This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new ac74224c40 [core] Keep all sibling tags of a snapshot as Iceberg refs 
(#10248)
ac74224c40 is described below

commit ac74224c406c208a38ef8c62334e40b4d1b63ab8
Author: YangJie <[email protected]>
AuthorDate: Mon Oct 5 10:07:34 2026 -0400

    [core] Keep all sibling tags of a snapshot as Iceberg refs (#10248)
---
 .../paimon/iceberg/IcebergCommitCallback.java      | 18 +++++++-----
 .../paimon/iceberg/IcebergCompatibilityTest.java   | 32 ++++++++++++++++++++++
 .../flink/iceberg/FlinkIcebergITCaseBase.java      | 13 +++++++++
 3 files changed, 56 insertions(+), 7 deletions(-)

diff --git 
a/paimon-core/src/main/java/org/apache/paimon/iceberg/IcebergCommitCallback.java
 
b/paimon-core/src/main/java/org/apache/paimon/iceberg/IcebergCommitCallback.java
index 08aaf110af..1a74f12309 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/iceberg/IcebergCommitCallback.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/iceberg/IcebergCommitCallback.java
@@ -1219,13 +1219,17 @@ public class IcebergCommitCallback implements 
CommitCallback, TagCallback {
         // exists. Otherwise an Iceberg client fails to parse the metadata and 
all reads fail.
         Set<Long> snapshotIds =
                 
snapshots.stream().map(IcebergSnapshot::snapshotId).collect(Collectors.toSet());
-        Map<String, IcebergRef> refs =
-                table.tagManager().tags().entrySet().stream()
-                        .filter(entry -> 
snapshotIds.contains(entry.getKey().id()))
-                        .collect(
-                                Collectors.toMap(
-                                        entry -> entry.getValue().get(0),
-                                        entry -> new 
IcebergRef(entry.getKey().id())));
+        // every tag of a snapshot becomes its own ref: dropping sibling tags 
would make
+        // them invisible in Iceberg and break VERSION AS OF for them
+        Map<String, IcebergRef> refs = new HashMap<>();
+        for (Map.Entry<Snapshot, List<String>> entry : 
table.tagManager().tags().entrySet()) {
+            long taggedSnapshotId = entry.getKey().id();
+            if (snapshotIds.contains(taggedSnapshotId)) {
+                for (String tagName : entry.getValue()) {
+                    refs.put(tagName, new IcebergRef(taggedSnapshotId));
+                }
+            }
+        }
 
         IcebergMetadata metadata =
                 new IcebergMetadata(
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/iceberg/IcebergCompatibilityTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/iceberg/IcebergCompatibilityTest.java
index 62e060489e..023df89537 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/iceberg/IcebergCompatibilityTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/iceberg/IcebergCompatibilityTest.java
@@ -1944,6 +1944,38 @@ public class IcebergCompatibilityTest {
                 .containsExactly("k", "v", "branch_only");
     }
 
+    @Test
+    public void testSiblingTagsOnOneSnapshotAllBecomeRefs() throws Exception {
+        RowType rowType =
+                RowType.of(
+                        new DataType[] {DataTypes.INT(), DataTypes.INT()}, new 
String[] {"k", "v"});
+        FileStoreTable table =
+                createPaimonTable(
+                        rowType, Collections.emptyList(), 
Collections.singletonList("k"), 1);
+
+        String commitUser = UUID.randomUUID().toString();
+        TableWriteImpl<?> write = table.newWrite(commitUser);
+        TableCommitImpl commit = table.newCommit(commitUser);
+
+        write.write(GenericRow.of(1, 10));
+        commit.commit(1, write.prepareCommit(false, 1));
+
+        // create the tags without the Iceberg tag callback, so v1 metadata 
carries no refs and
+        // only the next commit's rebuild from the tag list can produce them
+        Snapshot snapshot = table.snapshotManager().snapshot(1);
+        table.tagManager().createTag(snapshot, "first", null, 
Collections.emptyList(), false);
+        table.tagManager().createTag(snapshot, "second", null, 
Collections.emptyList(), false);
+
+        write.write(GenericRow.of(2, 20));
+        commit.commit(2, write.prepareCommit(false, 2));
+
+        long latestSnapshotId = table.snapshotManager().latestSnapshotId();
+        Map<String, IcebergRef> refs = getIcebergRefsFromSnapshot(table, 
latestSnapshotId);
+        assertThat(refs).containsOnlyKeys("first", "second");
+        assertThat(refs.get("first").snapshotId()).isEqualTo(1);
+        assertThat(refs.get("second").snapshotId()).isEqualTo(1);
+    }
+
     /*
     Create snapshots
     Create tags
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/iceberg/FlinkIcebergITCaseBase.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/iceberg/FlinkIcebergITCaseBase.java
index 80279a2688..8210443cbd 100644
--- 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/iceberg/FlinkIcebergITCaseBase.java
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/iceberg/FlinkIcebergITCaseBase.java
@@ -554,6 +554,19 @@ public abstract class FlinkIcebergITCaseBase extends 
AbstractTestBase {
                                 tEnv.executeSql(
                                         "SELECT name, type, snapshot_id FROM 
iceberg.`default`.T$refs")))
                 .containsExactlyInAnyOrder(Row.of("tag1", "TAG", 1L), 
Row.of("tag2", "TAG", 4L));
+
+        // a second tag on snapshot 4 must survive the next commit, which 
rebuilds the refs
+        tEnv.executeSql("CALL paimon.sys.create_tag('default.T', 'tag3', 4)");
+        tEnv.executeSql("INSERT INTO paimon.`default`.T VALUES (1, 13, 131, 
'black')").await();
+
+        assertThat(
+                        collect(
+                                tEnv.executeSql(
+                                        "SELECT name, type, snapshot_id FROM 
iceberg.`default`.T$refs")))
+                .containsExactlyInAnyOrder(
+                        Row.of("tag1", "TAG", 1L),
+                        Row.of("tag2", "TAG", 4L),
+                        Row.of("tag3", "TAG", 4L));
     }
 
     @ParameterizedTest

Reply via email to