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 4edc41b7a0 [core] RestCatalog: support ListObjectsByPattern (#5530)
4edc41b7a0 is described below

commit 4edc41b7a0b34c7b65e4368b13f5e215025b7362
Author: XiaoHongbo <[email protected]>
AuthorDate: Mon Apr 28 21:15:53 2025 +0800

    [core] RestCatalog: support ListObjectsByPattern (#5530)
---
 .../org/apache/paimon/catalog/AbstractCatalog.java |  15 +-
 .../java/org/apache/paimon/catalog/Catalog.java    |  71 +++++-
 .../org/apache/paimon/catalog/CatalogUtils.java    |  10 +
 .../org/apache/paimon/catalog/DelegateCatalog.java |  28 ++-
 .../java/org/apache/paimon/rest/RESTCatalog.java   |  63 ++++-
 .../main/java/org/apache/paimon/rest/RESTUtil.java |  31 +++
 .../org/apache/paimon/catalog/CatalogTestBase.java | 101 +++++---
 .../apache/paimon/rest/MockRESTCatalogTest.java    |   5 +-
 .../org/apache/paimon/rest/RESTCatalogServer.java  | 116 +++++++--
 .../org/apache/paimon/rest/RESTCatalogTest.java    | 276 +++++++++++++++++----
 .../java/org/apache/paimon/hive/HiveCatalog.java   |  17 +-
 paimon-open-api/rest-catalog-open-api.yaml         |  25 ++
 .../paimon/open/api/RESTCatalogController.java     |  50 +++-
 13 files changed, 653 insertions(+), 155 deletions(-)

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 eef17df5c2..79d963718d 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
@@ -179,8 +179,12 @@ public abstract class AbstractCatalog implements Catalog {
 
     @Override
     public PagedList<Partition> listPartitionsPaged(
-            Identifier identifier, Integer maxResults, String pageToken)
+            Identifier identifier,
+            Integer maxResults,
+            String pageToken,
+            String partitionNamePattern)
             throws TableNotExistException {
+        CatalogUtils.validateNamePattern(this, partitionNamePattern);
         return new PagedList<>(listPartitions(identifier), null);
     }
 
@@ -242,15 +246,17 @@ public abstract class AbstractCatalog implements Catalog {
 
     @Override
     public PagedList<String> listTablesPaged(
-            String databaseName, Integer maxResults, String pageToken)
+            String databaseName, Integer maxResults, String pageToken, String 
tableNamePattern)
             throws DatabaseNotExistException {
+        CatalogUtils.validateNamePattern(this, tableNamePattern);
         return new PagedList<>(listTables(databaseName), null);
     }
 
     @Override
     public PagedList<Table> listTableDetailsPaged(
-            String databaseName, Integer maxResults, String pageToken)
+            String databaseName, Integer maxResults, String pageToken, String 
tableNamePattern)
             throws DatabaseNotExistException {
+        CatalogUtils.validateNamePattern(this, tableNamePattern);
         if (isSystemDatabase(databaseName)) {
             List<Table> systemTables =
                     SystemTableLoader.loadGlobalTableNames().stream()
@@ -283,7 +289,8 @@ public abstract class AbstractCatalog implements Catalog {
     protected PagedList<Table> listTableDetailsPagedImpl(
             String databaseName, Integer maxResults, String pageToken)
             throws DatabaseNotExistException {
-        PagedList<String> pagedTableNames = listTablesPaged(databaseName, 
maxResults, pageToken);
+        PagedList<String> pagedTableNames =
+                listTablesPaged(databaseName, maxResults, pageToken, null);
         return new PagedList<>(
                 pagedTableNames.getElements().stream()
                         .map(
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 7d47459a26..743a2ae760 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
@@ -164,13 +164,19 @@ public interface Catalog extends AutoCloseable {
      *     max results.
      * @param pageToken Optional parameter indicating the next page token 
allows list to be start
      *     from a specific point.
+     * @param tableNamePattern A sql LIKE pattern (% and _) for table names. 
All tables will be
+     *     returned if not set or empty. Currently, only prefix matching is 
supported. Note please
+     *     escape the underline if you want to match it exactly.
      * @return a list of the names of tables with provided page size in this 
database and next page
      *     token, or a list of the names of all tables in this database if the 
catalog does not
      *     {@link #supportsListObjectsPaged()}.
      * @throws DatabaseNotExistException if the database does not exist
      */
     PagedList<String> listTablesPaged(
-            String databaseName, @Nullable Integer maxResults, @Nullable 
String pageToken)
+            String databaseName,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String tableNamePattern)
             throws DatabaseNotExistException;
 
     /**
@@ -185,13 +191,19 @@ public interface Catalog extends AutoCloseable {
      *     max results.
      * @param pageToken Optional parameter indicating the next page token 
allows list to be start
      *     from a specific point.
+     * @param tableNamePattern A sql LIKE pattern (% and _) for table names. 
All table details will
+     *     be returned if not set or empty. Currently, only prefix matching is 
supported. Note
+     *     please escape the underline if you want to match it exactly.
      * @return a list of the table details with provided page size in this 
database and next page
      *     token, or a list of the details of all tables in this database if 
the catalog does not
      *     {@link #supportsListObjectsPaged()}.
      * @throws DatabaseNotExistException if the database does not exist
      */
     PagedList<Table> listTableDetailsPaged(
-            String databaseName, @Nullable Integer maxResults, @Nullable 
String pageToken)
+            String databaseName,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String tableNamePattern)
             throws DatabaseNotExistException;
 
     /**
@@ -310,13 +322,19 @@ public interface Catalog extends AutoCloseable {
      *     max results.
      * @param pageToken Optional parameter indicating the next page token 
allows list to be start
      *     from a specific point.
+     * @param partitionNamePattern A sql LIKE pattern (% and _) for partition 
names. All partitions
+     *     will be * returned if not set or empty. Currently, only prefix 
matching is supported.
+     *     Note please * escape the underline if you want to match it exactly.
      * @return a list of the partitions with provided page size(@param 
maxResults) in this table and
      *     next page token, or a list of all partitions of the table if the 
catalog does not {@link
      *     #supportsListObjectsPaged()}.
      * @throws TableNotExistException if the table does not exist
      */
     PagedList<Partition> listPartitionsPaged(
-            Identifier identifier, @Nullable Integer maxResults, @Nullable 
String pageToken)
+            Identifier identifier,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String partitionNamePattern)
             throws TableNotExistException;
 
     // ======================= view methods ===============================
@@ -380,13 +398,19 @@ public interface Catalog extends AutoCloseable {
      *     max results.
      * @param pageToken Optional parameter indicating the next page token 
allows list to be start
      *     from a specific point.
+     * @param viewNamePattern A sql LIKE pattern (% and _) for view names. All 
views will be
+     *     returned if not set or empty. Currently, only prefix matching is 
supported. Note please
+     *     escape the underline if you want to match it exactly.
      * @return a list of the names of views with provided page size in this 
database and next page
      *     token, or a list of the names of all views in this database if the 
catalog does not
      *     {@link #supportsListObjectsPaged()}.
      * @throws DatabaseNotExistException if the database does not exist
      */
     default PagedList<String> listViewsPaged(
-            String databaseName, @Nullable Integer maxResults, @Nullable 
String pageToken)
+            String databaseName,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String viewNamePattern)
             throws DatabaseNotExistException {
         return new PagedList<>(listViews(databaseName), null);
     }
@@ -401,13 +425,19 @@ public interface Catalog extends AutoCloseable {
      *     max results.
      * @param pageToken Optional parameter indicating the next page token 
allows list to be start
      *     from a specific point.
+     * @param viewNamePattern A sql LIKE pattern (% and _) for view names. All 
view details will be
+     *     returned if not set or empty. Currently, only prefix matching is 
supported. Note please
+     *     escape the underline if you want to match it exactly.
      * @return a list of the view details with provided page size (@param 
maxResults) in this
      *     database and next page token, or a list of the details of all views 
in this database if
      *     the catalog does not {@link #supportsListObjectsPaged()}.
      * @throws DatabaseNotExistException if the database does not exist
      */
     default PagedList<View> listViewDetailsPaged(
-            String databaseName, @Nullable Integer maxResults, @Nullable 
String pageToken)
+            String databaseName,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String viewNamePattern)
             throws DatabaseNotExistException {
         return new PagedList<>(Collections.emptyList(), null);
     }
@@ -467,21 +497,38 @@ public interface Catalog extends AutoCloseable {
     }
 
     /**
-     * Whether this catalog supports version management for tables. If not, 
corresponding methods
-     * will fall back to listing all objects. For example, {@link 
#listTablesPaged(String, Integer,
+     * Whether this catalog supports list objects paged. If not, corresponding 
methods will fall
+     * back to listing all objects. For example, {@link 
#listTablesPaged(String, Integer, String,
      * String)} would fall back to {@link #listTables(String)}.
      *
      * <ul>
      *   <li>{@link #listDatabasesPaged(Integer, String)}.
-     *   <li>{@link #listTablesPaged(String, Integer, String)}.
-     *   <li>{@link #listTableDetailsPaged(String, Integer, String)}.
-     *   <li>{@link #listViewsPaged(String, Integer, String)}.
-     *   <li>{@link #listViewDetailsPaged(String, Integer, String)}.
-     *   <li>{@link #listPartitionsPaged(Identifier, Integer, String)}.
+     *   <li>{@link #listTablesPaged(String, Integer, String, String)}.
+     *   <li>{@link #listTableDetailsPaged(String, Integer, String, String)}.
+     *   <li>{@link #listViewsPaged(String, Integer, String, String)}.
+     *   <li>{@link #listViewDetailsPaged(String, Integer, String, String)}.
+     *   <li>{@link #listPartitionsPaged(Identifier, Integer, String, String)}.
      * </ul>
      */
     boolean supportsListObjectsPaged();
 
+    /**
+     * Whether this catalog supports name pattern filter when list objects 
paged. If not,
+     * corresponding methods will throw exception if name pattern provided.
+     *
+     * <ul>
+     *   <li>{@link #listDatabasesPaged(Integer, String)}.
+     *   <li>{@link #listTablesPaged(String, Integer, String, String)}.
+     *   <li>{@link #listTableDetailsPaged(String, Integer, String, String)}.
+     *   <li>{@link #listViewsPaged(String, Integer, String, String)}.
+     *   <li>{@link #listViewDetailsPaged(String, Integer, String, String)}.
+     *   <li>{@link #listPartitionsPaged(Identifier, Integer, String, String)}.
+     * </ul>
+     */
+    default boolean supportsListByPattern() {
+        return false;
+    }
+
     // ==================== Version management methods 
==========================
 
     /**
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/CatalogUtils.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/CatalogUtils.java
index bdbfe41587..37346aac94 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/CatalogUtils.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/CatalogUtils.java
@@ -45,6 +45,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Function;
 
 import static org.apache.paimon.CoreOptions.PARTITION_DEFAULT_NAME;
@@ -137,6 +138,15 @@ public class CatalogUtils {
                         CoreOptions.AUTO_CREATE.key(), Boolean.FALSE));
     }
 
+    public static void validateNamePattern(Catalog catalog, String 
namePattern) {
+        if (Objects.nonNull(namePattern) && !catalog.supportsListByPattern()) {
+            throw new UnsupportedOperationException(
+                    String.format(
+                            "Current catalog %s does not support name pattern 
filter.",
+                            catalog.getClass().getSimpleName()));
+        }
+    }
+
     public static List<Partition> listPartitionsFromFileSystem(Table table) {
         Options options = Options.fromMap(table.options());
         InternalRowPartitionComputer computer =
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 af64463fb5..d45e92ab24 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
@@ -99,16 +99,16 @@ public abstract class DelegateCatalog implements Catalog {
 
     @Override
     public PagedList<String> listTablesPaged(
-            String databaseName, Integer maxResults, String pageToken)
+            String databaseName, Integer maxResults, String pageToken, String 
tableNamePattern)
             throws DatabaseNotExistException {
-        return wrapped.listTablesPaged(databaseName, maxResults, pageToken);
+        return wrapped.listTablesPaged(databaseName, maxResults, pageToken, 
tableNamePattern);
     }
 
     @Override
     public PagedList<Table> listTableDetailsPaged(
-            String databaseName, Integer maxResults, String pageToken)
+            String databaseName, Integer maxResults, String pageToken, String 
tableNamePattern)
             throws DatabaseNotExistException {
-        return wrapped.listTableDetailsPaged(databaseName, maxResults, 
pageToken);
+        return wrapped.listTableDetailsPaged(databaseName, maxResults, 
pageToken, tableNamePattern);
     }
 
     @Override
@@ -141,6 +141,11 @@ public abstract class DelegateCatalog implements Catalog {
         return wrapped.supportsListObjectsPaged();
     }
 
+    @Override
+    public boolean supportsListByPattern() {
+        return wrapped.supportsListByPattern();
+    }
+
     @Override
     public boolean supportsVersionManagement() {
         return wrapped.supportsVersionManagement();
@@ -239,16 +244,16 @@ public abstract class DelegateCatalog implements Catalog {
 
     @Override
     public PagedList<String> listViewsPaged(
-            String databaseName, Integer maxResults, String pageToken)
+            String databaseName, Integer maxResults, String pageToken, String 
tableNamePattern)
             throws DatabaseNotExistException {
-        return wrapped.listViewsPaged(databaseName, maxResults, pageToken);
+        return wrapped.listViewsPaged(databaseName, maxResults, pageToken, 
tableNamePattern);
     }
 
     @Override
     public PagedList<View> listViewDetailsPaged(
-            String databaseName, Integer maxResults, String pageToken)
+            String databaseName, Integer maxResults, String pageToken, String 
tableNamePattern)
             throws DatabaseNotExistException {
-        return wrapped.listViewDetailsPaged(databaseName, maxResults, 
pageToken);
+        return wrapped.listViewDetailsPaged(databaseName, maxResults, 
pageToken, tableNamePattern);
     }
 
     @Override
@@ -270,9 +275,12 @@ public abstract class DelegateCatalog implements Catalog {
 
     @Override
     public PagedList<Partition> listPartitionsPaged(
-            Identifier identifier, Integer maxResults, String pageToken)
+            Identifier identifier,
+            Integer maxResults,
+            String pageToken,
+            String partitionNamePattern)
             throws TableNotExistException {
-        return wrapped.listPartitionsPaged(identifier, maxResults, pageToken);
+        return wrapped.listPartitionsPaged(identifier, maxResults, pageToken, 
partitionNamePattern);
     }
 
     @Override
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 53336f5f2c..50c8ebbe65 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
@@ -129,6 +129,10 @@ public class RESTCatalog implements Catalog {
     public static final String PAGE_TOKEN = "pageToken";
     public static final String QUERY_PARAMETER_WAREHOUSE_KEY = "warehouse";
 
+    public static final String TABLE_NAME_PATTERN = "tableNamePattern";
+    public static final String VIEW_NAME_PATTERN = "viewNamePattern";
+    public static final String PARTITION_NAME_PATTERN = "partitionNamePattern";
+
     private final RESTClient client;
     private final ResourcePaths resourcePaths;
     private final CatalogContext context;
@@ -314,13 +318,17 @@ public class RESTCatalog implements Catalog {
 
     @Override
     public PagedList<String> listTablesPaged(
-            String databaseName, @Nullable Integer maxResults, @Nullable 
String pageToken)
+            String databaseName,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String tableNamePattern)
             throws DatabaseNotExistException {
         try {
             ListTablesResponse response =
                     client.get(
                             resourcePaths.tables(databaseName),
-                            buildPagedQueryParams(maxResults, pageToken),
+                            buildPagedQueryParams(
+                                    maxResults, pageToken, TABLE_NAME_PATTERN, 
tableNamePattern),
                             ListTablesResponse.class,
                             restAuthFunction);
             List<String> tables = response.getTables();
@@ -335,13 +343,17 @@ public class RESTCatalog implements Catalog {
 
     @Override
     public PagedList<Table> listTableDetailsPaged(
-            String db, @Nullable Integer maxResults, @Nullable String 
pageToken)
+            String db,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String tableNamePattern)
             throws DatabaseNotExistException {
         try {
             ListTableDetailsResponse response =
                     client.get(
                             resourcePaths.tableDetails(db),
-                            buildPagedQueryParams(maxResults, pageToken),
+                            buildPagedQueryParams(
+                                    maxResults, pageToken, TABLE_NAME_PATTERN, 
tableNamePattern),
                             ListTableDetailsResponse.class,
                             restAuthFunction);
             List<GetTableResponse> tables = response.getTableDetails();
@@ -396,6 +408,11 @@ public class RESTCatalog implements Catalog {
         return true;
     }
 
+    @Override
+    public boolean supportsListByPattern() {
+        return true;
+    }
+
     @Override
     public boolean supportsVersionManagement() {
         return true;
@@ -650,14 +667,21 @@ public class RESTCatalog implements Catalog {
 
     @Override
     public PagedList<Partition> listPartitionsPaged(
-            Identifier identifier, @Nullable Integer maxResults, @Nullable 
String pageToken)
+            Identifier identifier,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String partitionNamePattern)
             throws TableNotExistException {
         try {
             ListPartitionsResponse response =
                     client.get(
                             resourcePaths.partitions(
                                     identifier.getDatabaseName(), 
identifier.getObjectName()),
-                            buildPagedQueryParams(maxResults, pageToken),
+                            buildPagedQueryParams(
+                                    maxResults,
+                                    pageToken,
+                                    PARTITION_NAME_PATTERN,
+                                    partitionNamePattern),
                             ListPartitionsResponse.class,
                             restAuthFunction);
             List<Partition> partitions = response.getPartitions();
@@ -848,13 +872,17 @@ public class RESTCatalog implements Catalog {
 
     @Override
     public PagedList<String> listViewsPaged(
-            String databaseName, @Nullable Integer maxResults, @Nullable 
String pageToken)
+            String databaseName,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String viewNamePattern)
             throws DatabaseNotExistException {
         try {
             ListViewsResponse response =
                     client.get(
                             resourcePaths.views(databaseName),
-                            buildPagedQueryParams(maxResults, pageToken),
+                            buildPagedQueryParams(
+                                    maxResults, pageToken, VIEW_NAME_PATTERN, 
viewNamePattern),
                             ListViewsResponse.class,
                             restAuthFunction);
             List<String> views = response.getViews();
@@ -869,13 +897,17 @@ public class RESTCatalog implements Catalog {
 
     @Override
     public PagedList<View> listViewDetailsPaged(
-            String db, @Nullable Integer maxResults, @Nullable String 
pageToken)
+            String db,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String viewNamePattern)
             throws DatabaseNotExistException {
         try {
             ListViewDetailsResponse response =
                     client.get(
                             resourcePaths.viewDetails(db),
-                            buildPagedQueryParams(maxResults, pageToken),
+                            buildPagedQueryParams(
+                                    maxResults, pageToken, VIEW_NAME_PATTERN, 
viewNamePattern),
                             ListViewDetailsResponse.class,
                             restAuthFunction);
             List<GetViewResponse> views = response.getViewDetails();
@@ -1032,6 +1064,14 @@ public class RESTCatalog implements Catalog {
 
     private Map<String, String> buildPagedQueryParams(
             @Nullable Integer maxResults, @Nullable String pageToken) {
+        return buildPagedQueryParams(maxResults, pageToken, null, null);
+    }
+
+    private Map<String, String> buildPagedQueryParams(
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String namePatternKey,
+            @Nullable String namePatternValue) {
         Map<String, String> queryParams = Maps.newHashMap();
         if (Objects.nonNull(maxResults) && maxResults > 0) {
             queryParams.put(MAX_RESULTS, maxResults.toString());
@@ -1039,6 +1079,9 @@ public class RESTCatalog implements Catalog {
         if (Objects.nonNull(pageToken)) {
             queryParams.put(PAGE_TOKEN, pageToken);
         }
+        if (Objects.nonNull(namePatternValue)) {
+            queryParams.put(namePatternKey, namePatternValue);
+        }
         return queryParams;
     }
 }
diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTUtil.java 
b/paimon-core/src/main/java/org/apache/paimon/rest/RESTUtil.java
index 73b90f4ed8..dd42394d04 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTUtil.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTUtil.java
@@ -97,4 +97,35 @@ public class RESTUtil {
                     e);
         }
     }
+
+    public static void validatePrefixSqlPattern(String pattern) {
+        if (pattern != null && !pattern.isEmpty()) {
+            boolean escaped = false;
+            boolean inWildcardZone = false;
+
+            for (int i = 0; i < pattern.length(); i++) {
+                char c = pattern.charAt(i);
+
+                if (escaped) {
+                    escaped = false;
+                    continue;
+                }
+
+                if (c == '\\') {
+                    escaped = true;
+                    continue;
+                }
+
+                if (c == '%' || c == '_') {
+                    inWildcardZone = true;
+                } else {
+                    if (inWildcardZone) {
+                        throw new IllegalArgumentException(
+                                "Can only support sql like prefix query now. "
+                                        + "Note please escape the underline if 
you want to match it exactly");
+                    }
+                }
+            }
+        }
+    }
 }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java 
b/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java
index 90641edfe8..293692a906 100644
--- a/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java
+++ b/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java
@@ -75,6 +75,7 @@ import static 
org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 /** Base test class of paimon catalog in {@link Catalog}. */
 public abstract class CatalogTestBase {
@@ -275,7 +276,7 @@ public abstract class CatalogTestBase {
         // List tables paged returns an empty list when there are no tables in 
the database
         String databaseName = "tables_paged_db";
         catalog.createDatabase(databaseName, false);
-        PagedList<String> pagedTables = catalog.listTablesPaged(databaseName, 
null, null);
+        PagedList<String> pagedTables = catalog.listTablesPaged(databaseName, 
null, null, null);
         assertThat(pagedTables.getElements()).isEmpty();
         assertNull(pagedTables.getNextPageToken());
 
@@ -288,22 +289,22 @@ public abstract class CatalogTestBase {
         // List tables paged returns a list with the names of all tables in 
the database in all
         // catalogs except RestCatalog
         // even if the maxResults or pageToken is not null
-        pagedTables = catalog.listTablesPaged(databaseName, null, null);
+        pagedTables = catalog.listTablesPaged(databaseName, null, null, null);
         assertPagedTables(pagedTables, tableNames);
 
         int maxResults = 2;
-        pagedTables = catalog.listTablesPaged(databaseName, maxResults, null);
+        pagedTables = catalog.listTablesPaged(databaseName, maxResults, null, 
null);
         assertPagedTables(pagedTables, tableNames);
 
         String pageToken = "table1";
-        pagedTables = catalog.listTablesPaged(databaseName, maxResults, 
pageToken);
+        pagedTables = catalog.listTablesPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedTables(pagedTables, tableNames);
 
         maxResults = 8;
-        pagedTables = catalog.listTablesPaged(databaseName, maxResults, null);
+        pagedTables = catalog.listTablesPaged(databaseName, maxResults, null, 
null);
         assertPagedTables(pagedTables, tableNames);
 
-        pagedTables = catalog.listTablesPaged(databaseName, maxResults, 
pageToken);
+        pagedTables = catalog.listTablesPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedTables(pagedTables, tableNames);
 
         // List tables throws DatabaseNotExistException when the database does 
not exist
@@ -312,7 +313,7 @@ public abstract class CatalogTestBase {
                 .isThrownBy(
                         () ->
                                 catalog.listTablesPaged(
-                                        "non_existing_db", finalMaxResults, 
pageToken));
+                                        "non_existing_db", finalMaxResults, 
pageToken, null));
     }
 
     @Test
@@ -321,7 +322,7 @@ public abstract class CatalogTestBase {
         String databaseName = "table_details_paged_db";
         catalog.createDatabase(databaseName, false);
         PagedList<Table> pagedTableDetails =
-                catalog.listTableDetailsPaged(databaseName, null, null);
+                catalog.listTableDetailsPaged(databaseName, null, null, null);
         assertThat(pagedTableDetails.getElements()).isEmpty();
         assertNull(pagedTableDetails.getNextPageToken());
 
@@ -334,26 +335,28 @@ public abstract class CatalogTestBase {
                     Identifier.create(databaseName, tableName), 
DEFAULT_TABLE_SCHEMA, false);
         }
 
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null);
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null, null);
         assertPagedTableDetails(pagedTableDetails, tableNames.length, 
tableNames);
         assertNull(pagedTableDetails.getNextPageToken());
 
         int maxResults = 2;
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, null);
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, null, null);
         assertPagedTableDetails(pagedTableDetails, tableNames.length, 
tableNames);
         assertNull(pagedTableDetails.getNextPageToken());
 
         String pageToken = "table1";
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, pageToken);
+        pagedTableDetails =
+                catalog.listTableDetailsPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedTableDetails(pagedTableDetails, tableNames.length, 
tableNames);
         assertNull(pagedTableDetails.getNextPageToken());
 
         maxResults = 8;
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, null);
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, null, null);
         assertPagedTableDetails(pagedTableDetails, tableNames.length, 
tableNames);
         assertNull(pagedTableDetails.getNextPageToken());
 
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, pageToken);
+        pagedTableDetails =
+                catalog.listTableDetailsPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedTableDetails(pagedTableDetails, tableNames.length, 
tableNames);
         assertNull(pagedTableDetails.getNextPageToken());
 
@@ -363,7 +366,7 @@ public abstract class CatalogTestBase {
                 .isThrownBy(
                         () ->
                                 catalog.listTableDetailsPaged(
-                                        "non_existing_db", finalMaxResults, 
pageToken));
+                                        "non_existing_db", finalMaxResults, 
pageToken, null));
     }
 
     @Test
