This is an automated email from the ASF dual-hosted git repository.
xuzifu666 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new cf4ffc1fdf [CALCITE-6291] Support converting ArrowTable to Queryable
cf4ffc1fdf is described below
commit cf4ffc1fdf9b6d971bc703fb31ec97be9b2f42de
Author: Yu Xu <[email protected]>
AuthorDate: Fri Apr 24 15:03:55 2026 +0800
[CALCITE-6291] Support converting ArrowTable to Queryable
---
.../apache/calcite/adapter/arrow/ArrowTable.java | 38 +++++++++++-
.../calcite/adapter/arrow/ArrowAdapterTest.java | 70 ++++++++++++++++++++++
2 files changed, 107 insertions(+), 1 deletion(-)
diff --git
a/arrow/src/main/java/org/apache/calcite/adapter/arrow/ArrowTable.java
b/arrow/src/main/java/org/apache/calcite/adapter/arrow/ArrowTable.java
index fa8d59389b..ba1568bcd2 100644
--- a/arrow/src/main/java/org/apache/calcite/adapter/arrow/ArrowTable.java
+++ b/arrow/src/main/java/org/apache/calcite/adapter/arrow/ArrowTable.java
@@ -19,6 +19,7 @@
import org.apache.calcite.DataContext;
import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.linq4j.Enumerator;
import org.apache.calcite.linq4j.QueryProvider;
import org.apache.calcite.linq4j.Queryable;
import org.apache.calcite.linq4j.tree.Expression;
@@ -33,6 +34,7 @@
import org.apache.calcite.schema.Schemas;
import org.apache.calcite.schema.TranslatableTable;
import org.apache.calcite.schema.impl.AbstractTable;
+import org.apache.calcite.schema.impl.AbstractTableQueryable;
import org.apache.calcite.util.ImmutableIntList;
import org.apache.calcite.util.Util;
@@ -184,7 +186,7 @@ public Enumerable<Object> query(DataContext root,
ImmutableIntList fields,
@Override public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
SchemaPlus schema, String tableName) {
- throw new UnsupportedOperationException();
+ return new ArrowQueryable<>(queryProvider, schema, this, tableName);
}
@Override public Type getElementType() {
@@ -262,4 +264,38 @@ private static TreeNode makeLiteralNode(String literal,
String type) {
+ ", type " + type);
}
}
+
+ /**
+ * Implementation of {@link Queryable} based on a {@link ArrowTable}.
+ *
+ * @param <T> element type
+ */
+ public static class ArrowQueryable<T> extends AbstractTableQueryable<T> {
+ ArrowQueryable(QueryProvider queryProvider, SchemaPlus schema,
+ ArrowTable table, String tableName) {
+ super(queryProvider, schema, table, tableName);
+ }
+
+ @Override public Enumerator<T> enumerator() {
+ throw new UnsupportedOperationException("enumerator");
+ }
+
+ private ArrowTable getTable() {
+ return (ArrowTable) table;
+ }
+
+ /**
+ * Executes a query with projection and filter conditions.
+ *
+ * @param fields projection fields
+ * @param conditions filter conditions
+ * @return result as enumerable
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public Enumerable<Object> query(List<Integer> fields,
+ List<List<List<String>>> conditions) {
+ final ImmutableIntList fieldList = ImmutableIntList.copyOf(fields);
+ return getTable().query(null, fieldList, conditions);
+ }
+ }
}
diff --git
a/arrow/src/test/java/org/apache/calcite/adapter/arrow/ArrowAdapterTest.java
b/arrow/src/test/java/org/apache/calcite/adapter/arrow/ArrowAdapterTest.java
index 25212a2083..275bdd0be7 100644
--- a/arrow/src/test/java/org/apache/calcite/adapter/arrow/ArrowAdapterTest.java
+++ b/arrow/src/test/java/org/apache/calcite/adapter/arrow/ArrowAdapterTest.java
@@ -17,6 +17,9 @@
package org.apache.calcite.adapter.arrow;
import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.linq4j.Queryable;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeSystem;
@@ -39,6 +42,10 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
import static org.apache.calcite.test.Matchers.isListOf;
@@ -94,6 +101,69 @@ static void initializeArrowState(@TempDir Path
sharedTempDir)
isListOf("intField", "stringField", "floatField", "longField"));
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-6291">[CALCITE-6291]
+ * Support converting ArrowTable to Queryable</a>.
+ */
+ @Test void testArrowTableAsQueryable() {
+ ArrowSchema arrowSchema = new ArrowSchema(arrowDataDirectory);
+ Map<String, Table> tableMap = arrowSchema.getTableMap();
+ ArrowTable arrowTable = (ArrowTable) tableMap.get("ARROWDATA");
+
+ // asQueryable can accept null QueryProvider and SchemaPlus for testing
+ Queryable<?> queryable = arrowTable.asQueryable(null, null, "ARROWDATA");
+
+ // Verify that asQueryable returns a non-null Queryable
+ assert queryable != null : "asQueryable should return a non-null
Queryable";
+
+ // Verify that the Queryable is an instance of ArrowQueryable
+ assert queryable instanceof ArrowTable.ArrowQueryable
+ : "asQueryable should return an instance of ArrowQueryable";
+ }
+
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-6291">[CALCITE-6291]
+ * Support converting ArrowTable to Queryable</a>.
+ */
+ @Test void testArrowQueryableQueryWithData() {
+ ArrowSchema arrowSchema = new ArrowSchema(arrowDataDirectory);
+ Map<String, Table> tableMap = arrowSchema.getTableMap();
+ ArrowTable arrowTable = (ArrowTable) tableMap.get("ARROWDATA");
+
+ @SuppressWarnings("unchecked")
+ ArrowTable.ArrowQueryable<Object> queryable =
+ (ArrowTable.ArrowQueryable<Object>) arrowTable.asQueryable(null, null,
"ARROWDATA");
+
+ // Query with projection on all fields (0, 1, 2, 3) and no filter
conditions
+ List<Integer> fields = Arrays.asList(0, 1, 2, 3);
+ List<List<List<String>>> conditions = Collections.emptyList();
+
+ Enumerable<Object> enumerable = queryable.query(fields, conditions);
+
+ // Fetch the first 6 rows using enumerator
+ List<Object> results = new ArrayList<>();
+ Enumerator<Object> enumerator = enumerable.enumerator();
+ int count = 0;
+ while (enumerator.moveNext() && count < 6) {
+ results.add(enumerator.current());
+ count++;
+ }
+ enumerator.close();
+
+ assert results.size() == 6 : "Expected 6 rows, got " + results.size();
+
+ // Verify each row is an Object array with 4 fields
+ for (int i = 0; i < 6; i++) {
+ Object[] row = (Object[]) results.get(i);
+ assert row.length == 4 : "Expected 4 fields, got " + row.length;
+ assert row[0].equals(i) : "Expected intField=" + i + ", got " + row[0];
+ // stringField may be Text or String type, convert to String for
comparison
+ String stringValue = row[1].toString();
+ assert stringValue.equals(String.valueOf(i))
+ : "Expected stringField=" + i + ", got " + stringValue;
+ }
+ }
+
@Test void testArrowProjectAllFields() {
String sql = "select * from arrowdata\n";
String plan = "PLAN=ArrowToEnumerableConverter\n"