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

mbudiu 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 39bf99bdd1 [CALCITE-6268] Support implementing custom JdbcSchema
39bf99bdd1 is described below

commit 39bf99bdd1d126b21d9f184b78ddc3bb887cb2a0
Author: Ulrich Kramer <[email protected]>
AuthorDate: Fri Feb 16 12:45:38 2024 +0100

    [CALCITE-6268] Support implementing custom JdbcSchema
---
 .../calcite/adapter/jdbc/JdbcCatalogSchema.java    | 14 +++++-
 .../apache/calcite/adapter/jdbc/JdbcSchema.java    | 14 +++++-
 .../org/apache/calcite/jdbc/CalciteSchema.java     | 13 ++----
 .../org/apache/calcite/test/JdbcAdapterTest.java   | 11 +++++
 .../java/org/apache/calcite/test/JdbcTest.java     | 53 ++++++++++++++++++++++
 5 files changed, 93 insertions(+), 12 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcCatalogSchema.java 
b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcCatalogSchema.java
index e2e1478d13..202bf0e017 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcCatalogSchema.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcCatalogSchema.java
@@ -22,6 +22,7 @@ import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.schema.Schema;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.Schemas;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.sql.SqlDialect;
 import org.apache.calcite.sql.SqlDialectFactory;
@@ -54,7 +55,7 @@ import static java.util.Objects.requireNonNull;
  * {@link JdbcSchema} for each schema name. Each JdbcSchema will populate its
  * tables on demand.
  */