@@ -1100,7 +1103,7 @@ public abstract class CatalogTestBase {
         // List views returns an empty list when there are no views in the 
database
         String databaseName = "views_paged_db";
         catalog.createDatabase(databaseName, false);
-        PagedList<String> pagedViews = catalog.listViewsPaged(databaseName, 
null, null);
+        PagedList<String> pagedViews = catalog.listViewsPaged(databaseName, 
null, null, null);
         assertThat(pagedViews.getElements()).isEmpty();
         assertNull(pagedViews.getNextPageToken());
 
@@ -1113,22 +1116,22 @@ public abstract class CatalogTestBase {
             catalog.createView(Identifier.create(databaseName, viewName), 
view, false);
         }
 
-        pagedViews = catalog.listViewsPaged(databaseName, null, null);
+        pagedViews = catalog.listViewsPaged(databaseName, null, null, null);
         assertPagedViews(pagedViews, viewNames);
 
         int maxResults = 2;
-        pagedViews = catalog.listViewsPaged(databaseName, maxResults, null);
+        pagedViews = catalog.listViewsPaged(databaseName, maxResults, null, 
null);
         assertPagedViews(pagedViews, viewNames);
 
         String pageToken = "view1";
-        pagedViews = catalog.listViewsPaged(databaseName, maxResults, 
pageToken);
+        pagedViews = catalog.listViewsPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedViews(pagedViews, viewNames);
 
         maxResults = 8;
-        pagedViews = catalog.listViewsPaged(databaseName, maxResults, null);
+        pagedViews = catalog.listViewsPaged(databaseName, maxResults, null, 
null);
         assertPagedViews(pagedViews, viewNames);
 
-        pagedViews = catalog.listViewsPaged(databaseName, maxResults, 
pageToken);
+        pagedViews = catalog.listViewsPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedViews(pagedViews, viewNames);
 
         // List views throws DatabaseNotExistException when the database does 
not exist
@@ -1137,7 +1140,13 @@ public abstract class CatalogTestBase {
                 .isThrownBy(
                         () ->
                                 catalog.listViewsPaged(
-                                        "non_existing_db", finalMaxResults, 
pageToken));
+                                        "non_existing_db", finalMaxResults, 
pageToken, null));
+
+        assertThatExceptionOfType(UnsupportedOperationException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.listViewsPaged(
+                                        databaseName, finalMaxResults, 
pageToken, "view%"));
     }
 
     @Test
