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 66396f70cb [core] RESTCatalog: fix NotImplementedException handle when 
create and alter table (#5274)
66396f70cb is described below

commit 66396f70cb41809bf160f25dbcb2dad3e573e858
Author: jerry <[email protected]>
AuthorDate: Tue Mar 18 20:28:08 2025 +0800

    [core] RESTCatalog: fix NotImplementedException handle when create and 
alter table (#5274)
---
 .../java/org/apache/paimon/rest/RESTCatalog.java   |  8 ++
 .../apache/paimon/rest/auth/DLFAuthProvider.java   |  8 +-
 .../rest/responses/BaseResourceAuditResponse.java  | 88 ++++++++++++++++++++++
 .../paimon/rest/responses/GetDatabaseResponse.java | 11 ++-
 .../paimon/rest/responses/GetTableResponse.java    | 10 ++-
 .../paimon/rest/responses/GetViewResponse.java     | 10 ++-
 .../org/apache/paimon/catalog/CatalogTestBase.java | 36 +++++++++
 .../org/apache/paimon/rest/MockRESTMessage.java    | 32 +++++++-
 .../org/apache/paimon/rest/RESTCatalogServer.java  | 66 +++++++++++-----
 .../apache/paimon/rest/RESTCatalogTestBase.java    | 14 ++++
 .../apache/paimon/flink/CatalogTableITCase.java    |  4 +-
 paimon-open-api/rest-catalog-open-api.yaml         | 30 ++++++++
 .../paimon/open/api/RESTCatalogController.java     | 45 +++++++++--
 .../org/apache/paimon/spark/SparkReadITCase.java   |  4 +-
 14 files changed, 326 insertions(+), 40 deletions(-)

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 32cfd52069..e37e85688c 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
@@ -75,6 +75,7 @@ import org.apache.paimon.schema.SchemaChange;
 import org.apache.paimon.schema.TableSchema;
 import org.apache.paimon.table.Table;
 import org.apache.paimon.table.TableSnapshot;
+import org.apache.paimon.table.system.SystemTableLoader;
 import org.apache.paimon.utils.Pair;
 import org.apache.paimon.view.View;
 import org.apache.paimon.view.ViewImpl;
@@ -286,6 +287,9 @@ public class RESTCatalog implements Catalog {
     @Override
     public List<String> listTables(String databaseName) throws 
DatabaseNotExistException {
         try {
+            if (isSystemDatabase(databaseName)) {
+                return SystemTableLoader.loadGlobalTableNames();
+            }
             return listDataFromPageApi(
                     queryParams ->
                             client.get(
@@ -465,6 +469,8 @@ public class RESTCatalog implements Catalog {
             if (!ignoreIfExists) {
                 throw new TableAlreadyExistException(identifier);
             }
+        } catch (NotImplementedException e) {
+            throw new RuntimeException(new 
UnsupportedOperationException(e.getMessage()));
         } catch (NoSuchResourceException e) {
             throw new DatabaseNotExistException(identifier.getDatabaseName());
         } catch (BadRequestException e) {
@@ -522,6 +528,8 @@ public class RESTCatalog implements Catalog {
             throw new TableNoPermissionException(identifier, e);
         } catch (ServiceFailureException e) {
             throw new IllegalStateException(e.getMessage());
+        } catch (NotImplementedException e) {
+            throw new UnsupportedOperationException(e.getMessage());
         } catch (BadRequestException e) {
             throw new RuntimeException(new 
IllegalArgumentException(e.getMessage()));
         }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/rest/auth/DLFAuthProvider.java 
b/paimon-core/src/main/java/org/apache/paimon/rest/auth/DLFAuthProvider.java
index 0f5371228d..f82720b33f 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/auth/DLFAuthProvider.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/auth/DLFAuthProvider.java
@@ -89,9 +89,11 @@ public class DLFAuthProvider implements AuthProvider {
     public Map<String, String> header(
             Map<String, String> baseHeader, RESTAuthParameter 
restAuthParameter) {
         try {
-            ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
-            String date = now.format(AUTH_DATE_FORMATTER);
-            String dateTime = now.format(AUTH_DATE_TIME_FORMATTER);
+            String dateTime =
+                    baseHeader.getOrDefault(
+                            DLF_DATE_HEADER_KEY.toLowerCase(),
+                            
ZonedDateTime.now(ZoneOffset.UTC).format(AUTH_DATE_TIME_FORMATTER));
+            String date = dateTime.substring(0, 8);
             Map<String, String> signHeaders =
                     generateSignHeaders(
                             restAuthParameter.data(), dateTime, 
token.getSecurityToken());
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/rest/responses/BaseResourceAuditResponse.java
 
b/paimon-core/src/main/java/org/apache/paimon/rest/responses/BaseResourceAuditResponse.java
new file mode 100644
index 0000000000..d867efd180
--- /dev/null
+++ 
b/paimon-core/src/main/java/org/apache/paimon/rest/responses/BaseResourceAuditResponse.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.rest.responses;
+
+import org.apache.paimon.rest.RESTResponse;
+
+import 
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonCreator;
+import 
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonGetter;
+import 
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
+
+/** Base class for database, table, view, audit response. */
+public abstract class BaseResourceAuditResponse implements RESTResponse {
+    protected static final String FIELD_OWNER = "owner";
+    protected static final String FIELD_CREATED_AT = "createdAt";
+    protected static final String FIELD_CREATED_BY = "createdBy";
+    protected static final String FIELD_UPDATED_AT = "updatedAt";
+    protected static final String FIELD_UPDATED_BY = "updatedBy";
+
+    @JsonProperty(FIELD_OWNER)
+    private final String owner;
+
+    @JsonProperty(FIELD_CREATED_AT)
+    private final long createdAt;
+
+    @JsonProperty(FIELD_CREATED_BY)
+    private final String createdBy;
+
+    @JsonProperty(FIELD_UPDATED_AT)
+    private final long updatedAt;
+
+    @JsonProperty(FIELD_UPDATED_BY)
+    private final String updatedBy;
+
+    @JsonCreator
+    public BaseResourceAuditResponse(
+            @JsonProperty(FIELD_OWNER) String owner,
+            @JsonProperty(FIELD_CREATED_AT) long createdAt,
+            @JsonProperty(FIELD_CREATED_BY) String createdBy,
+            @JsonProperty(FIELD_UPDATED_AT) long updatedAt,
+            @JsonProperty(FIELD_UPDATED_BY) String updatedBy) {
+        this.owner = owner;
+        this.createdAt = createdAt;
+        this.createdBy = createdBy;
+        this.updatedAt = updatedAt;
+        this.updatedBy = updatedBy;
+    }
+
+    @JsonGetter(FIELD_OWNER)
+    public String getOwner() {
+        return owner;
+    }
+
+    @JsonGetter(FIELD_CREATED_AT)
+    public long getCreatedAt() {
+        return createdAt;
+    }
+
+    @JsonGetter(FIELD_CREATED_BY)
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    @JsonGetter(FIELD_UPDATED_AT)
+    public long getUpdatedAt() {
+        return updatedAt;
+    }
+
+    @JsonGetter(FIELD_UPDATED_BY)
+    public String getUpdatedBy() {
+        return updatedBy;
+    }
+}
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetDatabaseResponse.java
 
b/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetDatabaseResponse.java
index 81c706cccb..b226f41888 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetDatabaseResponse.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetDatabaseResponse.java
@@ -33,7 +33,8 @@ import static org.apache.paimon.catalog.Catalog.COMMENT_PROP;
 
 /** Response for getting database. */
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class GetDatabaseResponse implements RESTResponse, Database {
+public class GetDatabaseResponse extends BaseResourceAuditResponse
+        implements RESTResponse, Database {
 
     private static final String FIELD_ID = "id";
     private static final String FIELD_NAME = "name";
@@ -52,7 +53,13 @@ public class GetDatabaseResponse implements RESTResponse, 
Database {
     public GetDatabaseResponse(
             @JsonProperty(FIELD_ID) String id,
             @JsonProperty(FIELD_NAME) String name,
-            @JsonProperty(FIELD_OPTIONS) Map<String, String> options) {
+            @JsonProperty(FIELD_OPTIONS) Map<String, String> options,
+            @JsonProperty(FIELD_OWNER) String owner,
+            @JsonProperty(FIELD_CREATED_AT) long createdAt,
+            @JsonProperty(FIELD_CREATED_BY) String createdBy,
+            @JsonProperty(FIELD_UPDATED_AT) long updatedAt,
+            @JsonProperty(FIELD_UPDATED_BY) String updatedBy) {
+        super(owner, createdAt, createdBy, updatedAt, updatedBy);
         this.id = id;
         this.name = name;
         this.options = options;
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetTableResponse.java
 
b/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetTableResponse.java
index 82b55fae7f..c556b591cc 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetTableResponse.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetTableResponse.java
@@ -28,7 +28,7 @@ import 
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonPro
 
 /** Response for getting table. */
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class GetTableResponse implements RESTResponse {
+public class GetTableResponse extends BaseResourceAuditResponse implements 
RESTResponse {
 
     private static final String FIELD_ID = "id";
     private static final String FIELD_NAME = "name";
@@ -57,7 +57,13 @@ public class GetTableResponse implements RESTResponse {
             @JsonProperty(FIELD_NAME) String name,
             @JsonProperty(FIELD_IS_EXTERNAL) boolean isExternal,
             @JsonProperty(FIELD_SCHEMA_ID) long schemaId,
-            @JsonProperty(FIELD_SCHEMA) Schema schema) {
+            @JsonProperty(FIELD_SCHEMA) Schema schema,
+            @JsonProperty(FIELD_OWNER) String owner,
+            @JsonProperty(FIELD_CREATED_AT) long createdAt,
+            @JsonProperty(FIELD_CREATED_BY) String createdBy,
+            @JsonProperty(FIELD_UPDATED_AT) long updatedAt,
+            @JsonProperty(FIELD_UPDATED_BY) String updatedBy) {
+        super(owner, createdAt, createdBy, updatedAt, updatedBy);
         this.id = id;
         this.name = name;
         this.isExternal = isExternal;
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetViewResponse.java
 
b/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetViewResponse.java
index 7fe1237691..ab1e0341b1 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetViewResponse.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/rest/responses/GetViewResponse.java
@@ -28,7 +28,7 @@ import 
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonPro
 
 /** Response for getting view. */
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class GetViewResponse implements RESTResponse {
+public class GetViewResponse extends BaseResourceAuditResponse implements 
RESTResponse {
 
     private static final String FIELD_ID = "id";
     private static final String FIELD_NAME = "name";
@@ -47,7 +47,13 @@ public class GetViewResponse implements RESTResponse {
     public GetViewResponse(
             @JsonProperty(FIELD_ID) String id,
             @JsonProperty(FIELD_NAME) String name,
-            @JsonProperty(FIELD_SCHEMA) ViewSchema schema) {
+            @JsonProperty(FIELD_SCHEMA) ViewSchema schema,
+            @JsonProperty(FIELD_OWNER) String owner,
+            @JsonProperty(FIELD_CREATED_AT) long createdAt,
+            @JsonProperty(FIELD_CREATED_BY) String createdBy,
+            @JsonProperty(FIELD_UPDATED_AT) long updatedAt,
+            @JsonProperty(FIELD_UPDATED_BY) String updatedBy) {
+        super(owner, createdAt, createdBy, updatedAt, updatedBy);
         this.id = id;
         this.name = name;
         this.schema = schema;
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 77f62ed8b6..49d6f623c1 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
@@ -36,12 +36,15 @@ import org.apache.paimon.table.Table;
 import org.apache.paimon.table.sink.BatchTableCommit;
 import org.apache.paimon.table.sink.BatchTableWrite;
 import org.apache.paimon.table.sink.BatchWriteBuilder;
+import org.apache.paimon.table.system.AllTableOptionsTable;
+import org.apache.paimon.table.system.CatalogOptionsTable;
 import org.apache.paimon.types.DataField;
 import org.apache.paimon.types.DataTypes;
 import org.apache.paimon.types.RowType;
 import org.apache.paimon.view.View;
 import org.apache.paimon.view.ViewImpl;
 
+import org.apache.paimon.shade.guava30.com.google.common.collect.ImmutableMap;
 import org.apache.paimon.shade.guava30.com.google.common.collect.Lists;
 import org.apache.paimon.shade.guava30.com.google.common.collect.Maps;
 
@@ -483,6 +486,20 @@ public abstract class CatalogTestBase {
                 .hasRootCauseInstanceOf(IllegalArgumentException.class)
                 .hasRootCauseMessage(
                         "Unrecognized option for boolean: max. Expected either 
true or false(case insensitive)");
+
+        // conflict options
+        Schema conflictOptionsSchema =
+                Schema.newBuilder()
+                        .column("a", DataTypes.INT())
+                        .options(ImmutableMap.of("changelog-producer", 
"input"))
+                        .build();
+        assertThatThrownBy(
+                        () ->
+                                catalog.createTable(
+                                        Identifier.create("test_db", 
"conflict_options_table"),
+                                        conflictOptionsSchema,
+                                        false))
+                .isInstanceOf(RuntimeException.class);
     }
 
     @Test
@@ -538,6 +555,12 @@ public abstract class CatalogTestBase {
         assertThatExceptionOfType(Catalog.TableNotExistException.class)
                 .isThrownBy(
                         () -> 
catalog.getTable(Identifier.create(SYSTEM_DATABASE_NAME, "1111")));
+
+        List<String> sysTables = catalog.listTables(SYSTEM_DATABASE_NAME);
+        assertThat(sysTables)
+                .containsExactlyInAnyOrder(
+                        AllTableOptionsTable.ALL_TABLE_OPTIONS,
+                        CatalogOptionsTable.CATALOG_OPTIONS);
     }
 
     @Test
@@ -683,6 +706,19 @@ public abstract class CatalogTestBase {
                         anyCauseMatches(
                                 Catalog.ColumnAlreadyExistException.class,
                                 "Column col1 already exists in the 
test_db.test_table table."));
+
+        // conflict options
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        Lists.newArrayList(
+                                                SchemaChange.setOption(
+                                                        "changelog-producer", 
"input")),
+                                        false))
+                .isInstanceOf(RuntimeException.class)
+                .hasMessageContaining(
+                        "Can not set changelog-producer on table without 
primary keys");
     }
 
     @Test
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
index 1470b52001..3c099f7372 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
@@ -82,7 +82,15 @@ public class MockRESTMessage {
         Map<String, String> options = new HashMap<>();
         options.put("a", "b");
         options.put(COMMENT_PROP, "comment");
-        return new GetDatabaseResponse(UUID.randomUUID().toString(), name, 
options);
+        return new GetDatabaseResponse(
+                UUID.randomUUID().toString(),
+                name,
+                options,
+                "owner",
+                System.currentTimeMillis(),
+                "created",
+                System.currentTimeMillis(),
+                "updated");
     }
 
     public static ListDatabasesResponse listDatabasesResponse(String name) {
@@ -219,7 +227,17 @@ public class MockRESTMessage {
         Map<String, String> options = new HashMap<>();
         options.put("option-1", "value-1");
         options.put("option-2", "value-2");
-        return new GetTableResponse(UUID.randomUUID().toString(), "", false, 
1, schema(options));
+        return new GetTableResponse(
+                UUID.randomUUID().toString(),
+                "",
+                false,
+                1,
+                schema(options),
+                "owner",
+                System.currentTimeMillis(),
+                "created",
+                System.currentTimeMillis(),
+                "updated");
     }
 
     public static CreateViewRequest createViewRequest(String name) {
@@ -228,7 +246,15 @@ public class MockRESTMessage {
     }
 
     public static GetViewResponse getViewResponse() {
-        return new GetViewResponse(UUID.randomUUID().toString(), "", 
viewSchema());
+        return new GetViewResponse(
+                UUID.randomUUID().toString(),
+                "",
+                viewSchema(),
+                "owner",
+                System.currentTimeMillis(),
+                "created",
+                System.currentTimeMillis(),
+                "updated");
     }
 
     public static ListViewsResponse listViewsResponse() {
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 9654f2647c..e151f976c5 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
@@ -273,10 +273,6 @@ public class RESTCatalogServer {
                                 resources.length == 2 && 
resources[1].startsWith("tables");
                         boolean isTableDetails =
                                 resources.length == 2 && 
resources[1].startsWith("table-details");
-                        boolean isViewRename =
-                                resources.length == 3
-                                        && "views".equals(resources[1])
-                                        && "rename".equals(resources[2]);
                         boolean isView =
                                 resources.length == 3
                                         && "views".equals(resources[1])
@@ -485,14 +481,18 @@ public class RESTCatalogServer {
                                 new ErrorResponse(
                                         null, null, 
e.getCause().getCause().getMessage(), 400);
                         return mockResponse(response, 400);
-                    } else if (e instanceof UnsupportedOperationException) {
+                    } else if (e instanceof UnsupportedOperationException
+                            || e.getCause() instanceof 
UnsupportedOperationException) {
                         response = new ErrorResponse(null, null, 
e.getMessage(), 501);
                         return mockResponse(response, 501);
-                    } else if (e instanceof IllegalStateException) {
+                    } else if (e instanceof IllegalStateException
+                            || e.getCause() instanceof IllegalStateException) {
                         response = new ErrorResponse(null, null, 
e.getMessage(), 500);
                         return mockResponse(response, 500);
                     }
-                    return new MockResponse().setResponseCode(500);
+                    return new MockResponse()
+                            .setResponseCode(500)
+                            .setBody(e.getCause().getMessage());
                 }
             }
         };
@@ -671,7 +671,12 @@ public class RESTCatalogServer {
                             new GetDatabaseResponse(
                                     UUID.randomUUID().toString(),
                                     database.name(),
-                                    database.options());
+                                    database.options(),
+                                    "owner",
+                                    1L,
+                                    "created",
+                                    1L,
+                                    "updated");
                     return mockResponse(response, 200);
                 case "DELETE":
                     catalog.dropDatabase(databaseName, false, true);
@@ -740,7 +745,7 @@ public class RESTCatalogServer {
                         tableMetadata =
                                 createTableMetadata(
                                         requestBody.getIdentifier(),
-                                        1L,
+                                        0L,
                                         requestBody.getSchema(),
                                         UUID.randomUUID().toString(),
                                         false);
@@ -842,7 +847,12 @@ public class RESTCatalogServer {
                                 identifier.getTableName(),
                                 entry.getValue().isExternal(),
                                 entry.getValue().schema().id(),
-                                entry.getValue().schema().toSchema());
+                                entry.getValue().schema().toSchema(),
+                                "owner",
+                                1L,
+                                "created",
+                                1L,
+                                "updated");
                 tableDetails.add(getTableResponse);
             }
         }
@@ -862,7 +872,6 @@ public class RESTCatalogServer {
         switch (method) {
             case "GET":
                 TableMetadata tableMetadata;
-                identifier.isSystemTable();
                 if (identifier.isSystemTable()) {
                     TableSchema schema = catalog.loadTableSchema(identifier);
                     tableMetadata =
@@ -877,7 +886,12 @@ public class RESTCatalogServer {
                                 identifier.getTableName(),
                                 tableMetadata.isExternal(),
                                 tableMetadata.schema().id(),
-                                tableMetadata.schema().toSchema());
+                                tableMetadata.schema().toSchema(),
+                                "owner",
+                                1L,
+                                "created",
+                                1L,
+                                "updated");
                 return mockResponse(response, 200);
             case "POST":
                 AlterTableRequest requestBody =
@@ -891,6 +905,8 @@ public class RESTCatalogServer {
                     System.out.println(e.getMessage());
                 }
                 tableMetadataStore.remove(identifier.getFullName());
+                tableSnapshotStore.remove(identifier.getFullName());
+                tablePartitionsStore.remove(identifier.getFullName());
                 return new MockResponse().setResponseCode(200);
             default:
                 return new MockResponse().setResponseCode(404);
@@ -1171,7 +1187,15 @@ public class RESTCatalogServer {
                                             view.dialects(),
                                             view.comment().orElse(null),
                                             view.options());
-                            return new GetViewResponse("id", 
identifier.getTableName(), schema);
+                            return new GetViewResponse(
+                                    "id",
+                                    identifier.getTableName(),
+                                    schema,
+                                    "owner",
+                                    1L,
+                                    "created",
+                                    1L,
+                                    "updated");
                         })
                 .collect(Collectors.toList());
     }
@@ -1190,7 +1214,16 @@ public class RESTCatalogServer {
                                         view.dialects(),
                                         view.comment().orElse(null),
                                         view.options());
-                        response = new GetViewResponse("id", 
identifier.getTableName(), schema);
+                        response =
+                                new GetViewResponse(
+                                        "id",
+                                        identifier.getTableName(),
+                                        schema,
+                                        "owner",
+                                        1L,
+                                        "created",
+                                        1L,
+                                        "updated");
                         return mockResponse(response, 200);
                     }
                     throw new Catalog.ViewNotExistException(identifier);
@@ -1416,11 +1449,6 @@ public class RESTCatalogServer {
         return createTableMetadata(identifier, 1L, schema, 
UUID.randomUUID().toString(), true);
     }
 
-    private Partition spec2Partition(Map<String, String> spec) {
-        // todo: need update
-        return new Partition(spec, 123, 456, 789, 123, false);
-    }
-
     private FileStoreTable getFileTable(Identifier identifier)
             throws Catalog.TableNotExistException {
         if (tableMetadataStore.containsKey(identifier.getFullName())) {
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTestBase.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTestBase.java
index 1a6b80ffe3..a2be1a631a 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTestBase.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTestBase.java
@@ -850,6 +850,20 @@ public abstract class RESTCatalogTestBase extends 
CatalogTestBase {
         assertThat(snapshot.get().fileSizeInBytes()).isEqualTo(2);
         assertThat(snapshot.get().fileCount()).isEqualTo(3);
         assertThat(snapshot.get().lastFileCreationTime()).isEqualTo(4);
+
+        // drop table then create table
+        catalog.dropTable(hasSnapshotTableIdentifier, true);
+        createTable(hasSnapshotTableIdentifier, Maps.newHashMap(), 
Lists.newArrayList("col1"));
+        snapshot = catalog.loadSnapshot(hasSnapshotTableIdentifier);
+        assertThat(snapshot).isEmpty();
+        updateSnapshotOnRestServer(
+                hasSnapshotTableIdentifier, createSnapshotWithMillis(id, 
millis), 5, 6, 7, 8);
+        snapshot = catalog.loadSnapshot(hasSnapshotTableIdentifier);
+        assertThat(snapshot.get().recordCount()).isEqualTo(5);
+
+        // test no snapshot
+        catalog.loadSnapshot(hasSnapshotTableIdentifier);
+        createTable(hasSnapshotTableIdentifier, Maps.newHashMap(), 
Lists.newArrayList("col1"));
         Identifier noSnapshotTableIdentifier = 
Identifier.create("test_db_a_1", "unknown");
         createTable(noSnapshotTableIdentifier, Maps.newHashMap(), 
Lists.newArrayList("col1"));
         snapshot = catalog.loadSnapshot(noSnapshotTableIdentifier);
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/CatalogTableITCase.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/CatalogTableITCase.java
index 8cd6afbb4d..3be5071e7a 100644
--- 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/CatalogTableITCase.java
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/CatalogTableITCase.java
@@ -552,14 +552,14 @@ public class CatalogTableITCase extends CatalogITCaseBase 
{
         assertThatThrownBy(
                         () -> sql("CREATE TABLE T (a INT) WITH 
('changelog-producer' = 'input')"))
                 .rootCause()
-                .isInstanceOf(UnsupportedOperationException.class)
+                .isInstanceOf(RuntimeException.class)
                 .hasMessageContaining(
                         "Can not set changelog-producer on table without 
primary keys");
 
         sql("CREATE TABLE T (a INT)");
         assertThatThrownBy(() -> sql("ALTER TABLE T SET 
('changelog-producer'='input')"))
                 .rootCause()
-                .isInstanceOf(UnsupportedOperationException.class)
+                .isInstanceOf(RuntimeException.class)
                 .hasMessageContaining(
                         "Can not set changelog-producer on table without 
primary keys");
     }
diff --git a/paimon-open-api/rest-catalog-open-api.yaml 
b/paimon-open-api/rest-catalog-open-api.yaml
index fe10e71c3e..4183e28741 100644
--- a/paimon-open-api/rest-catalog-open-api.yaml
+++ b/paimon-open-api/rest-catalog-open-api.yaml
@@ -1219,6 +1219,16 @@ components:
           $ref: '#/components/schemas/Schema'
         uuid:
           type: string
+        owner:
+          type: string
+        createdAt:
+          format: int64
+        createdBy:
+          type: string
+        updatedAt:
+          format: int64
+        updatedBy:
+          type: string
     SchemaChange:
       anyOf:
         - $ref: '#/components/schemas/SetOption'
@@ -1509,6 +1519,16 @@ components:
           type: object
           additionalProperties:
             type: string
+        owner:
+          type: string
+        createdAt:
+          format: int64
+        createdBy:
+          type: string
+        updatedAt:
+          format: int64
+        updatedBy:
+          type: string
     ListTablesResponse:
       type: object
       properties:
@@ -1576,6 +1596,16 @@ components:
           type: string
         schema:
           $ref: '#/components/schemas/ViewSchema'
+        owner:
+          type: string
+        createdAt:
+          format: int64
+        createdBy:
+          type: string
+        updatedAt:
+          format: int64
+        updatedBy:
+          type: string
     ListViewsResponse:
       type: object
       properties:
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 0ca57e0bde..faaa260bdd 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
@@ -164,7 +164,15 @@ public class RESTCatalogController {
     public GetDatabaseResponse getDatabases(
             @PathVariable String prefix, @PathVariable String database) {
         Map<String, String> options = new HashMap<>();
-        return new GetDatabaseResponse(UUID.randomUUID().toString(), "name", 
options);
+        return new GetDatabaseResponse(
+                UUID.randomUUID().toString(),
+                "name",
+                options,
+                "owner",
+                System.currentTimeMillis(),
+                "created",
+                System.currentTimeMillis(),
+                "updated");
     }
 
     @Operation(
@@ -267,7 +275,12 @@ public class RESTCatalogController {
                                 ImmutableList.of(),
                                 ImmutableList.of(),
                                 new HashMap<>(),
-                                "test-comment"));
+                                "test-comment"),
+                        "owner",
+                        System.currentTimeMillis(),
+                        "created",
+                        System.currentTimeMillis(),
+                        "updated");
         return new ListTableDetailsResponse(ImmutableList.of(singleTable), 
null);
     }
 
@@ -305,7 +318,12 @@ public class RESTCatalogController {
                         ImmutableList.of(),
                         ImmutableList.of(),
                         new HashMap<>(),
-                        "comment"));
+                        "comment"),
+                "owner",
+                System.currentTimeMillis(),
+                "created",
+                System.currentTimeMillis(),
+                "updated");
     }
 
     @Operation(
@@ -640,7 +658,16 @@ public class RESTCatalogController {
                         Collections.emptyMap(),
                         "comment",
                         Collections.singletonMap("pt", "1"));
-        GetViewResponse singleView = new GetViewResponse("id", "name", schema);
+        GetViewResponse singleView =
+                new GetViewResponse(
+                        "id",
+                        "name",
+                        schema,
+                        "owner",
+                        System.currentTimeMillis(),
+                        "created",
+                        System.currentTimeMillis(),
+                        "updated");
         return new ListViewDetailsResponse(ImmutableList.of(singleView), null);
     }
 
@@ -692,7 +719,15 @@ public class RESTCatalogController {
                         Collections.emptyMap(),
                         "comment",
                         Collections.singletonMap("pt", "1"));
-        return new GetViewResponse("id", "name", schema);
+        return new GetViewResponse(
+                "id",
+                "name",
+                schema,
+                "owner",
+                System.currentTimeMillis(),
+                "created",
+                System.currentTimeMillis(),
+                "updated");
     }
 
     @Operation(
diff --git 
a/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkReadITCase.java
 
b/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkReadITCase.java
index b00267410a..a96954dcdf 100644
--- 
a/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkReadITCase.java
+++ 
b/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkReadITCase.java
@@ -312,7 +312,7 @@ public class SparkReadITCase extends SparkReadTestBase {
                                 spark.sql(
                                         "CREATE TABLE T (a INT) TBLPROPERTIES 
('changelog-producer' = 'input')"))
                 .rootCause()
-                .isInstanceOf(UnsupportedOperationException.class)
+                .isInstanceOf(RuntimeException.class)
                 .hasMessageContaining(
                         "Can not set changelog-producer on table without 
primary keys");
 
@@ -323,7 +323,7 @@ public class SparkReadITCase extends SparkReadTestBase {
                                 spark.sql(
                                         "ALTER TABLE T SET 
TBLPROPERTIES('changelog-producer' 'input')"))
                 .rootCause()
-                .isInstanceOf(UnsupportedOperationException.class)
+                .isInstanceOf(RuntimeException.class)
                 .hasMessageContaining(
                         "Can not set changelog-producer on table without 
primary keys");
     }


Reply via email to