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 + "'";
}