@@ -1150,7 +1159,7 @@ public abstract class CatalogTestBase {
         String databaseName = "view_details_paged_db";
         catalog.createDatabase(databaseName, false);
         PagedList<View> pagedViewDetailsPaged =
-                catalog.listViewDetailsPaged(databaseName, null, null);
+                catalog.listViewDetailsPaged(databaseName, null, null, null);
         assertThat(pagedViewDetailsPaged.getElements()).isEmpty();
         assertNull(pagedViewDetailsPaged.getNextPageToken());
 
@@ -1163,26 +1172,28 @@ public abstract class CatalogTestBase {
             catalog.createView(Identifier.create(databaseName, viewName), 
view, false);
         }
 
-        pagedViewDetailsPaged = catalog.listViewDetailsPaged(databaseName, 
null, null);
+        pagedViewDetailsPaged = catalog.listViewDetailsPaged(databaseName, 
null, null, null);
         assertPagedViewDetails(pagedViewDetailsPaged, view, viewNames.length, 
viewNames);
         assertNull(pagedViewDetailsPaged.getNextPageToken());
 
         int maxResults = 2;
-        pagedViewDetailsPaged = catalog.listViewDetailsPaged(databaseName, 
maxResults, null);
+        pagedViewDetailsPaged = catalog.listViewDetailsPaged(databaseName, 
maxResults, null, null);
         assertPagedViewDetails(pagedViewDetailsPaged, view, viewNames.length, 
viewNames);
         assertNull(pagedViewDetailsPaged.getNextPageToken());
 
         String pageToken = "view1";
-        pagedViewDetailsPaged = catalog.listViewDetailsPaged(databaseName, 
maxResults, pageToken);
+        pagedViewDetailsPaged =
+                catalog.listViewDetailsPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedViewDetails(pagedViewDetailsPaged, view, viewNames.length, 
viewNames);
         assertNull(pagedViewDetailsPaged.getNextPageToken());
 
         maxResults = 8;
-        pagedViewDetailsPaged = catalog.listViewDetailsPaged(databaseName, 
maxResults, null);
+        pagedViewDetailsPaged = catalog.listViewDetailsPaged(databaseName, 
maxResults, null, null);
         assertPagedViewDetails(pagedViewDetailsPaged, view, viewNames.length, 
viewNames);
         assertNull(pagedViewDetailsPaged.getNextPageToken());
 
-        pagedViewDetailsPaged = catalog.listViewDetailsPaged(databaseName, 
maxResults, pageToken);
+        pagedViewDetailsPaged =
+                catalog.listViewDetailsPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedViewDetails(pagedViewDetailsPaged, view, viewNames.length, 
viewNames);
         assertNull(pagedViewDetailsPaged.getNextPageToken());
 
@@ -1192,7 +1203,7 @@ public abstract class CatalogTestBase {
                 .isThrownBy(
                         () ->
                                 catalog.listViewDetailsPaged(
-                                        "non_existing_db", finalMaxResults, 
pageToken));
+                                        "non_existing_db", finalMaxResults, 
pageToken, null));
     }
 
     @Test
