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

biyan 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 d60110eb51 [core] Add lance table type for rest catalog (#5977)
d60110eb51 is described below

commit d60110eb51b54f0a574f3275a5e47900e44ee87c
Author: YeJunHao <[email protected]>
AuthorDate: Wed Jul 30 11:40:19 2025 +0800

    [core] Add lance table type for rest catalog (#5977)
---
 .../shortcodes/generated/core_configuration.html   |   2 +-
 .../src/main/java/org/apache/paimon/TableType.java |   3 +-
 .../org/apache/paimon/catalog/CatalogUtils.java    |  19 +++
 .../org/apache/paimon/table/lance/LanceTable.java  |  88 ++++++++++++++
 .../apache/paimon/table/lance/LanceTableImpl.java  | 130 +++++++++++++++++++++
 .../org/apache/paimon/rest/RESTCatalogTest.java    |  30 +++++
 6 files changed, 270 insertions(+), 2 deletions(-)

diff --git a/docs/layouts/shortcodes/generated/core_configuration.html 
b/docs/layouts/shortcodes/generated/core_configuration.html
index 77237c198e..311914ebb0 100644
--- a/docs/layouts/shortcodes/generated/core_configuration.html
+++ b/docs/layouts/shortcodes/generated/core_configuration.html
@@ -1198,7 +1198,7 @@ If the data size allocated for the sorting task is 
uneven,which may lead to perf
             <td><h5>type</h5></td>
             <td style="word-wrap: break-word;">table</td>
             <td><p>Enum</p></td>
-            <td>Type of the table.<br /><br />Possible values:<ul><li>"table": 
Normal Paimon table.</li><li>"format-table": A file format table refers to a 
directory that contains multiple files of the same 
format.</li><li>"materialized-table": A materialized table combines normal 
Paimon table and materialized SQL.</li><li>"object-table": An object table 
combines normal Paimon table and object location.</li></ul></td>
+            <td>Type of the table.<br /><br />Possible values:<ul><li>"table": 
Normal Paimon table.</li><li>"format-table": A file format table refers to a 
directory that contains multiple files of the same 
format.</li><li>"materialized-table": A materialized table combines normal 
Paimon table and materialized SQL.</li><li>"object-table": An object table 
combines normal Paimon table and object location.</li><li>"lance-table": A 
lance table, see 'https://lancedb.github.io/lance/'.</li></ul></td>
         </tr>
         <tr>
             <td><h5>upsert-key</h5></td>
diff --git a/paimon-api/src/main/java/org/apache/paimon/TableType.java 
b/paimon-api/src/main/java/org/apache/paimon/TableType.java
index 5f3f1f0d1f..215070cd02 100644
--- a/paimon-api/src/main/java/org/apache/paimon/TableType.java
+++ b/paimon-api/src/main/java/org/apache/paimon/TableType.java
@@ -33,7 +33,8 @@ public enum TableType implements DescribedEnum {
             "materialized-table",
             "A materialized table combines normal Paimon table and 
materialized SQL."),
     OBJECT_TABLE(
-            "object-table", "An object table combines normal Paimon table and 
object location.");
+            "object-table", "An object table combines normal Paimon table and 
object location."),
+    LANCE_TABLE("lance-table", "A lance table, see 
'https://lancedb.github.io/lance/'.");
 
     private final String value;
     private final String description;
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 766b708663..2b79263438 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
@@ -33,6 +33,7 @@ import org.apache.paimon.table.FileStoreTable;
 import org.apache.paimon.table.FileStoreTableFactory;
 import org.apache.paimon.table.FormatTable;
 import org.apache.paimon.table.Table;
+import org.apache.paimon.table.lance.LanceTable;
 import org.apache.paimon.table.object.ObjectTable;
 import org.apache.paimon.table.system.AllTableOptionsTable;
 import org.apache.paimon.table.system.CatalogOptionsTable;
@@ -211,6 +212,10 @@ public class CatalogUtils {
             return toObjectTable(identifier, schema, dataFileIO);
         }
 
+        if (options.type() == TableType.LANCE_TABLE) {
+            return toLanceTable(identifier, schema, dataFileIO);
+        }
+
         CatalogEnvironment catalogEnv =
                 new CatalogEnvironment(
                         identifier,
@@ -305,4 +310,18 @@ public class CatalogUtils {
                 .comment(schema.comment())
                 .build();
     }
+
+    private static LanceTable toLanceTable(
+            Identifier identifier, TableSchema schema, Function<Path, FileIO> 
fileIO) {
+        Map<String, String> options = schema.options();
+        String location = options.get(CoreOptions.PATH.key());
+        return LanceTable.builder()
+                .fileIO(fileIO.apply(new Path(location)))
+                .identifier(identifier)
+                .location(location)
+                .rowType(schema.logicalRowType())
+                .options(options)
+                .comment(schema.comment())
+                .build();
+    }
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/lance/LanceTable.java 
b/paimon-core/src/main/java/org/apache/paimon/table/lance/LanceTable.java
new file mode 100644
index 0000000000..93146a41a8
--- /dev/null
+++ b/paimon-core/src/main/java/org/apache/paimon/table/lance/LanceTable.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.table.lance;
+
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.fs.FileIO;
+import org.apache.paimon.table.Table;
+import org.apache.paimon.types.RowType;
+
+import java.util.Map;
+
+/**
+ * A lance table format table, paimon does not support read and write 
operation on this table yet.
+ */
+public interface LanceTable extends Table {
+
+    /** Object location in file system. */
+    String location();
+
+    @Override
+    LanceTable copy(Map<String, String> dynamicOptions);
+
+    /** Create a new builder for {@link LanceTable}. */
+    static Builder builder() {
+        return new Builder();
+    }
+
+    /** Builder for {@link LanceTable}. */
+    class Builder {
+
+        private Identifier identifier;
+        private FileIO fileIO;
+        private RowType rowType;
+        private String location;
+        private Map<String, String> options;
+        private String comment;
+
+        public Builder identifier(Identifier identifier) {
+            this.identifier = identifier;
+            return this;
+        }
+
+        public Builder fileIO(FileIO fileIO) {
+            this.fileIO = fileIO;
+            return this;
+        }
+
+        public Builder rowType(RowType rowType) {
+            this.rowType = rowType;
+            return this;
+        }
+
+        public Builder location(String location) {
+            this.location = location;
+            return this;
+        }
+
+        public Builder options(Map<String, String> options) {
+            this.options = options;
+            return this;
+        }
+
+        public Builder comment(String comment) {
+            this.comment = comment;
+            return this;
+        }
+
+        public LanceTable build() {
+            return new LanceTableImpl(identifier, fileIO, rowType, location, 
options, comment);
+        }
+    }
+}
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/lance/LanceTableImpl.java 
b/paimon-core/src/main/java/org/apache/paimon/table/lance/LanceTableImpl.java
new file mode 100644
index 0000000000..2669ae699a
--- /dev/null
+++ 
b/paimon-core/src/main/java/org/apache/paimon/table/lance/LanceTableImpl.java
@@ -0,0 +1,130 @@
+/*
+ * 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.table.lance;
+
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.fs.FileIO;
+import org.apache.paimon.stats.Statistics;
+import org.apache.paimon.table.ReadonlyTable;
+import org.apache.paimon.table.source.InnerTableRead;
+import org.apache.paimon.table.source.InnerTableScan;
+import org.apache.paimon.types.RowType;
+
+import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/** An implementation for {@link LanceTable}. */
+public class LanceTableImpl implements ReadonlyTable, LanceTable {
+
+    private final Identifier identifier;
+    private final FileIO fileIO;
+    private final RowType rowType;
+    private final String location;
+    private final Map<String, String> options;
+    @Nullable private final String comment;
+
+    public LanceTableImpl(
+            Identifier identifier,
+            FileIO fileIO,
+            RowType rowType,
+            String location,
+            Map<String, String> options,
+            @Nullable String comment) {
+        this.identifier = identifier;
+        this.fileIO = fileIO;
+        this.rowType = rowType;
+        this.location = location;
+        this.options = options;
+        this.comment = comment;
+    }
+
+    @Override
+    public String name() {
+        return identifier.getTableName();
+    }
+
+    @Override
+    public String fullName() {
+        return identifier.getFullName();
+    }
+
+    @Override
+    public RowType rowType() {
+        return rowType;
+    }
+
+    @Override
+    public List<String> partitionKeys() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<String> primaryKeys() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Map<String, String> options() {
+        return options;
+    }
+
+    @Override
+    public Optional<String> comment() {
+        return Optional.ofNullable(comment);
+    }
+
+    @Override
+    public Optional<Statistics> statistics() {
+        return ReadonlyTable.super.statistics();
+    }
+
+    @Override
+    public FileIO fileIO() {
+        return fileIO;
+    }
+
+    @Override
+    public String location() {
+        return location;
+    }
+
+    @Override
+    public LanceTable copy(Map<String, String> dynamicOptions) {
+        Map<String, String> newOptions = new HashMap<>(options);
+        newOptions.putAll(dynamicOptions);
+        return new LanceTableImpl(identifier, fileIO, rowType, location, 
newOptions, comment);
+    }
+
+    @Override
+    public InnerTableScan newScan() {
+        throw new UnsupportedOperationException(
+                "LanceTable does not support InnerTableScan. Use newRead() 
instead.");
+    }
+
+    @Override
+    public InnerTableRead newRead() {
+        throw new UnsupportedOperationException(
+                "LanceTable does not support InnerTableRead. Use newScan() 
instead.");
+    }
+}
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 8755cb74fe..b1b52520ce 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
@@ -2039,6 +2039,36 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         assertThat(files).containsExactlyInAnyOrder("my_file1", "my_file2", 
"dir1/my_file3");
     }
 
+    @Test
+    public void testCreateLanceTable() throws Exception {
+        Catalog catalog = newRestCatalogWithDataToken();
+        catalog.createDatabase("test_db", false);
+        List<String> tables = catalog.listTables("test_db");
+        assertThat(tables).isEmpty();
+
+        Map<String, String> options = new HashMap<>();
+        options.put("type", "lance-table");
+        options.put("a", "b");
+        Schema schema =
+                new Schema(
+                        Lists.newArrayList(
+                                new DataField(0, "pk", DataTypes.INT()),
+                                new DataField(1, "col1", DataTypes.STRING()),
+                                new DataField(2, "col2", DataTypes.STRING())),
+                        Collections.emptyList(),
+                        Collections.emptyList(),
+                        options,
+                        "");
+        catalog.createTable(Identifier.create("test_db", "table1"), schema, 
false);
+
+        tables = catalog.listTables("test_db");
+        Table table = catalog.getTable(Identifier.create("test_db", "table1"));
+        assertThat(table.options()).containsEntry("a", "b");
+        assertThat(table.options().containsKey("path")).isTrue();
+        assertThat(table.fileIO()).isInstanceOf(RESTTokenFileIO.class);
+        assertThat(tables).containsExactlyInAnyOrder("table1");
+    }
+
     private TestPagedResponse generateTestPagedResponse(
             Map<String, String> queryParams,
             List<Integer> testData,

Reply via email to