-public class JdbcCatalogSchema extends AbstractSchema {
+public class JdbcCatalogSchema extends AbstractSchema implements Wrapper {
   final DataSource dataSource;
   public final SqlDialect dialect;
   final JdbcConvention convention;
@@ -137,6 +138,17 @@ public class JdbcCatalogSchema extends AbstractSchema {
     return dataSource;
   }
 
+
+  @Override public <T extends Object> @Nullable T unwrap(Class<T> clazz) {
+    if (clazz.isInstance(this)) {
+      return clazz.cast(this);
+    }
+    if (clazz == DataSource.class) {
+      return clazz.cast(getDataSource());
+    }
+    return null;
+  }
+
   /** Contains sub-schemas by name, and the name of the default schema. */
   private static class SubSchemaMap {
     final String defaultSchemaName;
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java 
b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
index 006390e387..176939c915 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
@@ -33,6 +33,7 @@ import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.SchemaVersion;
 import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.sql.SqlDialect;
 import org.apache.calcite.sql.SqlDialectFactory;
 import org.apache.calcite.sql.SqlDialectFactoryImpl;
@@ -75,7 +76,7 @@ import static java.util.Objects.requireNonNull;
  * queries against this schema are executed against those tables, pushing down
  * as much as possible of the query logic to SQL.
  */
-public class JdbcSchema implements Schema {
+public class JdbcSchema implements Schema, Wrapper {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(JdbcSchema.class);
 
   final DataSource dataSource;
@@ -512,6 +513,17 @@ public class JdbcSchema implements Schema {
     return ImmutableSet.of();
   }
 
+  @Override public <T extends Object> @Nullable T unwrap(Class<T> clazz) {
+    if (clazz.isInstance(this)) {
+      return clazz.cast(this);
+    }
+    if (clazz == DataSource.class) {
+      return clazz.cast(getDataSource());
+    }
+    return null;
+  }
+
+
   private static void close(
       @Nullable Connection connection,
       @Nullable Statement statement,
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java 
b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
index 4466bd3cd5..76e1ba39f1 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java
@@ -16,8 +16,6 @@
  */
 package org.apache.calcite.jdbc;
 
-import org.apache.calcite.adapter.jdbc.JdbcCatalogSchema;
-import org.apache.calcite.adapter.jdbc.JdbcSchema;
 import org.apache.calcite.linq4j.function.Experimental;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.materialize.Lattice;
@@ -28,6 +26,7 @@ import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.SchemaVersion;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.TableMacro;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.schema.impl.MaterializedViewTable;
 import org.apache.calcite.schema.impl.StarTable;
 import org.apache.calcite.util.NameMap;
@@ -49,7 +48,6 @@ import java.util.Map;
 import java.util.NavigableMap;
 import java.util.NavigableSet;
 import java.util.Set;
-import javax.sql.DataSource;
 
 import static java.util.Objects.requireNonNull;
 
@@ -702,13 +700,8 @@ public abstract class CalciteSchema {
       if (clazz.isInstance(CalciteSchema.this.schema)) {
         return clazz.cast(CalciteSchema.this.schema);
       }
-      if (clazz == DataSource.class) {
-        if (schema instanceof JdbcSchema) {
-          return clazz.cast(((JdbcSchema) schema).getDataSource());
-        }
-        if (schema instanceof JdbcCatalogSchema) {
-          return clazz.cast(((JdbcCatalogSchema) schema).getDataSource());
-        }
+      if (schema instanceof Wrapper) {
+        return ((Wrapper) schema).unwrapOrThrow(clazz);
       }
       throw new ClassCastException("not a " + clazz);
     }
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java 
b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
index ea57e5d945..fbcb1727f9 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -117,6 +117,17 @@ class JdbcAdapterTest {
                 + "WHERE \"EMPNO\" > 10");
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6268";>[CALCITE-6268]
+   * Support implementing custom JdbcSchema</a>. */
+  @Test void testCustomJdbc() {
+    CalciteAssert.model(JdbcTest.FOODMART_SCOTT_CUSTOM_MODEL)
+        .query("select * from SCOTT.emp\n")
+        .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
+        .planHasSql("SELECT *\nFROM \"SCOTT\".\"EMP\"")
+        .returnsCount(14);
+  }
+
   @Test void testFilterUnionPlan() {
     CalciteAssert.model(FoodmartSchema.FOODMART_MODEL)
         .query("select * from (\n"
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java 
b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 2edb52a93c..5cf1177f7f 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 package org.apache.calcite.test;
+
 import org.apache.calcite.DataContexts;
 import org.apache.calcite.adapter.clone.CloneSchema;
 import org.apache.calcite.adapter.generate.RangeTable;
@@ -62,12 +63,15 @@ import org.apache.calcite.runtime.SqlFunctions;
 import org.apache.calcite.schema.Schema;
 import org.apache.calcite.schema.SchemaFactory;
 import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.SchemaVersion;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.TableFactory;
 import org.apache.calcite.schema.TableMacro;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.schema.impl.AbstractTable;
 import org.apache.calcite.schema.impl.AbstractTableQueryable;
+import org.apache.calcite.schema.impl.DelegatingSchema;
 import org.apache.calcite.schema.impl.TableMacroImpl;
 import org.apache.calcite.schema.impl.ViewTable;
 import org.apache.calcite.sql.SqlCall;
@@ -241,6 +245,55 @@ public class JdbcTest {
       + "(8,1,4))\n"
       + " as t(rn,val,expected)";
 
+  public static final String FOODMART_SCOTT_CUSTOM_MODEL = "{\n"
+      + "  version: '1.0',\n"
+      + "   schemas: [\n"
+      + "     {\n"
+      + "       type: 'custom',\n"
+      + "       factory: '"
+      + JdbcCustomSchemaFactory.class.getName()
+      + "',\n"
+      + "       name: 'SCOTT'\n"
+       + "     }\n"
+      + "   ]\n"
+      + "}";
+
+
+  /**
+   * Tests class for custom JDBC schema.
+   */
+  public static class JdbcCustomSchema extends DelegatingSchema implements 
Wrapper {
+
+    public JdbcCustomSchema(SchemaPlus parentSchema, String name) {
+      super(JdbcSchema.create(parentSchema, name, getDataSource(), 
SCOTT.catalog, SCOTT.schema));
+    }
+
+    private static DataSource getDataSource() {
+      return JdbcSchema.dataSource(SCOTT.url, SCOTT.driver, SCOTT.username, 
SCOTT.password);
+    }
+
+    @Override public Schema snapshot(SchemaVersion version) {
+      return this;
+    }
+
+    @Override public <T extends Object> @Nullable T unwrap(Class<T> clazz) {
+      if (schema instanceof Wrapper) {
+        return ((Wrapper) schema).unwrap(clazz);
+      }
+      return null;
+    }
+  }
+
+  /**
+   * Tests class for custom JDBC schema factory.
+   */
+  public static class JdbcCustomSchemaFactory implements SchemaFactory {
+
+    @Override public Schema create(SchemaPlus parentSchema, String name,
+        Map<String, Object> operand) {
+      return new JdbcCustomSchema(parentSchema, name);
+    }
+  }
   private static String q(String s) {
     return s == null ? "null" : "'" + s + "'";
   }

Reply via email to