@@ -1343,23 +1354,24 @@ public abstract class CatalogTestBase {
         // List partitions paged returns a list with all partitions of the 
table in all catalogs
         // except RestCatalog even
         // if the maxResults or pageToken is not null
-        PagedList<Partition> pagedPartitions = 
catalog.listPartitionsPaged(identifier, null, null);
+        PagedList<Partition> pagedPartitions =
+                catalog.listPartitionsPaged(identifier, null, null, null);
         Map[] specs = partitionSpecs.toArray(new Map[0]);
         assertPagedPartitions(pagedPartitions, specs.length, specs);
 
         int maxResults = 2;
-        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null);
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null, null);
         assertPagedPartitions(pagedPartitions, specs.length, specs);
 
         String pageToken = "dt=20250101";
-        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
pageToken);
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
pageToken, null);
         assertPagedPartitions(pagedPartitions, specs.length, specs);
 
         maxResults = 8;
-        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null);
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null, null);
         assertPagedPartitions(pagedPartitions, specs.length, specs);
 
-        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
pageToken);
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
pageToken, null);
         assertPagedPartitions(pagedPartitions, specs.length, specs);
 
         // List partitions throws TableNotExistException when the table does 
not exist
@@ -1370,7 +1382,28 @@ public abstract class CatalogTestBase {
                                 catalog.listPartitionsPaged(
                                         Identifier.create(databaseName, 
"non_existing_table"),
                                         finalMaxResults,
-                                        pageToken));
+                                        pageToken,
+                                        null));
+
+        assertThrows(
+                UnsupportedOperationException.class,
+                () -> catalog.listPartitionsPaged(identifier, null, null, 
"dt=_0101"));
+
+        assertThrows(
+                UnsupportedOperationException.class,
+                () -> catalog.listPartitionsPaged(identifier, null, null, 
"dt=0101_"));
+
+        assertThrows(
+                UnsupportedOperationException.class,
+                () -> catalog.listPartitionsPaged(identifier, null, null, 
"dt=%0101"));
+
+        assertThrows(
+                UnsupportedOperationException.class,
+                () -> catalog.listPartitionsPaged(identifier, null, null, 
"dt=0101%"));
+
+        assertThrows(
+                UnsupportedOperationException.class,
+                () -> catalog.listPartitionsPaged(identifier, null, null, 
"dt=0101"));
     }
 
     protected boolean supportsAlterDatabase() {
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 69ea8a5185..dab6b0fb34 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
@@ -156,9 +156,10 @@ class MockRESTCatalogTest extends RESTCatalogTest {
                     Identifier.create(databaseName, tableName), 
DEFAULT_TABLE_SCHEMA, false);
         }
         PagedList<String> listTablesPaged =
-                restCatalog.listTablesPaged(databaseName, 1, "dt=20230101");
+                restCatalog.listTablesPaged(databaseName, 1, "dt=20230101", 
null);
         PagedList<String> listTablesPaged2 =
-                restCatalog.listTablesPaged(databaseName, 1, 
listTablesPaged.getNextPageToken());
+                restCatalog.listTablesPaged(
+                        databaseName, 1, listTablesPaged.getNextPageToken(), 
null);
         assertEquals(listTablesPaged.getElements().get(0), "dt=20230102");
         assertEquals(listTablesPaged2.getElements().get(0), "dt=20230103");
     }
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 6173e43361..2c4cc894a7 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
@@ -104,12 +104,18 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 import static org.apache.paimon.CoreOptions.PATH;
 import static org.apache.paimon.CoreOptions.SNAPSHOT_CLEAN_EMPTY_DIRECTORIES;
 import static org.apache.paimon.CoreOptions.TYPE;
 import static org.apache.paimon.TableType.FORMAT_TABLE;
+import static org.apache.paimon.rest.RESTCatalog.MAX_RESULTS;
+import static org.apache.paimon.rest.RESTCatalog.PAGE_TOKEN;
+import static org.apache.paimon.rest.RESTCatalog.PARTITION_NAME_PATTERN;
+import static org.apache.paimon.rest.RESTCatalog.TABLE_NAME_PATTERN;
+import static org.apache.paimon.rest.RESTCatalog.VIEW_NAME_PATTERN;
 import static org.apache.paimon.rest.RESTObjectMapper.OBJECT_MAPPER;
 
 /** Mock REST server for testing. */
