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

lzljs3620320 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 4ccd244519 [rest] add column masking rules in authTableQuery response 
(#7024)
4ccd244519 is described below

commit 4ccd24451913da5417d69862a65cef84906ca816
Author: Jiajia Li <[email protected]>
AuthorDate: Tue Jan 13 19:01:15 2026 +0800

    [rest] add column masking rules in authTableQuery response (#7024)
---
 docs/static/rest-catalog-open-api.yaml             |  5 ++
 .../main/java/org/apache/paimon/rest/RESTApi.java  | 18 ++++---
 .../rest/responses/AuthTableQueryResponse.java     | 16 ++++++-
 .../org/apache/paimon/catalog/AbstractCatalog.java |  2 +-
 .../java/org/apache/paimon/catalog/Catalog.java    |  7 +--
 .../org/apache/paimon/catalog/DelegateCatalog.java |  2 +-
 .../paimon/catalog/TableQueryAuthResult.java       | 53 ++++++++++++++++++++
 .../java/org/apache/paimon/rest/RESTCatalog.java   | 56 +++++++++++++++++++++-
 .../apache/paimon/table/CatalogEnvironment.java    |  4 +-
 .../apache/paimon/table/source/TableQueryAuth.java |  4 +-
 .../apache/paimon/rest/MockRESTCatalogTest.java    | 46 ++++++++++++++++++
 .../org/apache/paimon/rest/MockRESTMessage.java    | 19 ++++++++
 .../org/apache/paimon/rest/RESTApiJsonTest.java    | 11 +++++
 .../org/apache/paimon/rest/RESTCatalogServer.java  | 14 +++++-
 14 files changed, 234 insertions(+), 23 deletions(-)

diff --git a/docs/static/rest-catalog-open-api.yaml 
b/docs/static/rest-catalog-open-api.yaml
index fcf5c53d11..88e7396514 100644
--- a/docs/static/rest-catalog-open-api.yaml
+++ b/docs/static/rest-catalog-open-api.yaml
@@ -2923,6 +2923,11 @@ components:
           type: array
           items:
             type: string
+        columnMasking:
+          type: object
+          description: Column masking rules as a map from column name to 
transform entry JSON string.
+          additionalProperties:
+            type: string
     AlterDatabaseRequest:
       type: object
       properties:
diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java 
b/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
index a6bf162d55..99266d1dba 100644
--- a/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
+++ b/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
@@ -672,21 +672,19 @@ public class RESTApi {
      *
      * @param identifier database name and table name.
      * @param select select columns, null if select all
-     * @return additional filter for row level access control
+     * @return additional filter for row level access control and column 
masking rules
      * @throws NoSuchResourceException Exception thrown on HTTP 404 means the 
table not exists
      * @throws ForbiddenException Exception thrown on HTTP 403 means don't 
have the permission for
      *     this table
      */
-    public List<String> authTableQuery(Identifier identifier, @Nullable 
List<String> select) {
+    public AuthTableQueryResponse authTableQuery(
+            Identifier identifier, @Nullable List<String> select) {
         AuthTableQueryRequest request = new AuthTableQueryRequest(select);
-        AuthTableQueryResponse response =
-                client.post(
-                        resourcePaths.authTable(
-                                identifier.getDatabaseName(), 
identifier.getObjectName()),
-                        request,
-                        AuthTableQueryResponse.class,
-                        restAuthFunction);
-        return response.filter();
+        return client.post(
+                resourcePaths.authTable(identifier.getDatabaseName(), 
identifier.getObjectName()),
+                request,
+                AuthTableQueryResponse.class,
+                restAuthFunction);
     }
 
     /**
diff --git 
a/paimon-api/src/main/java/org/apache/paimon/rest/responses/AuthTableQueryResponse.java
 
b/paimon-api/src/main/java/org/apache/paimon/rest/responses/AuthTableQueryResponse.java
index 0f833b0330..3aab9ea14e 100644
--- 
a/paimon-api/src/main/java/org/apache/paimon/rest/responses/AuthTableQueryResponse.java
+++ 
b/paimon-api/src/main/java/org/apache/paimon/rest/responses/AuthTableQueryResponse.java
@@ -27,24 +27,38 @@ import 
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonInc
 import 
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
 
 import java.util.List;
+import java.util.Map;
 
 /** Response for auth table query. */
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class AuthTableQueryResponse implements RESTResponse {
 
     private static final String FIELD_FILTER = "filter";
+    private static final String FIELD_COLUMN_MASKING = "columnMasking";
 
     @JsonInclude(JsonInclude.Include.NON_NULL)
     @JsonProperty(FIELD_FILTER)
     private final List<String> filter;
 
     @JsonCreator
-    public AuthTableQueryResponse(@JsonProperty(FIELD_FILTER) List<String> 
filter) {
+    public AuthTableQueryResponse(
+            @JsonProperty(FIELD_FILTER) List<String> filter,
+            @JsonProperty(FIELD_COLUMN_MASKING) Map<String, String> 
columnMasking) {
         this.filter = filter;
+        this.columnMasking = columnMasking;
     }
 
     @JsonGetter(FIELD_FILTER)
     public List<String> filter() {
         return filter;
     }
+
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    @JsonProperty(FIELD_COLUMN_MASKING)
+    private final Map<String, String> columnMasking;
+
+    @JsonGetter(FIELD_COLUMN_MASKING)
+    public Map<String, String> columnMasking() {
+        return columnMasking;
+    }
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
index 045710356b..5d6c102208 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
@@ -577,7 +577,7 @@ public abstract class AbstractCatalog implements Catalog {
     }
 
     @Override
-    public List<String> authTableQuery(Identifier identifier, List<String> 
select) {
+    public TableQueryAuthResult authTableQuery(Identifier identifier, 
List<String> select) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
index 74e35dde3d..f4e7913c24 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
@@ -1032,14 +1032,15 @@ public interface Catalog extends AutoCloseable {
     // ==================== Table Auth ==========================
 
     /**
-     * Auth table query select and get the filter for row level access control.
+     * Auth table query select and get the filter for row level access control 
and column masking
+     * rules.
      *
      * @param identifier path of the table to alter partitions
      * @param select selected fields, null if select all
-     * @return additional filter for row level access control
+     * @return additional filter for row level access control and column 
masking rules
      * @throws TableNotExistException if the table does not exist
      */
-    List<String> authTableQuery(Identifier identifier, @Nullable List<String> 
select)
+    TableQueryAuthResult authTableQuery(Identifier identifier, @Nullable 
List<String> select)
             throws TableNotExistException;
 
     // ==================== Catalog Information ==========================
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
index 5e286191de..b92cd63d94 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
@@ -409,7 +409,7 @@ public abstract class DelegateCatalog implements Catalog {
     }
 
     @Override
-    public List<String> authTableQuery(Identifier identifier, @Nullable 
List<String> select)
+    public TableQueryAuthResult authTableQuery(Identifier identifier, 
@Nullable List<String> select)
             throws TableNotExistException {
         return wrapped.authTableQuery(identifier, select);
     }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/TableQueryAuthResult.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/TableQueryAuthResult.java
new file mode 100644
index 0000000000..dcc94031a8
--- /dev/null
+++ 
b/paimon-core/src/main/java/org/apache/paimon/catalog/TableQueryAuthResult.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.catalog;
+
+import org.apache.paimon.predicate.Predicate;
+import org.apache.paimon.predicate.Transform;
+
+import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.Map;
+
+/** Auth result for table query, including row level filter and optional 
column masking rules. */
+public class TableQueryAuthResult {
+
+    @Nullable private final Predicate rowFilter;
+    private final Map<String, Transform> columnMasking;
+
+    public TableQueryAuthResult(
+            @Nullable Predicate rowFilter, Map<String, Transform> 
columnMasking) {
+        this.rowFilter = rowFilter;
+        this.columnMasking = columnMasking == null ? Collections.emptyMap() : 
columnMasking;
+    }
+
+    public static TableQueryAuthResult empty() {
+        return new TableQueryAuthResult(null, Collections.emptyMap());
+    }
+
+    @Nullable
+    public Predicate rowFilter() {
+        return rowFilter;
+    }
+
+    public Map<String, Transform> columnMasking() {
+        return columnMasking;
+    }
+}
diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java 
b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
index d8254bb58f..c41810c0fd 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
@@ -30,6 +30,7 @@ import org.apache.paimon.catalog.Database;
 import org.apache.paimon.catalog.Identifier;
 import org.apache.paimon.catalog.PropertyChange;
 import org.apache.paimon.catalog.TableMetadata;
+import org.apache.paimon.catalog.TableQueryAuthResult;
 import org.apache.paimon.fs.FileIO;
 import org.apache.paimon.fs.Path;
 import org.apache.paimon.function.Function;
@@ -37,12 +38,17 @@ import org.apache.paimon.function.FunctionChange;
 import org.apache.paimon.options.Options;
 import org.apache.paimon.partition.Partition;
 import org.apache.paimon.partition.PartitionStatistics;
+import org.apache.paimon.predicate.And;
+import org.apache.paimon.predicate.CompoundPredicate;
+import org.apache.paimon.predicate.Predicate;
+import org.apache.paimon.predicate.Transform;
 import org.apache.paimon.rest.exceptions.AlreadyExistsException;
 import org.apache.paimon.rest.exceptions.BadRequestException;
 import org.apache.paimon.rest.exceptions.ForbiddenException;
 import org.apache.paimon.rest.exceptions.NoSuchResourceException;
 import org.apache.paimon.rest.exceptions.NotImplementedException;
 import org.apache.paimon.rest.exceptions.ServiceFailureException;
+import org.apache.paimon.rest.responses.AuthTableQueryResponse;
 import org.apache.paimon.rest.responses.ErrorResponse;
 import org.apache.paimon.rest.responses.GetDatabaseResponse;
 import org.apache.paimon.rest.responses.GetFunctionResponse;
@@ -58,6 +64,7 @@ import org.apache.paimon.table.Table;
 import org.apache.paimon.table.TableSnapshot;
 import org.apache.paimon.table.sink.BatchTableCommit;
 import org.apache.paimon.table.system.SystemTableLoader;
+import org.apache.paimon.utils.JsonSerdeUtil;
 import org.apache.paimon.utils.Pair;
 import org.apache.paimon.utils.SnapshotNotExistException;
 import org.apache.paimon.view.View;
@@ -67,6 +74,8 @@ import org.apache.paimon.view.ViewSchema;
 
 import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils;
 
+import org.jetbrains.annotations.NotNull;
+
 import javax.annotation.Nullable;
 
 import java.io.IOException;
@@ -79,6 +88,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.stream.Collectors;
 
 import static org.apache.paimon.CoreOptions.BRANCH;
@@ -524,11 +534,12 @@ public class RESTCatalog implements Catalog {
     }
 
     @Override
-    public List<String> authTableQuery(Identifier identifier, @Nullable 
List<String> select)
+    public TableQueryAuthResult authTableQuery(Identifier identifier, 
@Nullable List<String> select)
             throws TableNotExistException {
         checkNotSystemTable(identifier, "authTable");
         try {
-            return api.authTableQuery(identifier, select);
+            AuthTableQueryResponse response = api.authTableQuery(identifier, 
select);
+            return getTableQueryAuthResult(response);
         } catch (NoSuchResourceException e) {
             throw new TableNotExistException(identifier);
         } catch (ForbiddenException e) {
@@ -1154,4 +1165,45 @@ public class RESTCatalog implements Catalog {
         }
         return schema;
     }
+
+    private static @NotNull TableQueryAuthResult getTableQueryAuthResult(
+            AuthTableQueryResponse response) {
+        List<String> predicateJsons = response == null ? null : 
response.filter();
+        Predicate rowFilter = null;
+        if (predicateJsons != null && !predicateJsons.isEmpty()) {
+            List<Predicate> predicates = new ArrayList<>();
+            for (String json : predicateJsons) {
+                if (StringUtils.isEmpty(json)) {
+                    continue;
+                }
+                Predicate predicate = JsonSerdeUtil.fromJson(json, 
Predicate.class);
+                if (predicate != null) {
+                    predicates.add(predicate);
+                }
+            }
+            if (predicates.size() == 1) {
+                rowFilter = predicates.get(0);
+            } else if (!predicates.isEmpty()) {
+                rowFilter = new CompoundPredicate(And.INSTANCE, predicates);
+            }
+        }
+
+        Map<String, Transform> columnMasking = new TreeMap<>();
+        Map<String, String> maskingJsons = response == null ? null : 
response.columnMasking();
+        if (maskingJsons != null && !maskingJsons.isEmpty()) {
+            for (Map.Entry<String, String> e : maskingJsons.entrySet()) {
+                String column = e.getKey();
+                String json = e.getValue();
+                if (StringUtils.isEmpty(column) || StringUtils.isEmpty(json)) {
+                    continue;
+                }
+                Transform transform = JsonSerdeUtil.fromJson(json, 
Transform.class);
+                if (transform == null) {
+                    continue;
+                }
+                columnMasking.put(column, transform);
+            }
+        }
+        return new TableQueryAuthResult(rowFilter, columnMasking);
+    }
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/CatalogEnvironment.java 
b/paimon-core/src/main/java/org/apache/paimon/table/CatalogEnvironment.java
index 0f61f8fa09..d07e009214 100644
--- a/paimon-core/src/main/java/org/apache/paimon/table/CatalogEnvironment.java
+++ b/paimon-core/src/main/java/org/apache/paimon/table/CatalogEnvironment.java
@@ -28,6 +28,7 @@ import org.apache.paimon.catalog.CatalogSnapshotCommit;
 import org.apache.paimon.catalog.Identifier;
 import org.apache.paimon.catalog.RenamingSnapshotCommit;
 import org.apache.paimon.catalog.SnapshotCommit;
+import org.apache.paimon.catalog.TableQueryAuthResult;
 import org.apache.paimon.operation.Lock;
 import org.apache.paimon.table.source.TableQueryAuth;
 import org.apache.paimon.tag.SnapshotLoaderImpl;
@@ -37,7 +38,6 @@ import org.apache.paimon.utils.SnapshotManager;
 import javax.annotation.Nullable;
 
 import java.io.Serializable;
-import java.util.Collections;
 import java.util.Optional;
 
 /** Catalog environment in table which contains log factory, metastore client 
factory. */
@@ -154,7 +154,7 @@ public class CatalogEnvironment implements Serializable {
 
     public TableQueryAuth tableQueryAuth(CoreOptions options) {
         if (!options.queryAuthEnabled() || catalogLoader == null) {
-            return select -> Collections.emptyList();
+            return select -> TableQueryAuthResult.empty();
         }
         return select -> {
             try (Catalog catalog = catalogLoader.load()) {
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/source/TableQueryAuth.java 
b/paimon-core/src/main/java/org/apache/paimon/table/source/TableQueryAuth.java
index 96a0dfb3a5..3d45ec2f33 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/table/source/TableQueryAuth.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/table/source/TableQueryAuth.java
@@ -18,6 +18,8 @@
 
 package org.apache.paimon.table.source;
 
+import org.apache.paimon.catalog.TableQueryAuthResult;
+
 import javax.annotation.Nullable;
 
 import java.util.List;
@@ -25,5 +27,5 @@ import java.util.List;
 /** Table query auth. */
 public interface TableQueryAuth {
 
-    List<String> auth(@Nullable List<String> select);
+    TableQueryAuthResult auth(@Nullable List<String> select);
 }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTCatalogTest.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTCatalogTest.java
index 150a8e28eb..7a52bf1af9 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTCatalogTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTCatalogTest.java
@@ -25,8 +25,14 @@ import org.apache.paimon.TableType;
 import org.apache.paimon.catalog.Catalog;
 import org.apache.paimon.catalog.CatalogContext;
 import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.catalog.TableQueryAuthResult;
 import org.apache.paimon.options.CatalogOptions;
 import org.apache.paimon.options.Options;
+import org.apache.paimon.predicate.FieldRef;
+import org.apache.paimon.predicate.Predicate;
+import org.apache.paimon.predicate.PredicateBuilder;
+import org.apache.paimon.predicate.Transform;
+import org.apache.paimon.predicate.UpperTransform;
 import org.apache.paimon.rest.auth.AuthProvider;
 import org.apache.paimon.rest.auth.AuthProviderEnum;
 import org.apache.paimon.rest.auth.BearTokenAuthProvider;
@@ -35,9 +41,12 @@ import org.apache.paimon.rest.auth.DLFTokenLoader;
 import org.apache.paimon.rest.auth.DLFTokenLoaderFactory;
 import org.apache.paimon.rest.auth.RESTAuthParameter;
 import org.apache.paimon.rest.exceptions.NotAuthorizedException;
+import org.apache.paimon.rest.responses.AuthTableQueryResponse;
 import org.apache.paimon.rest.responses.ConfigResponse;
 import org.apache.paimon.schema.Schema;
 import org.apache.paimon.types.DataTypes;
+import org.apache.paimon.types.RowType;
+import org.apache.paimon.utils.JsonSerdeUtil;
 
 import org.apache.paimon.shade.guava30.com.google.common.collect.ImmutableMap;
 
@@ -55,6 +64,7 @@ import java.util.UUID;
 
 import static org.apache.paimon.catalog.Catalog.TABLE_DEFAULT_OPTION_PREFIX;
 import static org.apache.paimon.rest.RESTApi.HEADER_PREFIX;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -246,6 +256,42 @@ class MockRESTCatalogTest extends RESTCatalogTest {
         catalog.dropTable(identifier, true);
     }
 
+    @Test
+    void testAuthTableQueryResponseWithColumnMasking() throws Exception {
+        Identifier identifier = Identifier.create("test_db", "auth_table");
+        catalog.createDatabase(identifier.getDatabaseName(), true);
+        catalog.createTable(
+                Identifier.create(identifier.getDatabaseName(), 
identifier.getTableName()),
+                DEFAULT_TABLE_SCHEMA,
+                false);
+
+        PredicateBuilder builder =
+                new PredicateBuilder(RowType.of(DataTypes.INT(), 
DataTypes.STRING()));
+        Predicate predicate = builder.equal(0, 100);
+        String predicateJson = JsonSerdeUtil.toFlatJson(predicate);
+
+        Transform transform =
+                new UpperTransform(
+                        Collections.singletonList(new FieldRef(1, "col2", 
DataTypes.STRING())));
+        String transformJson = JsonSerdeUtil.toFlatJson(transform);
+
+        // Set up mock response with filter and columnMasking
+        List<String> filter = Collections.singletonList(predicateJson);
+        Map<String, String> columnMasking = new HashMap<>();
+        columnMasking.put("col2", transformJson);
+        AuthTableQueryResponse response = new AuthTableQueryResponse(filter, 
columnMasking);
+        restCatalogServer.setTableQueryAuthResponse(identifier, response);
+
+        TableQueryAuthResult result = catalog.authTableQuery(identifier, null);
+        assertThat(result.rowFilter()).isEqualTo(predicate);
+        assertThat(result.columnMasking()).isNotEmpty();
+        assertThat(result.columnMasking()).containsKey("col2");
+        assertThat(result.columnMasking().get("col2")).isEqualTo(transform);
+
+        catalog.dropTable(identifier, true);
+        catalog.dropDatabase(identifier.getDatabaseName(), true, true);
+    }
+
     private void checkHeader(String headerName, String headerValue) {
         // Verify that the header were included in the requests
         List<Map<String, String>> receivedHeaders = 
restCatalogServer.getReceivedHeaders();
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
index f487815e4d..d202d41ea1 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
@@ -24,6 +24,10 @@ import org.apache.paimon.function.FunctionChange;
 import org.apache.paimon.function.FunctionDefinition;
 import org.apache.paimon.function.FunctionImpl;
 import org.apache.paimon.partition.Partition;
+import org.apache.paimon.predicate.Equal;
+import org.apache.paimon.predicate.FieldRef;
+import org.apache.paimon.predicate.LeafPredicate;
+import org.apache.paimon.predicate.UpperTransform;
 import org.apache.paimon.rest.requests.AlterDatabaseRequest;
 import org.apache.paimon.rest.requests.AlterFunctionRequest;
 import org.apache.paimon.rest.requests.AlterTableRequest;
@@ -35,6 +39,7 @@ import org.apache.paimon.rest.requests.CreateViewRequest;
 import org.apache.paimon.rest.requests.RenameTableRequest;
 import org.apache.paimon.rest.requests.RollbackTableRequest;
 import org.apache.paimon.rest.responses.AlterDatabaseResponse;
+import org.apache.paimon.rest.responses.AuthTableQueryResponse;
 import org.apache.paimon.rest.responses.GetDatabaseResponse;
 import org.apache.paimon.rest.responses.GetFunctionResponse;
 import org.apache.paimon.rest.responses.GetTableResponse;
@@ -52,6 +57,7 @@ import org.apache.paimon.types.DataType;
 import org.apache.paimon.types.DataTypes;
 import org.apache.paimon.types.IntType;
 import org.apache.paimon.types.RowType;
+import org.apache.paimon.utils.JsonSerdeUtil;
 import org.apache.paimon.view.ViewChange;
 import org.apache.paimon.view.ViewSchema;
 
@@ -382,4 +388,17 @@ public class MockRESTMessage {
         List<String> primaryKeys = Arrays.asList("f0", "f1");
         return new Schema(fields, partitionKeys, primaryKeys, options, 
"comment");
     }
+
+    public static AuthTableQueryResponse authTableQueryResponse() {
+        LeafPredicate predicate =
+                new LeafPredicate(
+                        Equal.INSTANCE, DataTypes.INT(), 0, "id", 
Collections.singletonList(1));
+        List<String> filter = 
java.util.Arrays.asList(JsonSerdeUtil.toFlatJson(predicate));
+        Map<String, String> columnMasking = new HashMap<>();
+        FieldRef fieldRef = new FieldRef(1, "f1", DataTypes.STRING());
+        UpperTransform upperTransform = new 
UpperTransform(Collections.singletonList(fieldRef));
+        columnMasking.put("c1", JsonSerdeUtil.toFlatJson(upperTransform));
+
+        return new AuthTableQueryResponse(filter, columnMasking);
+    }
 }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTApiJsonTest.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTApiJsonTest.java
index 10aea7f3b4..1b8b1f71d0 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTApiJsonTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTApiJsonTest.java
@@ -29,6 +29,7 @@ import org.apache.paimon.rest.requests.CreateViewRequest;
 import org.apache.paimon.rest.requests.RenameTableRequest;
 import org.apache.paimon.rest.requests.RollbackTableRequest;
 import org.apache.paimon.rest.responses.AlterDatabaseResponse;
+import org.apache.paimon.rest.responses.AuthTableQueryResponse;
 import org.apache.paimon.rest.responses.ConfigResponse;
 import org.apache.paimon.rest.responses.ErrorResponse;
 import org.apache.paimon.rest.responses.GetDatabaseResponse;
@@ -298,4 +299,14 @@ public class RESTApiJsonTest {
         AlterFunctionRequest parseData = RESTApi.fromJson(requestStr, 
AlterFunctionRequest.class);
         assertEquals(parseData.changes().size(), request.changes().size());
     }
+
+    @Test
+    public void authTableQueryResponseParseTest() throws Exception {
+        AuthTableQueryResponse response = 
MockRESTMessage.authTableQueryResponse();
+        String responseStr = RESTApi.toJson(response);
+        AuthTableQueryResponse parseData =
+                RESTApi.fromJson(responseStr, AuthTableQueryResponse.class);
+        assertEquals(response.filter(), parseData.filter());
+        assertEquals(response.columnMasking(), parseData.columnMasking());
+    }
 }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java
index 544b490385..ff4d932501 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java
@@ -107,6 +107,7 @@ import org.apache.paimon.view.ViewChange;
 import org.apache.paimon.view.ViewImpl;
 import org.apache.paimon.view.ViewSchema;
 
+import org.apache.paimon.shade.guava30.com.google.common.collect.ImmutableMap;
 import 
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.core.JsonProcessingException;
 import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils;
 
@@ -116,7 +117,6 @@ import okhttp3.mockwebserver.MockWebServer;
 import okhttp3.mockwebserver.RecordedRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
 
 import javax.annotation.Nullable;
 
@@ -185,6 +185,8 @@ public class RESTCatalogServer {
     private final List<String> noPermissionTables = new ArrayList<>();
     private final Map<String, Function> functionStore = new HashMap<>();
     private final Map<String, List<String>> columnAuthHandler = new 
HashMap<>();
+    private final Map<String, AuthTableQueryResponse> 
tableQueryAuthResponseHandler =
+            new HashMap<>();
     public final ConfigResponse configResponse;
     public final String warehouse;
 
@@ -266,6 +268,10 @@ public class RESTCatalogServer {
         columnAuthHandler.put(identifier.getFullName(), select);
     }
 
+    public void setTableQueryAuthResponse(Identifier identifier, 
AuthTableQueryResponse response) {
+        tableQueryAuthResponseHandler.put(identifier.getFullName(), response);
+    }
+
     public RESTToken getDataToken(Identifier identifier) {
         return DataTokenStore.getDataToken(warehouse, 
identifier.getFullName());
     }
@@ -829,7 +835,11 @@ public class RESTCatalogServer {
                         }
                     });
         }
-        AuthTableQueryResponse response = new 
AuthTableQueryResponse(Collections.emptyList());
+        AuthTableQueryResponse response =
+                tableQueryAuthResponseHandler.get(identifier.getFullName());
+        if (response == null) {
+            response = new AuthTableQueryResponse(Collections.emptyList(), 
ImmutableMap.of());
+        }
         return mockResponse(response, 200);
     }
 

Reply via email to