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

XiaoHongbo-Hope pushed a commit to branch release-2.1
in repository https://gitbox.apache.org/repos/asf/paimon.git

commit b09fafcd1febd93cb9050275cd20f5f3e42c8432
Author: YeJunHao <[email protected]>
AuthorDate: Thu Sep 17 18:24:50 2026 +0800

    [core] Preserve query authorization when wrapping data evolution index 
splits (#9925)
---
 .../paimon/globalindex/DataEvolutionBatchScan.java | 23 +++++---
 .../globalindex/DataEvolutionBatchScanTest.java    | 68 ++++++++++++++++++++++
 2 files changed, 83 insertions(+), 8 deletions(-)

diff --git 
a/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionBatchScan.java
 
b/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionBatchScan.java
index e412d8123f..618a0ee765 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionBatchScan.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionBatchScan.java
@@ -37,6 +37,7 @@ import org.apache.paimon.table.source.AppendBatchTableScan;
 import org.apache.paimon.table.source.DataSplit;
 import org.apache.paimon.table.source.DataTableScan;
 import org.apache.paimon.table.source.InnerTableScan;
+import org.apache.paimon.table.source.QueryAuthSplit;
 import org.apache.paimon.table.source.Split;
 import org.apache.paimon.types.RowType;
 import org.apache.paimon.utils.Filter;
@@ -455,18 +456,24 @@ public class DataEvolutionBatchScan implements 
DataTableScan {
     public static Plan wrapToIndexSplits(
             List<Split> splits, RowRangeIndex rowRangeIndex, ScoreGetter 
scoreGetter) {
         List<Split> indexedSplits = new ArrayList<>();
-        Function<Split, List<IndexedSplit>> process =
-                split ->
-                        Collections.singletonList(
-                                split instanceof IndexedSplit
-                                        ? (IndexedSplit) split
-                                        : wrap((DataSplit) split, 
rowRangeIndex, scoreGetter));
+        Function<Split, List<Split>> process =
+                split -> Collections.singletonList(wrap(split, rowRangeIndex, 
scoreGetter));
         randomlyExecuteSequentialReturn(process, splits, 
null).forEachRemaining(indexedSplits::add);
         return () -> indexedSplits;
     }
 
-    private static IndexedSplit wrap(
-            DataSplit dataSplit, final RowRangeIndex rowRangeIndex, 
ScoreGetter scoreGetter) {
+    private static Split wrap(
+            Split split, final RowRangeIndex rowRangeIndex, ScoreGetter 
scoreGetter) {
+        if (split instanceof QueryAuthSplit) {
+            QueryAuthSplit authSplit = (QueryAuthSplit) split;
+            return new QueryAuthSplit(
+                    wrap(authSplit.split(), rowRangeIndex, scoreGetter), 
authSplit.authResult());
+        }
+        if (split instanceof IndexedSplit) {
+            return split;
+        }
+
+        DataSplit dataSplit = (DataSplit) split;
         List<DataFileMeta> files = dataSplit.dataFiles();
 
         List<Range> expected = new ArrayList<>();
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/globalindex/DataEvolutionBatchScanTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/globalindex/DataEvolutionBatchScanTest.java
index 78771719d0..8ec43fe004 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/globalindex/DataEvolutionBatchScanTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/globalindex/DataEvolutionBatchScanTest.java
@@ -18,6 +18,7 @@
 
 package org.apache.paimon.globalindex;
 
+import org.apache.paimon.catalog.TableQueryAuthResult;
 import org.apache.paimon.data.BinaryRow;
 import org.apache.paimon.io.DataFileMeta;
 import org.apache.paimon.predicate.Predicate;
@@ -25,6 +26,7 @@ import org.apache.paimon.predicate.PredicateBuilder;
 import org.apache.paimon.table.source.AppendBatchTableScan;
 import org.apache.paimon.table.source.DataSplit;
 import org.apache.paimon.table.source.DataTableScan;
+import org.apache.paimon.table.source.QueryAuthSplit;
 import org.apache.paimon.table.source.Split;
 import org.apache.paimon.table.source.snapshot.SnapshotReader;
 import org.apache.paimon.types.DataField;
@@ -34,6 +36,8 @@ import org.apache.paimon.utils.Range;
 import org.apache.paimon.utils.RowRangeIndex;
 
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.ArgumentCaptor;
 
 import java.util.ArrayList;
@@ -210,6 +214,70 @@ public class DataEvolutionBatchScanTest {
                 .containsExactly(new Range(4200, 4450), new Range(4650, 4700));
     }
 
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    public void testWrapToIndexSplitsWithQueryAuth(boolean hasAuthResult) {
+        DataSplit split =
+                DataSplit.builder()
+                        .withSnapshot(1L)
+                        .withPartition(BinaryRow.EMPTY_ROW)
+                        .withBucket(0)
+                        .withBucketPath("bucket-0")
+                        
.withDataFiles(Collections.singletonList(newAppendFile(0L, 10L, "file-0")))
+                        .build();
+        TableQueryAuthResult authResult =
+                hasAuthResult
+                        ? new TableQueryAuthResult(
+                                Collections.singletonList("filter-json"),
+                                Collections.singletonMap("f0", "mask-json"))
+                        : null;
+        QueryAuthSplit authSplit = new QueryAuthSplit(split, authResult);
+
+        List<Split> indexedSplits =
+                DataEvolutionBatchScan.wrapToIndexSplits(
+                                Collections.singletonList(authSplit),
+                                RowRangeIndex.create(
+                                        Arrays.asList(new Range(1, 2), new 
Range(7, 12))),
+                                rowId -> rowId + 0.5f)
+                        .splits();
+
+        assertThat(indexedSplits).hasSize(1);
+        assertThat(indexedSplits.get(0)).isInstanceOf(QueryAuthSplit.class);
+        QueryAuthSplit indexedAuthSplit = (QueryAuthSplit) 
indexedSplits.get(0);
+        assertThat(indexedAuthSplit.authResult()).isSameAs(authResult);
+        assertThat(indexedAuthSplit.split()).isInstanceOf(IndexedSplit.class);
+        IndexedSplit indexedSplit = (IndexedSplit) indexedAuthSplit.split();
+        assertThat(indexedSplit.dataSplit()).isSameAs(split);
+        assertThat(indexedSplit.rowRanges()).containsExactly(new Range(1, 2), 
new Range(7, 9));
+        assertThat(indexedSplit.scores()).containsExactly(1.5f, 2.5f, 7.5f, 
8.5f, 9.5f);
+        assertThat(authSplit.split()).isSameAs(split);
+    }
+
+    @Test
+    public void testWrapToIndexSplitsKeepsExistingIndexedSplits() {
+        IndexedSplit indexedSplit =
+                new IndexedSplit(
+                        mock(DataSplit.class),
+                        Collections.singletonList(new Range(1, 2)),
+                        new float[] {1.5f, 2.5f});
+        TableQueryAuthResult authResult = mock(TableQueryAuthResult.class);
+
+        List<Split> indexedSplits =
+                DataEvolutionBatchScan.wrapToIndexSplits(
+                                Arrays.asList(
+                                        indexedSplit, new 
QueryAuthSplit(indexedSplit, authResult)),
+                                null,
+                                null)
+                        .splits();
+
+        assertThat(indexedSplits).hasSize(2);
+        assertThat(indexedSplits.get(0)).isSameAs(indexedSplit);
+        assertThat(indexedSplits.get(1)).isInstanceOf(QueryAuthSplit.class);
+        QueryAuthSplit indexedAuthSplit = (QueryAuthSplit) 
indexedSplits.get(1);
+        assertThat(indexedAuthSplit.authResult()).isSameAs(authResult);
+        assertThat(indexedAuthSplit.split()).isSameAs(indexedSplit);
+    }
+
     private static RowType rowTypeWithRowId() {
         return RowType.of(
                 new DataField(0, "f0", DataTypes.INT()),

Reply via email to