@@ -118,8 +124,6 @@ public class RESTCatalogServer {
     private static final Logger LOG = 
LoggerFactory.getLogger(RESTCatalogServer.class);
 
     public static final int DEFAULT_MAX_RESULTS = 100;
-    public static final String MAX_RESULTS = RESTCatalog.MAX_RESULTS;
-    public static final String PAGE_TOKEN = RESTCatalog.PAGE_TOKEN;
     public static final String AUTHORIZATION_HEADER_KEY = "Authorization";
 
     private final String prefix;
@@ -834,7 +838,7 @@ public class RESTCatalogServer {
         if (databaseStore.containsKey(databaseName)) {
             switch (method) {
                 case "GET":
-                    List<String> tables = listTables(databaseName);
+                    List<String> tables = listTables(databaseName, parameters);
                     return generateFinalListTablesResponse(parameters, tables);
                 case "POST":
                     CreateTableRequest requestBody =
@@ -865,17 +869,26 @@ public class RESTCatalogServer {
                 new ErrorResponse(ErrorResponse.RESOURCE_TYPE_DATABASE, null, 
"", 404), 404);
     }
 
-    private List<String> listTables(String databaseName) {
+    private List<String> listTables(String databaseName, Map<String, String> 
parameters) {
+        String tableNamePattern = parameters.get(TABLE_NAME_PATTERN);
         List<String> tables = new ArrayList<>();
         for (Map.Entry<String, TableMetadata> entry : 
tableMetadataStore.entrySet()) {
             Identifier identifier = Identifier.fromString(entry.getKey());
-            if (databaseName.equals(identifier.getDatabaseName())) {
+            if (databaseName.equals(identifier.getDatabaseName())
+                    && (Objects.isNull(tableNamePattern)
+                            || matchNamePattern(identifier.getTableName(), 
tableNamePattern))) {
                 tables.add(identifier.getTableName());
             }
         }
         return tables;
     }
 
+    private boolean matchNamePattern(String name, String pattern) {
+        RESTUtil.validatePrefixSqlPattern(pattern);
+        String regex = sqlPatternToRegex(pattern);
+        return Pattern.compile(regex).matcher(name).matches();
+    }
+
     private MockResponse generateFinalListTablesResponse(
             Map<String, String> parameters, List<String> tables) {
         RESTResponse response;
@@ -910,7 +923,7 @@ public class RESTCatalogServer {
 
     private MockResponse tableDetailsHandle(Map<String, String> parameters, 
String databaseName) {
         RESTResponse response;
-        List<GetTableResponse> tableDetails = listTableDetails(databaseName);
+        List<GetTableResponse> tableDetails = listTableDetails(databaseName, 
parameters);
         if (!tableDetails.isEmpty()) {
             int maxResults;
             try {
@@ -940,11 +953,15 @@ public class RESTCatalogServer {
         return mockResponse(response, 200);
     }
 
-    private List<GetTableResponse> listTableDetails(String databaseName) {
+    private List<GetTableResponse> listTableDetails(
+            String databaseName, Map<String, String> parameters) {
+        String tableNamePattern = parameters.get(TABLE_NAME_PATTERN);
         List<GetTableResponse> tableDetails = new ArrayList<>();
         for (Map.Entry<String, TableMetadata> entry : 
tableMetadataStore.entrySet()) {
             Identifier identifier = Identifier.fromString(entry.getKey());
-            if (databaseName.equals(identifier.getDatabaseName())) {
+            if (databaseName.equals(identifier.getDatabaseName())
+                    && (Objects.isNull(tableNamePattern)
+                            || matchNamePattern(identifier.getTableName(), 
tableNamePattern))) {
                 GetTableResponse getTableResponse =
                         new GetTableResponse(
                                 entry.getValue().uuid(),
@@ -1044,15 +1061,23 @@ public class RESTCatalogServer {
     }
 
     private MockResponse partitionsApiHandle(
-            String method, Map<String, String> parameters, Identifier 
tableIdentifier)
-            throws Exception {
+            String method, Map<String, String> parameters, Identifier 
tableIdentifier) {
+        String partitionNamePattern = parameters.get(PARTITION_NAME_PATTERN);
         switch (method) {
             case "GET":
                 List<Partition> partitions = new ArrayList<>();
                 for (Map.Entry<String, List<Partition>> entry : 
tablePartitionsStore.entrySet()) {
                     String objectName = 
Identifier.fromString(entry.getKey()).getObjectName();
                     if (objectName.equals(tableIdentifier.getObjectName())) {
-                        partitions.addAll(entry.getValue());
+                        partitions.addAll(
+                                entry.getValue().stream()
+                                        .filter(
+                                                partition ->
+                                                        
Objects.isNull(partitionNamePattern)
+                                                                || 
matchNamePattern(
+                                                                        
getPagedKey(partition),
+                                                                        
partitionNamePattern))
+                                        .collect(Collectors.toList()));
                     }
                 }
                 return generateFinalListPartitionsResponse(parameters, 
partitions);
@@ -1187,7 +1212,7 @@ public class RESTCatalogServer {
             throws Exception {
         switch (method) {
             case "GET":
-                List<String> views = listViews(databaseName);
+                List<String> views = listViews(databaseName, parameters);
                 return generateFinalListViewsResponse(parameters, views);
             case "POST":
                 CreateViewRequest requestBody =
@@ -1212,11 +1237,16 @@ public class RESTCatalogServer {
         }
     }
 
-    private List<String> listViews(String databaseName) {
+    private List<String> listViews(String databaseName, Map<String, String> 
parameters) {
+        String viewNamePattern = parameters.get(VIEW_NAME_PATTERN);
         return viewStore.keySet().stream()
                 .map(Identifier::fromString)
                 .filter(identifier -> 
identifier.getDatabaseName().equals(databaseName))
                 .map(Identifier::getTableName)
+                .filter(
+                        viewName ->
+                                (Objects.isNull(viewNamePattern)
+                                        || matchNamePattern(viewName, 
viewNamePattern)))
                 .collect(Collectors.toList());
     }
 
@@ -1256,7 +1286,7 @@ public class RESTCatalogServer {
         RESTResponse response;
         if ("GET".equals(method)) {
 
-            List<GetViewResponse> viewDetails = listViewDetails(databaseName);
+            List<GetViewResponse> viewDetails = listViewDetails(databaseName, 
parameters);
             if (!viewDetails.isEmpty()) {
 
                 int maxResults;
@@ -1292,10 +1322,17 @@ public class RESTCatalogServer {
         }
     }
 
-    private List<GetViewResponse> listViewDetails(String databaseName) {
+    private List<GetViewResponse> listViewDetails(
+            String databaseName, Map<String, String> parameters) {
+        String viewNamePattern = parameters.get(VIEW_NAME_PATTERN);
         return viewStore.keySet().stream()
                 .map(Identifier::fromString)
                 .filter(identifier -> 
identifier.getDatabaseName().equals(databaseName))
+                .filter(
+                        identifier ->
+                                (Objects.isNull(viewNamePattern)
+                                        || matchNamePattern(
+                                                identifier.getTableName(), 
viewNamePattern)))
                 .map(
                         identifier -> {
                             View view = 
viewStore.get(identifier.getFullName());
@@ -1711,15 +1748,44 @@ public class RESTCatalogServer {
     }
 
     private Map<String, String> getParameters(String query) {
-        Map<String, String> parameters =
-                Arrays.stream(query.split("&"))
-                        .map(pair -> pair.split("=", 2))
-                        .collect(
-                                Collectors.toMap(
-                                        pair -> pair[0].trim(), // key
-                                        pair -> 
RESTUtil.decodeString(pair[1].trim()), // value
-                                        (existing, replacement) -> existing // 
handle duplicates
-                                        ));
-        return parameters;
+        return Arrays.stream(query.split("&"))
+                .map(pair -> pair.split("=", 2))
+                .collect(
+                        Collectors.toMap(
+                                pair -> pair[0].trim(), // key
+                                pair -> RESTUtil.decodeString(pair[1].trim()), 
// value
+                                (existing, replacement) -> existing // handle 
duplicates
+                                ));
+    }
+
+    private String sqlPatternToRegex(String pattern) {
+        StringBuilder regex = new StringBuilder();
+        boolean escaped = false;
+
+        for (int i = 0; i < pattern.length(); i++) {
+            char c = pattern.charAt(i);
+
+            if (escaped) {
+                regex.append(c);
+                escaped = false;
+                continue;
+            }
+            if (c == '\\') {
+                escaped = true;
+                continue;
+            }
+            switch (c) {
+                case '%':
+                    regex.append(".*");
+                    break;
+                case '_':
+                    regex.append(".");
+                    break;
+                default:
+                    regex.append(c);
+                    break;
+            }
+        }
+        return "^" + regex + "$";
     }
 }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
index 08ba3d22f0..cb8392dd96 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
@@ -32,6 +32,7 @@ import org.apache.paimon.partition.Partition;
 import org.apache.paimon.partition.PartitionStatistics;
 import org.apache.paimon.reader.RecordReader;
 import org.apache.paimon.rest.auth.DLFToken;
+import org.apache.paimon.rest.exceptions.BadRequestException;
 import org.apache.paimon.rest.responses.ConfigResponse;
 import org.apache.paimon.schema.Schema;
 import org.apache.paimon.schema.SchemaChange;
@@ -58,6 +59,7 @@ import 
org.apache.paimon.shade.guava30.com.google.common.collect.Lists;
 import org.apache.paimon.shade.guava30.com.google.common.collect.Maps;
 
 import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.io.File;
@@ -87,6 +89,7 @@ import static 
org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /** Base test class for {@link RESTCatalog}. */
 public abstract class RESTCatalogTest extends CatalogTestBase {
@@ -202,10 +205,10 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
                                 false));
         assertThrows(
                 Catalog.DatabaseNotExistException.class,
-                () -> catalog.listTablesPaged(database, 100, null));
+                () -> catalog.listTablesPaged(database, 100, null, null));
         assertThrows(
                 Catalog.DatabaseNotExistException.class,
-                () -> catalog.listTableDetailsPaged(database, 100, null));
+                () -> catalog.listTableDetailsPaged(database, 100, null, 
null));
     }
 
     @Test
@@ -242,7 +245,7 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
                 Catalog.TableNoPermissionException.class, () -> 
catalog.listPartitions(identifier));
         assertThrows(
                 Catalog.TableNoPermissionException.class,
-                () -> catalog.listPartitionsPaged(identifier, 100, null));
+                () -> catalog.listPartitionsPaged(identifier, 100, null, 
null));
         assertThrows(
                 Catalog.TableNoPermissionException.class,
                 () -> restCatalog.createBranch(identifier, "test_branch", 
null));
@@ -312,7 +315,7 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         // List tables paged returns an empty list when there are no tables in 
the database
         String databaseName = "tables_paged_db";
         catalog.createDatabase(databaseName, false);
-        PagedList<String> pagedTables = catalog.listTablesPaged(databaseName, 
null, null);
+        PagedList<String> pagedTables = catalog.listTablesPaged(databaseName, 
null, null, null);
         assertThat(pagedTables.getElements()).isEmpty();
         assertNull(pagedTables.getNextPageToken());
 
@@ -324,7 +327,7 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
 
         // when maxResults is null or 0, the page length is set to a server 
configured value
         String[] sortedTableNames = 
Arrays.stream(tableNames).sorted().toArray(String[]::new);
-        pagedTables = catalog.listTablesPaged(databaseName, null, null);
+        pagedTables = catalog.listTablesPaged(databaseName, null, null, null);
         List<String> tables = pagedTables.getElements();
         assertThat(tables).containsExactly(sortedTableNames);
         assertNull(pagedTables.getNextPageToken());
@@ -333,7 +336,7 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         // server configured value
         // when pageToken is null, will list tables from the beginning
         int maxResults = 2;
-        pagedTables = catalog.listTablesPaged(databaseName, maxResults, null);
+        pagedTables = catalog.listTablesPaged(databaseName, maxResults, null, 
null);
         tables = pagedTables.getElements();
         assertEquals(maxResults, tables.size());
         assertThat(tables).containsExactly("abd", "def");
@@ -341,32 +344,35 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
 
         // when pageToken is not null, will list tables from the pageToken 
(exclusive)
         pagedTables =
-                catalog.listTablesPaged(databaseName, maxResults, 
pagedTables.getNextPageToken());
+                catalog.listTablesPaged(
+                        databaseName, maxResults, 
pagedTables.getNextPageToken(), null);
         tables = pagedTables.getElements();
         assertEquals(maxResults, tables.size());
         assertThat(tables).containsExactly("opr", "table1");
         assertEquals("table1", pagedTables.getNextPageToken());
 
         pagedTables =
-                catalog.listTablesPaged(databaseName, maxResults, 
pagedTables.getNextPageToken());
+                catalog.listTablesPaged(
+                        databaseName, maxResults, 
pagedTables.getNextPageToken(), null);
         tables = pagedTables.getElements();
         assertEquals(maxResults, tables.size());
         assertThat(tables).containsExactly("table2", "table3");
         assertEquals("table3", pagedTables.getNextPageToken());
 
         pagedTables =
-                catalog.listTablesPaged(databaseName, maxResults, 
pagedTables.getNextPageToken());
+                catalog.listTablesPaged(
+                        databaseName, maxResults, 
pagedTables.getNextPageToken(), null);
         tables = pagedTables.getElements();
         assertEquals(0, tables.size());
         assertNull(pagedTables.getNextPageToken());
 
         maxResults = 8;
-        pagedTables = catalog.listTablesPaged(databaseName, maxResults, null);
+        pagedTables = catalog.listTablesPaged(databaseName, maxResults, null, 
null);
         tables = pagedTables.getElements();
         assertThat(tables).containsExactly(sortedTableNames);
         assertNull(pagedTables.getNextPageToken());
 
-        pagedTables = catalog.listTablesPaged(databaseName, maxResults, 
"table1");
+        pagedTables = catalog.listTablesPaged(databaseName, maxResults, 
"table1", null);
         tables = pagedTables.getElements();
         assertEquals(2, tables.size());
         assertThat(tables).containsExactly("table2", "table3");
@@ -375,6 +381,46 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         // List tables throws DatabaseNotExistException when the database does 
not exist
         assertThatExceptionOfType(Catalog.DatabaseNotExistException.class)
                 .isThrownBy(() -> catalog.listTables("non_existing_db"));
+
+        pagedTables = catalog.listTablesPaged(databaseName, null, null, 
"table%");
+        tables = pagedTables.getElements();
+        assertEquals(3, tables.size());
+        assertThat(tables).containsExactly("table1", "table2", "table3");
+        assertNull(pagedTables.getNextPageToken());
+
+        pagedTables = catalog.listTablesPaged(databaseName, null, null, 
"table_");
+        tables = pagedTables.getElements();
+        assertEquals(3, tables.size());
+        assertThat(tables).containsExactly("table1", "table2", "table3");
+        assertNull(pagedTables.getNextPageToken());
+
+        pagedTables = catalog.listTablesPaged(databaseName, null, null, 
"table_%");
+        tables = pagedTables.getElements();
+        assertEquals(3, tables.size());
+        assertThat(tables).containsExactly("table1", "table2", "table3");
+        assertNull(pagedTables.getNextPageToken());
+
+        pagedTables = catalog.listTablesPaged(databaseName, null, null, 
"table%_");
+        tables = pagedTables.getElements();
+        assertEquals(3, tables.size());
+        assertThat(tables).containsExactly("table1", "table2", "table3");
+        assertNull(pagedTables.getNextPageToken());
+
+        pagedTables = catalog.listTablesPaged(databaseName, null, null, 
"table\\_");
+        Assertions.assertTrue(pagedTables.getElements().isEmpty());
+        Assertions.assertNull(pagedTables.getNextPageToken());
+
+        pagedTables = catalog.listTablesPaged(databaseName, null, null, 
"tabl_");
+        Assertions.assertTrue(pagedTables.getElements().isEmpty());
+        Assertions.assertNull(pagedTables.getNextPageToken());
+
+        Assertions.assertThrows(
+                BadRequestException.class,
+                () -> catalog.listTablesPaged(databaseName, null, null, 
"ta%le"));
+
+        Assertions.assertThrows(
+                BadRequestException.class,
+                () -> catalog.listTablesPaged(databaseName, null, null, 
"ta_le"));
     }
 
     @Test
@@ -383,7 +429,7 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         String databaseName = "table_details_paged_db";
         catalog.createDatabase(databaseName, false);
         PagedList<Table> pagedTableDetails =
-                catalog.listTableDetailsPaged(databaseName, null, null);
+                catalog.listTableDetailsPaged(databaseName, null, null, null);
         assertThat(pagedTableDetails.getElements()).isEmpty();
         assertNull(pagedTableDetails.getNextPageToken());
 
@@ -394,41 +440,42 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
                     Identifier.create(databaseName, tableName), 
DEFAULT_TABLE_SCHEMA, false);
         }
 
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null);
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null, null);
         assertPagedTableDetails(pagedTableDetails, tableNames.length, 
expectedTableNames);
         assertNull(pagedTableDetails.getNextPageToken());
 
         int maxResults = 2;
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, null);
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, null, null);
         assertPagedTableDetails(pagedTableDetails, maxResults, "abd", "def");
         assertEquals("def", pagedTableDetails.getNextPageToken());
 
         pagedTableDetails =
                 catalog.listTableDetailsPaged(
-                        databaseName, maxResults, 
pagedTableDetails.getNextPageToken());
+                        databaseName, maxResults, 
pagedTableDetails.getNextPageToken(), null);
         assertPagedTableDetails(pagedTableDetails, maxResults, "opr", 
"table1");
         assertEquals("table1", pagedTableDetails.getNextPageToken());
 
         pagedTableDetails =
                 catalog.listTableDetailsPaged(
-                        databaseName, maxResults, 
pagedTableDetails.getNextPageToken());
+                        databaseName, maxResults, 
pagedTableDetails.getNextPageToken(), null);
         assertPagedTableDetails(pagedTableDetails, maxResults, "table2", 
"table3");
         assertEquals("table3", pagedTableDetails.getNextPageToken());
 
         pagedTableDetails =
                 catalog.listTableDetailsPaged(
-                        databaseName, maxResults, 
pagedTableDetails.getNextPageToken());
+                        databaseName, maxResults, 
pagedTableDetails.getNextPageToken(), null);
         assertEquals(0, pagedTableDetails.getElements().size());
         assertNull(pagedTableDetails.getNextPageToken());
 
         maxResults = 8;
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, null);
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, null, null);
         assertPagedTableDetails(
                 pagedTableDetails, Math.min(maxResults, tableNames.length), 
expectedTableNames);
         assertNull(pagedTableDetails.getNextPageToken());
 
         String pageToken = "table1";
-        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, 
maxResults, pageToken);
+        pagedTableDetails =
+                catalog.listTableDetailsPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedTableDetails(pagedTableDetails, 2, "table2", "table3");
         assertNull(pagedTableDetails.getNextPageToken());
 
@@ -438,7 +485,43 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
                 .isThrownBy(
                         () ->
                                 catalog.listTableDetailsPaged(
-                                        "non_existing_db", finalMaxResults, 
pageToken));
+                                        "non_existing_db", finalMaxResults, 
pageToken, null));
+
+        // List tables throws DatabaseNotExistException when the database does 
not exist
+        assertThatExceptionOfType(Catalog.DatabaseNotExistException.class)
+                .isThrownBy(() -> catalog.listTables("non_existing_db"));
+
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null, "table%");
+        assertPagedTableDetails(pagedTableDetails, 3, "table1", "table2", 
"table3");
+        assertNull(pagedTableDetails.getNextPageToken());
+
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null, "table_");
+        assertPagedTableDetails(pagedTableDetails, 3, "table1", "table2", 
"table3");
+        assertNull(pagedTableDetails.getNextPageToken());
+
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null, "table_%");
+        assertPagedTableDetails(pagedTableDetails, 3, "table1", "table2", 
"table3");
+        assertNull(pagedTableDetails.getNextPageToken());
+
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null, "table%_");
+        assertPagedTableDetails(pagedTableDetails, 3, "table1", "table2", 
"table3");
+        assertNull(pagedTableDetails.getNextPageToken());
+
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null, "table\\_");
+        assertTrue(pagedTableDetails.getElements().isEmpty());
+        assertNull(pagedTableDetails.getNextPageToken());
+
+        pagedTableDetails = catalog.listTableDetailsPaged(databaseName, null, 
null, "tabl_");
+        assertTrue(pagedTableDetails.getElements().isEmpty());
+        assertNull(pagedTableDetails.getNextPageToken());
+
+        Assertions.assertThrows(
+                BadRequestException.class,
+                () -> catalog.listTableDetailsPaged(databaseName, null, null, 
"ta%le"));
+
+        Assertions.assertThrows(
+                BadRequestException.class,
+                () -> catalog.listTableDetailsPaged(databaseName, null, null, 
"ta_le"));
     }
 
     @Test
@@ -471,7 +554,7 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         // List views returns an empty list when there are no views in the 
database
         String databaseName = "views_paged_db";
         catalog.createDatabase(databaseName, false);
-        PagedList<String> pagedViews = catalog.listViewsPaged(databaseName, 
null, null);
+        PagedList<String> pagedViews = catalog.listViewsPaged(databaseName, 
null, null, null);
         assertThat(pagedViews.getElements()).isEmpty();
         assertNull(pagedViews.getNextPageToken());
 
@@ -485,33 +568,35 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
             catalog.createView(Identifier.create(databaseName, viewName), 
view, false);
         }
 
-        pagedViews = catalog.listViewsPaged(databaseName, null, null);
+        pagedViews = catalog.listViewsPaged(databaseName, null, null, null);
         assertThat(pagedViews.getElements()).containsExactly(sortedViewNames);
         assertNull(pagedViews.getNextPageToken());
 
         int maxResults = 2;
-        pagedViews = catalog.listViewsPaged(databaseName, maxResults, null);
+        pagedViews = catalog.listViewsPaged(databaseName, maxResults, null, 
null);
         assertPagedViews(pagedViews, "abd", "def");
         assertEquals("def", pagedViews.getNextPageToken());
 
         pagedViews =
-                catalog.listViewsPaged(databaseName, maxResults, 
pagedViews.getNextPageToken());
+                catalog.listViewsPaged(
+                        databaseName, maxResults, 
pagedViews.getNextPageToken(), null);
         assertPagedViews(pagedViews, "opr", "view1");
         assertEquals("view1", pagedViews.getNextPageToken());
 
         pagedViews =
-                catalog.listViewsPaged(databaseName, maxResults, 
pagedViews.getNextPageToken());
+                catalog.listViewsPaged(
+                        databaseName, maxResults, 
pagedViews.getNextPageToken(), null);
         assertPagedViews(pagedViews, "view2", "view3");
         assertEquals("view3", pagedViews.getNextPageToken());
 
         maxResults = 8;
         String[] expectedViewNames = 
Arrays.stream(viewNames).sorted().toArray(String[]::new);
-        pagedViews = catalog.listViewsPaged(databaseName, maxResults, null);
+        pagedViews = catalog.listViewsPaged(databaseName, maxResults, null, 
null);
         assertPagedViews(pagedViews, expectedViewNames);
         assertNull(pagedViews.getNextPageToken());
 
         String pageToken = "view1";
-        pagedViews = catalog.listViewsPaged(databaseName, maxResults, 
pageToken);
+        pagedViews = catalog.listViewsPaged(databaseName, maxResults, 
pageToken, null);
         assertPagedViews(pagedViews, "view2", "view3");
         assertNull(pagedViews.getNextPageToken());
 
@@ -521,7 +606,39 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
                 .isThrownBy(
                         () ->
                                 catalog.listViewsPaged(
-                                        "non_existing_db", finalMaxResults, 
pageToken));
+                                        "non_existing_db", finalMaxResults, 
pageToken, null));
+
+        pagedViews = catalog.listViewsPaged(databaseName, null, null, "view%");
+        assertPagedViews(pagedViews, "view1", "view2", "view3");
+        assertNull(pagedViews.getNextPageToken());
+
+        pagedViews = catalog.listViewsPaged(databaseName, null, null, "view_");
+        assertPagedViews(pagedViews, "view1", "view2", "view3");
+        assertNull(pagedViews.getNextPageToken());
+
+        pagedViews = catalog.listViewsPaged(databaseName, null, null, 
"view_%");
+        assertPagedViews(pagedViews, "view1", "view2", "view3");
+        assertNull(pagedViews.getNextPageToken());
+
+        pagedViews = catalog.listViewsPaged(databaseName, null, null, 
"view%_");
+        assertPagedViews(pagedViews, "view1", "view2", "view3");
+        assertNull(pagedViews.getNextPageToken());
+
+        pagedViews = catalog.listViewsPaged(databaseName, null, null, 
"view\\_");
+        assertTrue(pagedViews.getElements().isEmpty());
+        assertNull(pagedViews.getNextPageToken());
+
+        pagedViews = catalog.listViewsPaged(databaseName, null, null, "vie_");
+        Assertions.assertTrue(pagedViews.getElements().isEmpty());
+        assertNull(pagedViews.getNextPageToken());
+
+        Assertions.assertThrows(
+                BadRequestException.class,
+                () -> catalog.listViewsPaged(databaseName, null, null, 
"vi%ew"));
+
+        Assertions.assertThrows(
+                BadRequestException.class,
+                () -> catalog.listViewsPaged(databaseName, null, null, 
"vi_ew"));
     }
 
     @Test
@@ -529,7 +646,8 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         // List view details returns an empty list when there are no views in 
the database
         String databaseName = "view_details_paged_db";
         catalog.createDatabase(databaseName, false);
-        PagedList<View> pagedViewDetails = 
catalog.listViewDetailsPaged(databaseName, null, null);
+        PagedList<View> pagedViewDetails =
+                catalog.listViewDetailsPaged(databaseName, null, null, null);
         assertThat(pagedViewDetails.getElements()).isEmpty();
         assertNull(pagedViewDetails.getNextPageToken());
 
@@ -539,35 +657,35 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
             catalog.createView(Identifier.create(databaseName, viewName), 
view, false);
         }
 
-        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, null, 
null);
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, null, 
null, null);
         assertPagedViewDetails(pagedViewDetails, view, viewNames.length, 
viewNames);
         assertNull(pagedViewDetails.getNextPageToken());
 
         int maxResults = 2;
-        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, 
maxResults, null);
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, 
maxResults, null, null);
         assertPagedViewDetails(pagedViewDetails, view, maxResults, "abd", 
"def");
         assertEquals("def", pagedViewDetails.getNextPageToken());
 
         pagedViewDetails =
                 catalog.listViewDetailsPaged(
-                        databaseName, maxResults, 
pagedViewDetails.getNextPageToken());
+                        databaseName, maxResults, 
pagedViewDetails.getNextPageToken(), null);
         assertPagedViewDetails(pagedViewDetails, view, maxResults, "opr", 
"view1");
         assertEquals("view1", pagedViewDetails.getNextPageToken());
 
         pagedViewDetails =
                 catalog.listViewDetailsPaged(
-                        databaseName, maxResults, 
pagedViewDetails.getNextPageToken());
+                        databaseName, maxResults, 
pagedViewDetails.getNextPageToken(), null);
         assertPagedViewDetails(pagedViewDetails, view, maxResults, "view2", 
"view3");
         assertEquals("view3", pagedViewDetails.getNextPageToken());
 
         pagedViewDetails =
                 catalog.listViewDetailsPaged(
-                        databaseName, maxResults, 
pagedViewDetails.getNextPageToken());
+                        databaseName, maxResults, 
pagedViewDetails.getNextPageToken(), null);
         assertEquals(0, pagedViewDetails.getElements().size());
         assertNull(pagedViewDetails.getNextPageToken());
 
         maxResults = 8;
-        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, 
maxResults, null);
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, 
maxResults, null, null);
         String[] expectedViewNames = 
Arrays.stream(viewNames).sorted().toArray(String[]::new);
         assertPagedViewDetails(
                 pagedViewDetails,
@@ -577,7 +695,7 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         assertNull(pagedViewDetails.getNextPageToken());
 
         String pageToken = "view1";
-        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, 
maxResults, pageToken);
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, 
maxResults, pageToken, null);
         assertPagedViewDetails(pagedViewDetails, view, 2, "view2", "view3");
         assertNull(pagedViewDetails.getNextPageToken());
 
@@ -587,7 +705,39 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
                 .isThrownBy(
                         () ->
                                 catalog.listViewDetailsPaged(
-                                        "non_existing_db", finalMaxResults, 
pageToken));
+                                        "non_existing_db", finalMaxResults, 
pageToken, null));
+
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, null, 
null, "view%");
+        assertPagedViewDetails(pagedViewDetails, view, 3, "view1", "view2", 
"view3");
+        assertNull(pagedViewDetails.getNextPageToken());
+
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, null, 
null, "view_");
+        assertPagedViewDetails(pagedViewDetails, view, 3, "view1", "view2", 
"view3");
+        assertNull(pagedViewDetails.getNextPageToken());
+
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, null, 
null, "view%_");
+        assertPagedViewDetails(pagedViewDetails, view, 3, "view1", "view2", 
"view3");
+        assertNull(pagedViewDetails.getNextPageToken());
+
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, null, 
null, "view_%");
+        assertPagedViewDetails(pagedViewDetails, view, 3, "view1", "view2", 
"view3");
+        assertNull(pagedViewDetails.getNextPageToken());
+
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, null, 
null, "vie_");
+        Assertions.assertTrue(pagedViewDetails.getElements().isEmpty());
+        assertNull(pagedViewDetails.getNextPageToken());
+
+        pagedViewDetails = catalog.listViewDetailsPaged(databaseName, null, 
null, "view\\_");
+        Assertions.assertTrue(pagedViewDetails.getElements().isEmpty());
+        assertNull(pagedViewDetails.getNextPageToken());
+
+        Assertions.assertThrows(
+                BadRequestException.class,
+                () -> catalog.listViewDetailsPaged(databaseName, null, null, 
"vi%ew"));
+
+        Assertions.assertThrows(
+                BadRequestException.class,
+                () -> catalog.listViewDetailsPaged(databaseName, null, null, 
"vi_ew"));
     }
 
     @Test
@@ -707,7 +857,7 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
 
         assertThrows(
                 Catalog.TableNotExistException.class,
-                () -> catalog.listPartitionsPaged(identifier, 10, 
"dt=20250101"));
+                () -> catalog.listPartitionsPaged(identifier, 10, 
"dt=20250101", null));
 
         catalog.createTable(
                 identifier,
@@ -728,7 +878,8 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
             }
             commit.commit(write.prepareCommit());
         }
-        PagedList<Partition> pagedPartitions = 
catalog.listPartitionsPaged(identifier, null, null);
+        PagedList<Partition> pagedPartitions =
+                catalog.listPartitionsPaged(identifier, null, null, null);
         Map[] sortedSpecs =
                 partitionSpecs.stream()
                         .sorted(Comparator.comparing(i -> i.get("dt")))
@@ -736,47 +887,78 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         assertPagedPartitions(pagedPartitions, partitionSpecs.size(), 
sortedSpecs);
 
         int maxResults = 2;
-        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null);
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null, null);
         assertPagedPartitions(
                 pagedPartitions, maxResults, partitionSpecs.get(2), 
partitionSpecs.get(0));
         assertEquals("dt=20250101", pagedPartitions.getNextPageToken());
 
         pagedPartitions =
                 catalog.listPartitionsPaged(
-                        identifier, maxResults, 
pagedPartitions.getNextPageToken());
+                        identifier, maxResults, 
pagedPartitions.getNextPageToken(), null);
         assertPagedPartitions(
                 pagedPartitions, maxResults, partitionSpecs.get(1), 
partitionSpecs.get(5));
         assertEquals("dt=20250103", pagedPartitions.getNextPageToken());
 
         pagedPartitions =
                 catalog.listPartitionsPaged(
-                        identifier, maxResults, 
pagedPartitions.getNextPageToken());
+                        identifier, maxResults, 
pagedPartitions.getNextPageToken(), null);
         assertPagedPartitions(
                 pagedPartitions, maxResults, partitionSpecs.get(4), 
partitionSpecs.get(3));
         assertEquals("dt=20260101", pagedPartitions.getNextPageToken());
 
         pagedPartitions =
                 catalog.listPartitionsPaged(
-                        identifier, maxResults, 
pagedPartitions.getNextPageToken());
+                        identifier, maxResults, 
pagedPartitions.getNextPageToken(), null);
         assertThat(pagedPartitions.getElements()).isEmpty();
         assertNull(pagedPartitions.getNextPageToken());
 
         maxResults = 8;
-        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null);
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null, null);
 
         assertPagedPartitions(
                 pagedPartitions, Math.min(maxResults, partitionSpecs.size()), 
sortedSpecs);
         assertNull(pagedPartitions.getNextPageToken());
 
-        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
"dt=20250101");
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null, "dt=2025");
+        assertTrue(pagedPartitions.getElements().isEmpty());
+        assertNull(pagedPartitions.getNextPageToken());
+
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null, "dt=2025%");
+        assertPagedPartitions(
+                pagedPartitions,
+                4,
+                partitionSpecs.get(0),
+                partitionSpecs.get(1),
+                partitionSpecs.get(5),
+                partitionSpecs.get(4));
+        assertNull(pagedPartitions.getNextPageToken());
+
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null, "dt=2025010_");
         assertPagedPartitions(
                 pagedPartitions,
                 4,
+                partitionSpecs.get(0),
                 partitionSpecs.get(1),
                 partitionSpecs.get(5),
-                partitionSpecs.get(4),
-                partitionSpecs.get(3));
+                partitionSpecs.get(4));
+        assertNull(pagedPartitions.getNextPageToken());
+
+        pagedPartitions =
+                catalog.listPartitionsPaged(identifier, maxResults, null, 
"dt=2025010\\_");
+        assertTrue(pagedPartitions.getElements().isEmpty());
+        assertNull(pagedPartitions.getNextPageToken());
+
+        pagedPartitions = catalog.listPartitionsPaged(identifier, maxResults, 
null, "dt=202501_");
+        assertTrue(pagedPartitions.getElements().isEmpty());
         assertNull(pagedPartitions.getNextPageToken());
+
+        assertThrows(
+                BadRequestException.class,
+                () -> catalog.listPartitionsPaged(identifier, null, null, 
"dt=%0101"));
+
+        assertThrows(
+                BadRequestException.class,
+                () -> catalog.listPartitionsPaged(identifier, null, null, 
"dt=_0101"));
     }
 
     @Test
diff --git 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java
 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java
index c802e42cdd..5321eb378f 100644
--- 
a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java
+++ 
b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java
@@ -27,6 +27,7 @@ import org.apache.paimon.catalog.CatalogContext;
 import org.apache.paimon.catalog.CatalogLoader;
 import org.apache.paimon.catalog.CatalogLockContext;
 import org.apache.paimon.catalog.CatalogLockFactory;
+import org.apache.paimon.catalog.CatalogUtils;
 import org.apache.paimon.catalog.Identifier;
 import org.apache.paimon.catalog.PropertyChange;
 import org.apache.paimon.catalog.TableMetadata;
@@ -854,16 +855,28 @@ public class HiveCatalog extends AbstractCatalog {
         }
     }
 
+    @Override
+    public PagedList<String> listViewsPaged(
+            String databaseName,
+            @Nullable Integer maxResults,
+            @Nullable String pageToken,
+            @Nullable String viewNamePattern)
+            throws DatabaseNotExistException {
+        CatalogUtils.validateNamePattern(this, viewNamePattern);
+        return new PagedList<>(listViews(databaseName), null);
+    }
+
     @Override
     public PagedList<View> listViewDetailsPaged(
-            String databaseName, Integer maxResults, String pageToken)
+            String databaseName, Integer maxResults, String pageToken, String 
viewNamePattern)
             throws DatabaseNotExistException {
         if (isSystemDatabase(databaseName)) {
             return new PagedList<>(Collections.emptyList(), null);
         }
         getDatabase(databaseName);
 
-        PagedList<String> pagedViewNames = listViewsPaged(databaseName, 
maxResults, pageToken);
+        PagedList<String> pagedViewNames =
+                listViewsPaged(databaseName, maxResults, pageToken, 
viewNamePattern);
         return new PagedList<>(
                 pagedViewNames.getElements().stream()
                         .map(
diff --git a/paimon-open-api/rest-catalog-open-api.yaml 
b/paimon-open-api/rest-catalog-open-api.yaml
index c6793651b4..669eb4875e 100644
--- a/paimon-open-api/rest-catalog-open-api.yaml
+++ b/paimon-open-api/rest-catalog-open-api.yaml
@@ -232,6 +232,11 @@ paths:
           in: query
           schema:
             type: string
+        - name: tableNamePattern
+          description: A sql LIKE pattern (% and _) for table names.
+          in: query
+          schema:
+            type: string
       responses:
         "200":
           description: OK
@@ -305,6 +310,11 @@ paths:
           in: query
           schema:
             type: string
+        - name: tableNamePattern
+          description: A sql LIKE pattern (% and _) for table names.
+          in: query
+          schema:
+            type: string
       responses:
         "200":
           description: OK
@@ -658,6 +668,11 @@ paths:
           in: query
           schema:
             type: string
+        - name: partitionNamePattern
+          description: A sql LIKE pattern (% and _) for partition names.
+          in: query
+          schema:
+            type: string
       responses:
         "200":
           description: OK
@@ -896,6 +911,11 @@ paths:
           in: query
           schema:
             type: string
+        - name: viewNamePattern
+          description: A sql LIKE pattern (% and _) for view names.
+          in: query
+          schema:
+            type: string
       responses:
         "200":
           description: OK
@@ -969,6 +989,11 @@ paths:
           in: query
           schema:
             type: string
+        - name: viewNamePattern
+          description: A sql LIKE pattern (% and _) for view names.
+          in: query
+          schema:
+            type: string
       responses:
         "200":
           description: OK
diff --git 
a/paimon-open-api/src/main/java/org/apache/paimon/open/api/RESTCatalogController.java
 
b/paimon-open-api/src/main/java/org/apache/paimon/open/api/RESTCatalogController.java
index c27bbbba0a..cee2a50411 100644
--- 
a/paimon-open-api/src/main/java/org/apache/paimon/open/api/RESTCatalogController.java
+++ 
b/paimon-open-api/src/main/java/org/apache/paimon/open/api/RESTCatalogController.java
@@ -261,8 +261,9 @@ public class RESTCatalogController {
     public ListTablesResponse listTables(
             @PathVariable String prefix,
             @PathVariable String database,
-            @PathVariable Integer maxResults,
-            @PathVariable String pageToken) {
+            @RequestParam(required = false) Integer maxResults,
+            @RequestParam(required = false) String pageToken,
+            @RequestParam(required = false) String tableNamePattern) {
         // paged list tables in this database with provided maxResults and 
pageToken
         return new ListTablesResponse(ImmutableList.of("user"), null);
     }
@@ -288,8 +289,9 @@ public class RESTCatalogController {
     public ListTableDetailsResponse listTableDetails(
             @PathVariable String prefix,
             @PathVariable String database,
-            @PathVariable Integer maxResults,
-            @PathVariable String pageToken) {
+            @RequestParam(required = false) Integer maxResults,
+            @RequestParam(required = false) String pageToken,
+            @RequestParam(required = false) String tableNamePattern) {
         // paged list table details in this database with provided maxResults 
and pageToken
         GetTableResponse singleTable =
                 new GetTableResponse(
@@ -582,8 +584,9 @@ public class RESTCatalogController {
             @PathVariable String prefix,
             @PathVariable String database,
             @PathVariable String table,
-            @PathVariable Integer maxResults,
-            @PathVariable String pageToken) {
+            @RequestParam(required = false) Integer maxResults,
+            @RequestParam(required = false) String pageToken,
+            @RequestParam(required = false) String partitionNamePattern) {
         // paged list partitions in this table with provided maxResults and 
pageToken
         Map<String, String> spec = new HashMap<>();
         spec.put("f1", "1");
@@ -710,7 +713,7 @@ public class RESTCatalogController {
             @PathVariable String branch) {}
 
     @Operation(
-            summary = "List view details",
+            summary = "List views",
             tags = {"view"})
     @ApiResponses({
         @ApiResponse(
@@ -720,6 +723,34 @@ public class RESTCatalogController {
                 responseCode = "401",
                 description = "Unauthorized",
                 content = {@Content(schema = @Schema(implementation = 
ErrorResponse.class))}),
+        @ApiResponse(
+                responseCode = "500",
+                content = {@Content(schema = @Schema(implementation = 
ErrorResponse.class))})
+    })
+    @GetMapping("/v1/{prefix}/databases/{database}/views")
+    public ListViewsResponse listViews(
+            @PathVariable String prefix,
+            @PathVariable String database,
+            @RequestParam(required = false) Integer maxResults,
+            @RequestParam(required = false) String pageToken,
+            @RequestParam(required = false) String viewNamePattern) {
+        // paged list tables in this database with provided maxResults and 
pageToken
+        return new ListViewsResponse(ImmutableList.of("user"), null);
+    }
+
+    @Operation(
+            summary = "List view details",
+            tags = {"view"})
+    @ApiResponses({
+        @ApiResponse(
+                responseCode = "200",
+                content = {
+                    @Content(schema = @Schema(implementation = 
ListViewDetailsResponse.class))
+                }),
+        @ApiResponse(
+                responseCode = "401",
+                description = "Unauthorized",
+                content = {@Content(schema = @Schema(implementation = 
ErrorResponse.class))}),
         @ApiResponse(
                 responseCode = "404",
                 description = "Resource not found",
@@ -732,8 +763,9 @@ public class RESTCatalogController {
     public ListViewDetailsResponse listViewDetails(
             @PathVariable String prefix,
             @PathVariable String database,
-            @PathVariable Integer maxResults,
-            @PathVariable String pageToken) {
+            @RequestParam(required = false) Integer maxResults,
+            @RequestParam(required = false) String pageToken,
+            @RequestParam(required = false) String viewNamePattern) {
         // paged list view details in this database with provided maxResults 
and pageToken
         List<DataField> fields =
                 Arrays.asList(


Reply via email to