Repository: calcite Updated Branches: refs/heads/master c2059f152 -> ac8d04ed9
[CALCITE-911] Add a variant of CalciteSchema that does not cache sub-objects Close apache/calcite#142 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/ac8d04ed Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/ac8d04ed Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/ac8d04ed Branch: refs/heads/master Commit: ac8d04ed95589f29571b7de3c220876c3ebc3a00 Parents: c2059f1 Author: Jinfeng Ni <[email protected]> Authored: Tue Mar 3 14:51:09 2015 -0800 Committer: Julian Hyde <[email protected]> Committed: Thu Nov 5 23:18:24 2015 -0800 ---------------------------------------------------------------------- .../calcite/jdbc/CachingCalciteSchema.java | 292 +++++++++++++++ .../calcite/jdbc/CalciteConnectionImpl.java | 12 +- .../org/apache/calcite/jdbc/CalciteFactory.java | 2 +- .../calcite/jdbc/CalciteJdbc41Factory.java | 4 +- .../apache/calcite/jdbc/CalciteMetaImpl.java | 2 +- .../org/apache/calcite/jdbc/CalcitePrepare.java | 2 +- .../apache/calcite/jdbc/CalciteRootSchema.java | 3 +- .../org/apache/calcite/jdbc/CalciteSchema.java | 352 +++++++------------ .../java/org/apache/calcite/jdbc/Driver.java | 2 +- .../calcite/jdbc/SimpleCalciteSchema.java | 141 ++++++++ .../org/apache/calcite/materialize/Lattice.java | 11 +- .../materialize/MaterializationActor.java | 9 +- .../java/org/apache/calcite/schema/Schemas.java | 3 +- .../org/apache/calcite/tools/Frameworks.java | 1 - .../java/org/apache/calcite/test/JdbcTest.java | 51 +++ site/_docs/howto.md | 4 +- 16 files changed, 633 insertions(+), 258 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java new file mode 100644 index 0000000..8defef4 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java @@ -0,0 +1,292 @@ +/* + * 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.calcite.jdbc; + +import org.apache.calcite.schema.Function; +import org.apache.calcite.schema.Schema; +import org.apache.calcite.schema.Table; +import org.apache.calcite.schema.TableMacro; +import org.apache.calcite.util.Compatible; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.ImmutableSortedSet; + +import java.util.Collection; +import java.util.NavigableSet; + +/** + * Concrete implementation of {@link CalciteSchema} that caches tables, + * functions and sub-schemas. + */ +class CachingCalciteSchema extends CalciteSchema { + private final Cached<SubSchemaCache> implicitSubSchemaCache; + private final Cached<NavigableSet<String>> implicitTableCache; + private final Cached<NavigableSet<String>> implicitFunctionCache; + + private boolean cache = true; + + /** Creates a CachingCalciteSchema. */ + CachingCalciteSchema(CalciteSchema parent, Schema schema, String name) { + super(parent, schema, name); + this.implicitSubSchemaCache = + new AbstractCached<SubSchemaCache>() { + public SubSchemaCache build() { + return new SubSchemaCache(CachingCalciteSchema.this, + Compatible.INSTANCE.navigableSet( + ImmutableSortedSet.copyOf(COMPARATOR, + CachingCalciteSchema.this.schema.getSubSchemaNames()))); + } + }; + this.implicitTableCache = + new AbstractCached<NavigableSet<String>>() { + public NavigableSet<String> build() { + return Compatible.INSTANCE.navigableSet( + ImmutableSortedSet.copyOf(COMPARATOR, + CachingCalciteSchema.this.schema.getTableNames())); + } + }; + this.implicitFunctionCache = + new AbstractCached<NavigableSet<String>>() { + public NavigableSet<String> build() { + return Compatible.INSTANCE.navigableSet( + ImmutableSortedSet.copyOf(COMPARATOR, + CachingCalciteSchema.this.schema.getFunctionNames())); + } + }; + } + + public void setCache(boolean cache) { + if (cache == this.cache) { + return; + } + final long now = System.currentTimeMillis(); + implicitSubSchemaCache.enable(now, cache); + implicitTableCache.enable(now, cache); + implicitFunctionCache.enable(now, cache); + this.cache = cache; + } + + protected boolean isCacheEnabled() { + return this.cache; + } + + protected CalciteSchema getImplicitSubSchema(String schemaName, + boolean caseSensitive) { + if (caseSensitive) { + // Check implicit schemas, case-sensitive. + final long now = System.currentTimeMillis(); + final SubSchemaCache subSchemaCache = implicitSubSchemaCache.get(now); + if (subSchemaCache.names.contains(schemaName)) { + return subSchemaCache.cache.getUnchecked(schemaName); + } + } else { + // Check implicit schemas, case-insensitive. + final long now = System.currentTimeMillis(); + final SubSchemaCache subSchemaCache = + implicitSubSchemaCache.get(now); + final String schemaName2 = subSchemaCache.names.floor(schemaName); + if (schemaName2 != null) { + return subSchemaCache.cache.getUnchecked(schemaName2); + } + } + return null; + } + + /** Adds a child schema of this schema. */ + public CalciteSchema add(String name, Schema schema) { + final CalciteSchema calciteSchema = + new CachingCalciteSchema(this, schema, name); + subSchemaMap.put(name, calciteSchema); + return calciteSchema; + } + + protected TableEntry getImplicitTable(String tableName, + boolean caseSensitive) { + if (caseSensitive) { + // Check implicit tables, case-sensitive. + final long now = System.currentTimeMillis(); + if (implicitTableCache.get(now).contains(tableName)) { + final Table table = schema.getTable(tableName); + if (table != null) { + return tableEntry(tableName, table); + } + } + } else { + // Check implicit tables, case-insensitive. + final long now = System.currentTimeMillis(); + final NavigableSet<String> implicitTableNames = + implicitTableCache.get(now); + final String tableName2 = implicitTableNames.floor(tableName); + if (tableName2 != null) { + final Table table = schema.getTable(tableName2); + if (table != null) { + return tableEntry(tableName2, table); + } + } + } + return null; + } + + protected void addImplicitSubSchemaToBuilder( + ImmutableSortedMap.Builder<String, CalciteSchema> builder) { + ImmutableSortedMap<String, CalciteSchema> explicitSubSchemas = builder.build(); + final long now = System.currentTimeMillis(); + final SubSchemaCache subSchemaCache = implicitSubSchemaCache.get(now); + for (String name : subSchemaCache.names) { + if (explicitSubSchemas.containsKey(name)) { + // explicit sub-schema wins. + continue; + } + builder.put(name, subSchemaCache.cache.getUnchecked(name)); + } + } + + protected void addImplicitTableToBuilder( + ImmutableSortedSet.Builder<String> builder) { + // Add implicit tables, case-sensitive. + builder.addAll(implicitTableCache.get(System.currentTimeMillis())); + } + + protected void addImplicitFunctionToBuilder( + ImmutableList.Builder<Function> builder) { + // Add implicit functions, case-insensitive. + for (String name2 + : find(implicitFunctionCache.get(System.currentTimeMillis()), name)) { + final Collection<Function> functions = schema.getFunctions(name2); + if (functions != null) { + builder.addAll(functions); + } + } + } + + protected void addImplicitFuncNamesToBuilder( + ImmutableSortedSet.Builder<String> builder) { + // Add implicit functions, case-sensitive. + builder.addAll(implicitFunctionCache.get(System.currentTimeMillis())); + } + + protected void addImplicitTablesBasedOnNullaryFunctionsToBuilder( + ImmutableSortedMap.Builder<String, Table> builder) { + ImmutableSortedMap<String, Table> explicitTables = builder.build(); + + for (String s : implicitFunctionCache.get(System.currentTimeMillis())) { + // explicit table wins. + if (explicitTables.containsKey(s)) { + continue; + } + for (Function function : schema.getFunctions(s)) { + if (function instanceof TableMacro + && function.getParameters().isEmpty()) { + final Table table = ((TableMacro) function).apply(ImmutableList.of()); + builder.put(s, table); + } + } + } + } + + protected TableEntry getImplicitTableBasedOnNullaryFunction(String tableName, + boolean caseSensitive) { + final NavigableSet<String> set = + implicitFunctionCache.get(System.currentTimeMillis()); + for (String s : find(set, tableName)) { + for (Function function : schema.getFunctions(s)) { + if (function instanceof TableMacro + && function.getParameters().isEmpty()) { + final Table table = + ((TableMacro) function).apply(ImmutableList.of()); + return tableEntry(tableName, table); + } + } + } + return null; + } + + /** Strategy for caching the value of an object and re-creating it if its + * value is out of date as of a given timestamp. + * + * @param <T> Type of cached object + */ + private interface Cached<T> { + /** Returns the value; uses cached value if valid. */ + T get(long now); + + /** Creates a new value. */ + T build(); + + /** Called when CalciteSchema caching is enabled or disabled. */ + void enable(long now, boolean enabled); + } + + /** Implementation of {@link CachingCalciteSchema.Cached} + * that drives from {@link CachingCalciteSchema#cache}. */ + private abstract class AbstractCached<T> implements Cached<T> { + T t; + long checked = Long.MIN_VALUE; + + public T get(long now) { + if (!CachingCalciteSchema.this.cache) { + return build(); + } + if (checked == Long.MIN_VALUE + || schema.contentsHaveChangedSince(checked, now)) { + t = build(); + } + checked = now; + return t; + } + + public void enable(long now, boolean enabled) { + if (!enabled) { + t = null; + } + checked = Long.MIN_VALUE; + } + } + + /** Information about the implicit sub-schemas of an {@link CalciteSchema}. */ + private static class SubSchemaCache { + /** The names of sub-schemas returned from the {@link Schema} SPI. */ + final NavigableSet<String> names; + /** Cached {@link CalciteSchema} wrappers. It is + * worth caching them because they contain maps of their own sub-objects. */ + final LoadingCache<String, CalciteSchema> cache; + + private SubSchemaCache(final CalciteSchema calciteSchema, + NavigableSet<String> names) { + this.names = names; + this.cache = CacheBuilder.newBuilder().build( + new CacheLoader<String, CalciteSchema>() { + @SuppressWarnings("NullableProblems") + @Override public CalciteSchema load(String schemaName) { + final Schema subSchema = + calciteSchema.schema.getSubSchema(schemaName); + if (subSchema == null) { + throw new RuntimeException("sub-schema " + schemaName + + " not found"); + } + return new CachingCalciteSchema(calciteSchema, subSchema, schemaName); + } + }); + } + } +} + +// End CachingCalciteSchema.java http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java index 2b723d9..4319fe0 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java @@ -87,7 +87,7 @@ abstract class CalciteConnectionImpl implements CalciteConnection, QueryProvider { public final JavaTypeFactory typeFactory; - final CalciteRootSchema rootSchema; + final CalciteSchema rootSchema; final Function0<CalcitePrepare> prepareFactory; final CalciteServer server = new CalciteServerImpl(); @@ -107,7 +107,7 @@ abstract class CalciteConnectionImpl * @param typeFactory Type factory, or null */ protected CalciteConnectionImpl(Driver driver, AvaticaFactory factory, - String url, Properties info, CalciteRootSchema rootSchema, + String url, Properties info, CalciteSchema rootSchema, JavaTypeFactory typeFactory) { super(driver, factory, url, info); CalciteConnectionConfig cfg = new CalciteConnectionConfigImpl(info); @@ -120,8 +120,10 @@ abstract class CalciteConnectionImpl this.typeFactory = new JavaTypeFactoryImpl(typeSystem); } this.rootSchema = - rootSchema != null ? rootSchema : CalciteSchema.createRootSchema(true); - + Preconditions.checkNotNull(rootSchema != null + ? rootSchema + : CalciteSchema.createRootSchema(true)); + Preconditions.checkArgument(this.rootSchema.isRoot(), "must be root schema"); this.properties.put(InternalProperty.CASE_SENSITIVE, cfg.caseSensitive()); this.properties.put(InternalProperty.UNQUOTED_CASING, cfg.unquotedCasing()); this.properties.put(InternalProperty.QUOTED_CASING, cfg.quotedCasing()); @@ -432,7 +434,7 @@ abstract class CalciteConnectionImpl return connection.typeFactory; } - public CalciteRootSchema getRootSchema() { + public CalciteSchema getRootSchema() { return connection.rootSchema; } http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/CalciteFactory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteFactory.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteFactory.java index 03f5496..68c5507 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteFactory.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteFactory.java @@ -56,7 +56,7 @@ public abstract class CalciteFactory implements AvaticaFactory { /** Creates a connection with a root schema. */ public abstract AvaticaConnection newConnection(UnregisteredDriver driver, AvaticaFactory factory, String url, Properties info, - CalciteRootSchema rootSchema, JavaTypeFactory typeFactory); + CalciteSchema rootSchema, JavaTypeFactory typeFactory); } // End CalciteFactory.java http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java index 5f677c1..04258b7 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java @@ -55,7 +55,7 @@ public class CalciteJdbc41Factory extends CalciteFactory { public CalciteJdbc41Connection newConnection(UnregisteredDriver driver, AvaticaFactory factory, String url, Properties info, - CalciteRootSchema rootSchema, JavaTypeFactory typeFactory) { + CalciteSchema rootSchema, JavaTypeFactory typeFactory) { return new CalciteJdbc41Connection( (Driver) driver, factory, url, info, rootSchema, typeFactory); } @@ -109,7 +109,7 @@ public class CalciteJdbc41Factory extends CalciteFactory { /** Implementation of connection for JDBC 4.1. */ private static class CalciteJdbc41Connection extends CalciteConnectionImpl { CalciteJdbc41Connection(Driver driver, AvaticaFactory factory, String url, - Properties info, CalciteRootSchema rootSchema, + Properties info, CalciteSchema rootSchema, JavaTypeFactory typeFactory) { super(driver, factory, url, info, rootSchema, typeFactory); } http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java index e4f0ae5..96b0f54 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java @@ -647,7 +647,7 @@ public class CalciteMetaImpl extends MetaImpl { /** A trojan-horse method, subject to change without notice. */ @VisibleForTesting - public static CalciteConnection connect(CalciteRootSchema schema, + public static CalciteConnection connect(CalciteSchema schema, JavaTypeFactory typeFactory) { return DRIVER.connect(schema, typeFactory); } http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java index 7ed43f4..0aa47bc 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java @@ -107,7 +107,7 @@ public interface CalcitePrepare { interface Context { JavaTypeFactory getTypeFactory(); - CalciteRootSchema getRootSchema(); + CalciteSchema getRootSchema(); List<String> getDefaultSchemaPath(); http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/CalciteRootSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteRootSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteRootSchema.java index 6a22618..66e7526 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteRootSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteRootSchema.java @@ -21,7 +21,8 @@ import org.apache.calcite.schema.Schema; /** * Root schema. */ -public class CalciteRootSchema extends CalciteSchema { +@Deprecated // to be removed before 2.0 +public class CalciteRootSchema extends CachingCalciteSchema { /** Creates a root schema. */ CalciteRootSchema(Schema schema) { super(null, schema, ""); http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java ---------------------------------------------------------------------- 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 3ce35b0..a1f24b0 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java @@ -28,9 +28,6 @@ import org.apache.calcite.schema.impl.StarTable; import org.apache.calcite.util.Compatible; import com.google.common.base.Preconditions; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedSet; @@ -54,13 +51,13 @@ import java.util.TreeSet; * * <p>Wrapper around user-defined schema used internally.</p> */ -public class CalciteSchema { +public abstract class CalciteSchema { /** Comparator that compares all strings differently, but if two strings are * equal in case-insensitive match they are right next to each other. In a * collection sorted on this comparator, we can find case-insensitive matches * for a given string using a range scan between the upper-case string and * the lower-case string. */ - private static final Comparator<String> COMPARATOR = + protected static final Comparator<String> COMPARATOR = new Comparator<String>() { public int compare(String o1, String o2) { int c = o1.compareToIgnoreCase(o2); @@ -77,69 +74,68 @@ public class CalciteSchema { /** Tables explicitly defined in this schema. Does not include tables in * {@link #schema}. */ public final NavigableMap<String, TableEntry> tableMap = - new TreeMap<String, TableEntry>(COMPARATOR); - private final Multimap<String, FunctionEntry> functionMap = + new TreeMap<>(COMPARATOR); + protected final Multimap<String, FunctionEntry> functionMap = LinkedListMultimap.create(); - private final NavigableMap<String, LatticeEntry> latticeMap = - new TreeMap<String, LatticeEntry>(COMPARATOR); - private final NavigableSet<String> functionNames = - new TreeSet<String>(COMPARATOR); - private final NavigableMap<String, FunctionEntry> nullaryFunctionMap = - new TreeMap<String, FunctionEntry>(COMPARATOR); - private final NavigableMap<String, CalciteSchema> subSchemaMap = - new TreeMap<String, CalciteSchema>(COMPARATOR); + protected final NavigableMap<String, LatticeEntry> latticeMap = + new TreeMap<>(COMPARATOR); + protected final NavigableSet<String> functionNames = + new TreeSet<>(COMPARATOR); + protected final NavigableMap<String, FunctionEntry> nullaryFunctionMap = + new TreeMap<>(COMPARATOR); + protected final NavigableMap<String, CalciteSchema> subSchemaMap = + new TreeMap<>(COMPARATOR); private ImmutableList<ImmutableList<String>> path; - private boolean cache = true; - private final Cached<SubSchemaCache> implicitSubSchemaCache; - private final Cached<NavigableSet<String>> implicitTableCache; - private final Cached<NavigableSet<String>> implicitFunctionCache; - public CalciteSchema(CalciteSchema parent, final Schema schema, String name) { + CalciteSchema(CalciteSchema parent, Schema schema, String name) { this.parent = parent; this.schema = schema; this.name = name; - assert (parent == null) == (this instanceof CalciteRootSchema); - this.implicitSubSchemaCache = - new AbstractCached<SubSchemaCache>() { - public SubSchemaCache build() { - return new SubSchemaCache(CalciteSchema.this, - Compatible.INSTANCE.navigableSet( - ImmutableSortedSet.copyOf(COMPARATOR, - schema.getSubSchemaNames()))); - } - }; - this.implicitTableCache = - new AbstractCached<NavigableSet<String>>() { - public NavigableSet<String> build() { - return Compatible.INSTANCE.navigableSet( - ImmutableSortedSet.copyOf(COMPARATOR, - schema.getTableNames())); - } - }; - this.implicitFunctionCache = - new AbstractCached<NavigableSet<String>>() { - public NavigableSet<String> build() { - return Compatible.INSTANCE.navigableSet( - ImmutableSortedSet.copyOf(COMPARATOR, - schema.getFunctionNames())); - } - }; } - /** Creates a root schema. When <code>addMetadataSchema</code> argument is - * true a "metadata" schema containing definitions of tables, columns etc. is - * added to root schema. */ - public static CalciteRootSchema createRootSchema(boolean addMetadataSchema) { - CalciteRootSchema rootSchema = - new CalciteRootSchema(new CalciteConnectionImpl.RootSchema()); - if (addMetadataSchema) { - rootSchema.add("metadata", MetadataSchema.INSTANCE); - } - return rootSchema; - } + /** Returns a sub-schema with a given name that is defined implicitly + * (that is, by the underlying {@link Schema} object, not explicitly + * by a call to {@link #add(String, Schema)}), or null. */ + protected abstract CalciteSchema getImplicitSubSchema(String schemaName, + boolean caseSensitive); + + /** Returns a table with a given name that is defined implicitly + * (that is, by the underlying {@link Schema} object, not explicitly + * by a call to {@link #add(String, Table)}), or null. */ + protected abstract TableEntry getImplicitTable(String tableName, + boolean caseSensitive); + + /** Returns table function with a given name and zero arguments that is + * defined implicitly (that is, by the underlying {@link Schema} object, + * not explicitly by a call to {@link #add(String, Function)}), or null. */ + protected abstract TableEntry getImplicitTableBasedOnNullaryFunction(String tableName, + boolean caseSensitive); + + /** Adds implicit sub-schemas to a builder. */ + protected abstract void addImplicitSubSchemaToBuilder( + ImmutableSortedMap.Builder<String, CalciteSchema> builder); + + /** Adds implicit tables to a builder. */ + protected abstract void addImplicitTableToBuilder( + ImmutableSortedSet.Builder<String> builder); + + /** Adds implicit functions to a builder. */ + protected abstract void addImplicitFunctionToBuilder(ImmutableList.Builder<Function> builder); + + /** Adds implicit function names to a builder. */ + protected abstract void addImplicitFuncNamesToBuilder( + ImmutableSortedSet.Builder<String> builder); + + /** Adds implicit table functions to a builder. */ + protected abstract void addImplicitTablesBasedOnNullaryFunctionsToBuilder( + ImmutableSortedMap.Builder<String, Table> builder); + + protected abstract boolean isCacheEnabled(); + + public abstract void setCache(boolean cache); /** Creates a TableEntryImpl with no SQLs. */ - private TableEntryImpl tableEntry(String name, Table table) { + protected TableEntryImpl tableEntry(String name, Table table) { return new TableEntryImpl(this, name, table, ImmutableList.<String>of()); } @@ -177,18 +173,23 @@ public class CalciteSchema { return entry; } - public CalciteRootSchema root() { + public CalciteSchema root() { for (CalciteSchema schema = this;;) { if (schema.parent == null) { - return (CalciteRootSchema) schema; + return schema; } schema = schema.parent; } } + /** Returns whether this is a root schema. */ + public boolean isRoot() { + return parent == null; + } + /** Returns the path of an object in this schema. */ public List<String> path(String name) { - final List<String> list = new ArrayList<String>(); + final List<String> list = new ArrayList<>(); if (name != null) { list.add(name); } @@ -202,17 +203,6 @@ public class CalciteSchema { return ImmutableList.copyOf(Lists.reverse(list)); } - private void setCache(boolean cache) { - if (cache == this.cache) { - return; - } - final long now = System.currentTimeMillis(); - implicitSubSchemaCache.enable(now, cache); - implicitTableCache.enable(now, cache); - implicitFunctionCache.enable(now, cache); - this.cache = cache; - } - public final CalciteSchema getSubSchema(String schemaName, boolean caseSensitive) { if (caseSensitive) { @@ -221,13 +211,6 @@ public class CalciteSchema { if (entry != null) { return entry; } - // Check implicit schemas, case-sensitive. - final long now = System.currentTimeMillis(); - final SubSchemaCache subSchemaCache = implicitSubSchemaCache.get(now); - if (subSchemaCache.names.contains(schemaName)) { - return subSchemaCache.cache.getUnchecked(schemaName); - } - return null; } else { // Check explicit schemas, case-insensitive. //noinspection LoopStatementThatDoesntLoop @@ -235,24 +218,12 @@ public class CalciteSchema { : find(subSchemaMap, schemaName).entrySet()) { return entry.getValue(); } - // Check implicit schemas, case-insensitive. - final long now = System.currentTimeMillis(); - final SubSchemaCache subSchemaCache = - implicitSubSchemaCache.get(now); - final String schemaName2 = subSchemaCache.names.floor(schemaName); - if (schemaName2 != null) { - return subSchemaCache.cache.getUnchecked(schemaName2); - } - return null; } + return getImplicitSubSchema(schemaName, caseSensitive); } /** Adds a child schema of this schema. */ - public CalciteSchema add(String name, Schema schema) { - final CalciteSchema calciteSchema = new CalciteSchema(this, schema, name); - subSchemaMap.put(name, calciteSchema); - return calciteSchema; - } + public abstract CalciteSchema add(String name, Schema schema); /** Returns a table that materializes the given SQL statement. */ public final TableEntry getTableBySql(String sql) { @@ -265,23 +236,13 @@ public class CalciteSchema { } /** Returns a table with the given name. Does not look for views. */ - public final TableEntry getTable(String tableName, - boolean caseSensitive) { + public final TableEntry getTable(String tableName, boolean caseSensitive) { if (caseSensitive) { // Check explicit tables, case-sensitive. final TableEntry entry = tableMap.get(tableName); if (entry != null) { return entry; } - // Check implicit tables, case-sensitive. - final long now = System.currentTimeMillis(); - if (implicitTableCache.get(now).contains(tableName)) { - final Table table = schema.getTable(tableName); - if (table != null) { - return tableEntry(tableName, table); - } - } - return null; } else { // Check explicit tables, case-insensitive. //noinspection LoopStatementThatDoesntLoop @@ -289,19 +250,9 @@ public class CalciteSchema { : find(tableMap, tableName).entrySet()) { return entry.getValue(); } - // Check implicit tables, case-insensitive. - final long now = System.currentTimeMillis(); - final NavigableSet<String> implicitTableNames = - implicitTableCache.get(now); - final String tableName2 = implicitTableNames.floor(tableName); - if (tableName2 != null) { - final Table table = schema.getTable(tableName2); - if (table != null) { - return tableEntry(tableName2, table); - } - } - return null; } + + return getImplicitTable(tableName, caseSensitive); } public String getName() { @@ -337,17 +288,13 @@ public class CalciteSchema { * {@link #add(String, org.apache.calcite.schema.Schema)}) and implicit * (defined using {@link org.apache.calcite.schema.Schema#getSubSchemaNames()} * and {@link Schema#getSubSchema(String)}). */ - public NavigableMap<String, CalciteSchema> getSubSchemaMap() { + public final NavigableMap<String, CalciteSchema> getSubSchemaMap() { // Build a map of implicit sub-schemas first, then explicit sub-schemas. // If there are implicit and explicit with the same name, explicit wins. final ImmutableSortedMap.Builder<String, CalciteSchema> builder = - new ImmutableSortedMap.Builder<String, CalciteSchema>(COMPARATOR); - final long now = System.currentTimeMillis(); - final SubSchemaCache subSchemaCache = implicitSubSchemaCache.get(now); - for (String name : subSchemaCache.names) { - builder.put(name, subSchemaCache.cache.getUnchecked(name)); - } + new ImmutableSortedMap.Builder<>(COMPARATOR); builder.putAll(subSchemaMap); + addImplicitSubSchemaToBuilder(builder); return Compatible.INSTANCE.navigableMap(builder.build()); } @@ -360,19 +307,19 @@ public class CalciteSchema { /** Returns the set of all table names. Includes implicit and explicit tables * and functions with zero parameters. */ - public NavigableSet<String> getTableNames() { + public final NavigableSet<String> getTableNames() { final ImmutableSortedSet.Builder<String> builder = - new ImmutableSortedSet.Builder<String>(COMPARATOR); + new ImmutableSortedSet.Builder<>(COMPARATOR); // Add explicit tables, case-sensitive. builder.addAll(tableMap.keySet()); // Add implicit tables, case-sensitive. - builder.addAll(implicitTableCache.get(System.currentTimeMillis())); + addImplicitTableToBuilder(builder); return Compatible.INSTANCE.navigableSet(builder.build()); } /** Returns a collection of all functions, explicit and implicit, with a given * name. Never null. */ - public Collection<Function> getFunctions(String name, boolean caseSensitive) { + public final Collection<Function> getFunctions(String name, boolean caseSensitive) { final ImmutableList.Builder<Function> builder = ImmutableList.builder(); if (caseSensitive) { @@ -400,34 +347,28 @@ public class CalciteSchema { } } // Add implicit functions, case-insensitive. - for (String name2 - : find(implicitFunctionCache.get(System.currentTimeMillis()), name)) { - final Collection<Function> functions = schema.getFunctions(name2); - if (functions != null) { - builder.addAll(functions); - } - } + addImplicitFunctionToBuilder(builder); } return builder.build(); } /** Returns the list of function names in this schema, both implicit and * explicit, never null. */ - public NavigableSet<String> getFunctionNames() { + public final NavigableSet<String> getFunctionNames() { final ImmutableSortedSet.Builder<String> builder = - new ImmutableSortedSet.Builder<String>(COMPARATOR); + new ImmutableSortedSet.Builder<>(COMPARATOR); // Add explicit functions, case-sensitive. builder.addAll(functionMap.keySet()); // Add implicit functions, case-sensitive. - builder.addAll(implicitFunctionCache.get(System.currentTimeMillis())); + addImplicitFuncNamesToBuilder(builder); return Compatible.INSTANCE.navigableSet(builder.build()); } /** Returns tables derived from explicit and implicit functions * that take zero parameters. */ - public NavigableMap<String, Table> getTablesBasedOnNullaryFunctions() { + public final NavigableMap<String, Table> getTablesBasedOnNullaryFunctions() { ImmutableSortedMap.Builder<String, Table> builder = - new ImmutableSortedMap.Builder<String, Table>(COMPARATOR); + new ImmutableSortedMap.Builder<>(COMPARATOR); for (Map.Entry<String, FunctionEntry> s : nullaryFunctionMap.entrySet()) { final Function function = s.getValue().getFunction(); if (function instanceof TableMacro) { @@ -436,21 +377,14 @@ public class CalciteSchema { builder.put(s.getKey(), table); } } - for (String s : implicitFunctionCache.get(System.currentTimeMillis())) { - for (Function function : schema.getFunctions(s)) { - if (function instanceof TableMacro - && function.getParameters().isEmpty()) { - final Table table = ((TableMacro) function).apply(ImmutableList.of()); - builder.put(s, table); - } - } - } + // add tables derived from implicit functions + addImplicitTablesBasedOnNullaryFunctionsToBuilder(builder); return Compatible.INSTANCE.navigableMap(builder.build()); } /** Returns a tables derived from explicit and implicit functions * that take zero parameters. */ - public TableEntry getTableBasedOnNullaryFunction(String tableName, + public final TableEntry getTableBasedOnNullaryFunction(String tableName, boolean caseSensitive) { if (caseSensitive) { final FunctionEntry functionEntry = nullaryFunctionMap.get(tableName); @@ -479,25 +413,15 @@ public class CalciteSchema { return tableEntry(tableName, table); } } - final NavigableSet<String> set = - implicitFunctionCache.get(System.currentTimeMillis()); - for (String s : find(set, tableName)) { - for (Function function : schema.getFunctions(s)) { - if (function instanceof TableMacro - && function.getParameters().isEmpty()) { - final Table table = - ((TableMacro) function).apply(ImmutableList.of()); - return tableEntry(tableName, table); - } - } - } + TableEntry tableEntry = + getImplicitTableBasedOnNullaryFunction(tableName, false); } return null; } /** Returns a subset of a map whose keys match the given string * case-insensitively. */ - private static <V> NavigableMap<String, V> find(NavigableMap<String, V> map, + protected static <V> NavigableMap<String, V> find(NavigableMap<String, V> map, String s) { assert map.comparator() == COMPARATOR; return map.subMap(s.toUpperCase(), true, s.toLowerCase(), true); @@ -505,11 +429,43 @@ public class CalciteSchema { /** Returns a subset of a set whose values match the given string * case-insensitively. */ - private static Iterable<String> find(NavigableSet<String> set, String name) { + protected static Iterable<String> find(NavigableSet<String> set, String name) { assert set.comparator() == COMPARATOR; return set.subSet(name.toUpperCase(), true, name.toLowerCase(), true); } + /** Creates a root schema. + * + * <p>When <code>addMetadataSchema</code> argument is true adds a "metadata" + * schema containing definitions of tables, columns etc. to root schema. + * By default, creates a {@link CachingCalciteSchema}. + */ + public static CalciteSchema createRootSchema(boolean addMetadataSchema) { + return createRootSchema(addMetadataSchema, true); + } + + /** Creates a root schema. + * + * @param addMetadataSchema Whether to add a "metadata" schema containing + * definitions of tables, columns etc. + * @param cache If true create {@link CachingCalciteSchema}; + * if false create {@link SimpleCalciteSchema} + */ + public static CalciteSchema createRootSchema(boolean addMetadataSchema, + boolean cache) { + CalciteSchema rootSchema; + final Schema schema = new CalciteConnectionImpl.RootSchema(); + if (cache) { + rootSchema = new CachingCalciteSchema(null, schema, ""); + } else { + rootSchema = new SimpleCalciteSchema(null, schema, ""); + } + if (addMetadataSchema) { + rootSchema.add("metadata", MetadataSchema.INSTANCE); + } + return rootSchema; + } + /** * Entry in a schema, such as a table or sub-schema. * @@ -596,7 +552,7 @@ public class CalciteSchema { } public boolean isCacheEnabled() { - return CalciteSchema.this.cache; + return CalciteSchema.this.isCacheEnabled(); } public boolean contentsHaveChangedSince(long lastCheck, long now) { @@ -741,74 +697,6 @@ public class CalciteSchema { } } - /** Strategy for caching the value of an object and re-creating it if its - * value is out of date as of a given timestamp. - * - * @param <T> Type of cached object - */ - private interface Cached<T> { - /** Returns the value; uses cached value if valid. */ - T get(long now); - - /** Creates a new value. */ - T build(); - - /** Called when CalciteSchema caching is enabled or disabled. */ - void enable(long now, boolean enabled); - } - - /** Implementation of {@link CalciteSchema.Cached} - * that drives from {@link CalciteSchema#cache}. */ - private abstract class AbstractCached<T> implements Cached<T> { - T t; - long checked = Long.MIN_VALUE; - - public T get(long now) { - if (!CalciteSchema.this.cache) { - return build(); - } - if (checked == Long.MIN_VALUE - || schema.contentsHaveChangedSince(checked, now)) { - t = build(); - } - checked = now; - return t; - } - - public void enable(long now, boolean enabled) { - if (!enabled) { - t = null; - } - checked = Long.MIN_VALUE; - } - } - - /** Information about the implicit sub-schemas of an {@link CalciteSchema}. */ - private static class SubSchemaCache { - /** The names of sub-schemas returned from the {@link Schema} SPI. */ - final NavigableSet<String> names; - /** Cached {@link CalciteSchema} wrappers. It is - * worth caching them because they contain maps of their own sub-objects. */ - final LoadingCache<String, CalciteSchema> cache; - - private SubSchemaCache(final CalciteSchema calciteSchema, - NavigableSet<String> names) { - this.names = names; - this.cache = CacheBuilder.newBuilder().build( - new CacheLoader<String, CalciteSchema>() { - @SuppressWarnings("NullableProblems") - @Override public CalciteSchema load(String schemaName) { - final Schema subSchema = - calciteSchema.schema.getSubSchema(schemaName); - if (subSchema == null) { - throw new RuntimeException("sub-schema " + schemaName - + " not found"); - } - return new CalciteSchema(calciteSchema, subSchema, schemaName); - } - }); - } - } } // End CalciteSchema.java http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/Driver.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/Driver.java b/core/src/main/java/org/apache/calcite/jdbc/Driver.java index 3a29c92..2014e9f 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/Driver.java +++ b/core/src/main/java/org/apache/calcite/jdbc/Driver.java @@ -116,7 +116,7 @@ public class Driver extends UnregisteredDriver { } /** Creates an internal connection. */ - CalciteConnection connect(CalciteRootSchema rootSchema, + CalciteConnection connect(CalciteSchema rootSchema, JavaTypeFactory typeFactory) { return (CalciteConnection) ((CalciteFactory) factory) .newConnection(this, factory, CONNECT_STRING_PREFIX, new Properties(), http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java new file mode 100644 index 0000000..40a8870 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java @@ -0,0 +1,141 @@ +/* + * 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.calcite.jdbc; + +import org.apache.calcite.schema.Function; +import org.apache.calcite.schema.Schema; +import org.apache.calcite.schema.Table; +import org.apache.calcite.schema.TableMacro; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.ImmutableSortedSet; + +/** + * A concrete implementation of {@link org.apache.calcite.jdbc.CalciteSchema} + * that maintains minimal state. + */ +class SimpleCalciteSchema extends CalciteSchema { + /** Creates a CachingCalciteSchema. + * + * <p>Use {@link CalciteSchema#createRootSchema(boolean)} + * or {@link #add(String, Schema)}. */ + SimpleCalciteSchema(CalciteSchema parent, Schema schema, String name) { + super(parent, schema, name); + } + + public void setCache(boolean cache) { + throw new UnsupportedOperationException(); + } + + public CalciteSchema add(String name, Schema schema) { + final CalciteSchema calciteSchema = + new SimpleCalciteSchema(this, schema, name); + subSchemaMap.put(name, calciteSchema); + return calciteSchema; + } + + protected CalciteSchema getImplicitSubSchema(String schemaName, + boolean caseSensitive) { + // Check implicit schemas. + Schema s = schema.getSubSchema(schemaName); + if (s != null) { + return new SimpleCalciteSchema(this, s, schemaName); + } + return null; + } + + protected TableEntry getImplicitTable(String tableName, + boolean caseSensitive) { + // Check implicit tables. + Table table = schema.getTable(tableName); + if (table != null) { + return tableEntry(tableName, table); + } + return null; + } + + protected void addImplicitSubSchemaToBuilder( + ImmutableSortedMap.Builder<String, CalciteSchema> builder) { + ImmutableSortedMap<String, CalciteSchema> explicitSubSchemas = builder.build(); + for (String schemaName : schema.getSubSchemaNames()) { + if (explicitSubSchemas.containsKey(schemaName)) { + // explicit subschema wins. + continue; + } + Schema s = schema.getSubSchema(schemaName); + if (s != null) { + CalciteSchema calciteSchema = new SimpleCalciteSchema(this, s, schemaName); + builder.put(schemaName, calciteSchema); + } + } + } + + protected void addImplicitTableToBuilder(ImmutableSortedSet.Builder<String> builder) { + builder.addAll(schema.getTableNames()); + } + + protected void addImplicitFunctionToBuilder(ImmutableList.Builder<Function> builder) { + for (String functionName : schema.getFunctionNames()) { + builder.addAll(schema.getFunctions(functionName)); + } + } + + protected void addImplicitFuncNamesToBuilder(ImmutableSortedSet.Builder<String> builder) { + builder.addAll(schema.getFunctionNames()); + } + + protected void addImplicitTablesBasedOnNullaryFunctionsToBuilder( + ImmutableSortedMap.Builder<String, Table> builder) { + ImmutableSortedMap<String, Table> explicitTables = builder.build(); + + for (String s : schema.getFunctionNames()) { + // explicit table wins. + if (explicitTables.containsKey(s)) { + continue; + } + for (Function function : schema.getFunctions(s)) { + if (function instanceof TableMacro + && function.getParameters().isEmpty()) { + final Table table = ((TableMacro) function).apply(ImmutableList.of()); + builder.put(s, table); + } + } + } + } + + protected TableEntry getImplicitTableBasedOnNullaryFunction(String tableName, + boolean caseSensitive) { + for (String s : schema.getFunctionNames()) { + for (Function function : schema.getFunctions(s)) { + if (function instanceof TableMacro + && function.getParameters().isEmpty()) { + final Table table = ((TableMacro) function).apply(ImmutableList.of()); + return tableEntry(tableName, table); + } + } + } + return null; + } + + protected boolean isCacheEnabled() { + return false; + } + +} + +// End SimpleCalciteSchema.java http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/materialize/Lattice.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/materialize/Lattice.java b/core/src/main/java/org/apache/calcite/materialize/Lattice.java index ee7fef6..cc11625 100644 --- a/core/src/main/java/org/apache/calcite/materialize/Lattice.java +++ b/core/src/main/java/org/apache/calcite/materialize/Lattice.java @@ -18,7 +18,6 @@ package org.apache.calcite.materialize; import org.apache.calcite.avatica.AvaticaUtils; import org.apache.calcite.jdbc.CalcitePrepare; -import org.apache.calcite.jdbc.CalciteRootSchema; import org.apache.calcite.jdbc.CalciteSchema; import org.apache.calcite.plan.RelOptUtil; import org.apache.calcite.prepare.CalcitePrepareImpl; @@ -86,7 +85,7 @@ public class Lattice { } }; - public final CalciteRootSchema rootSchema; + public final CalciteSchema rootSchema; public final ImmutableList<Node> nodes; public final ImmutableList<Column> columns; public final boolean auto; @@ -112,7 +111,7 @@ public class Lattice { } }; - private Lattice(CalciteRootSchema rootSchema, ImmutableList<Node> nodes, + private Lattice(CalciteSchema rootSchema, ImmutableList<Node> nodes, boolean auto, boolean algorithm, long algorithmMaxMillis, LatticeStatisticProvider statisticProvider, Double rowCountEstimate, ImmutableList<Column> columns, ImmutableList<Measure> defaultMeasures, @@ -568,7 +567,7 @@ public class Lattice { ImmutableList.builder(); private final ImmutableList.Builder<Tile> tileListBuilder = ImmutableList.builder(); - private final CalciteRootSchema rootSchema; + private final CalciteSchema rootSchema; private boolean algorithm = false; private long algorithmMaxMillis = -1; private boolean auto = true; @@ -576,7 +575,8 @@ public class Lattice { private String statisticProvider; public Builder(CalciteSchema schema, String sql) { - this.rootSchema = schema.root(); + this.rootSchema = Preconditions.checkNotNull(schema.root()); + Preconditions.checkArgument(rootSchema.isRoot(), "must be root schema"); CalcitePrepare.ConvertResult parsed = Schemas.convert(MaterializedViewTable.MATERIALIZATION_CONNECTION, schema, schema.path(null), sql); @@ -695,6 +695,7 @@ public class Lattice { ? AvaticaUtils.instantiatePlugin(LatticeStatisticProvider.class, this.statisticProvider) : Lattices.CACHED_SQL; + Preconditions.checkArgument(rootSchema.isRoot(), "must be root schema"); return new Lattice(rootSchema, ImmutableList.copyOf(nodes), auto, algorithm, algorithmMaxMillis, statisticProvider, rowCountEstimate, columns, defaultMeasureListBuilder.build(), tileListBuilder.build()); http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java index ede840d..f70a08b 100644 --- a/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java +++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java @@ -16,10 +16,10 @@ */ package org.apache.calcite.materialize; -import org.apache.calcite.jdbc.CalciteRootSchema; import org.apache.calcite.jdbc.CalciteSchema; import org.apache.calcite.rel.type.RelDataType; +import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; @@ -50,7 +50,7 @@ class MaterializationActor { * same results as executing the query. */ static class Materialization { final MaterializationKey key; - final CalciteRootSchema rootSchema; + final CalciteSchema rootSchema; CalciteSchema.TableEntry materializedTable; final String sql; final RelDataType rowType; @@ -67,12 +67,13 @@ class MaterializationActor { * @param rowType Row type */ Materialization(MaterializationKey key, - CalciteRootSchema rootSchema, + CalciteSchema rootSchema, CalciteSchema.TableEntry materializedTable, String sql, RelDataType rowType) { this.key = key; - this.rootSchema = rootSchema; + this.rootSchema = Preconditions.checkNotNull(rootSchema); + Preconditions.checkArgument(rootSchema.isRoot(), "must be root schema"); this.materializedTable = materializedTable; // may be null this.sql = sql; this.rowType = rowType; http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/schema/Schemas.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/schema/Schemas.java b/core/src/main/java/org/apache/calcite/schema/Schemas.java index 639e852..6c8ab1d 100644 --- a/core/src/main/java/org/apache/calcite/schema/Schemas.java +++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java @@ -23,7 +23,6 @@ import org.apache.calcite.config.CalciteConnectionConfigImpl; import org.apache.calcite.config.CalciteConnectionProperty; import org.apache.calcite.jdbc.CalciteConnection; import org.apache.calcite.jdbc.CalcitePrepare; -import org.apache.calcite.jdbc.CalciteRootSchema; import org.apache.calcite.jdbc.CalciteSchema; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.QueryProvider; @@ -389,7 +388,7 @@ public final class Schemas { return typeFactory; } - public CalciteRootSchema getRootSchema() { + public CalciteSchema getRootSchema() { return schema.root(); } http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/main/java/org/apache/calcite/tools/Frameworks.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/tools/Frameworks.java b/core/src/main/java/org/apache/calcite/tools/Frameworks.java index f3ebe12..dffac61 100644 --- a/core/src/main/java/org/apache/calcite/tools/Frameworks.java +++ b/core/src/main/java/org/apache/calcite/tools/Frameworks.java @@ -76,7 +76,6 @@ public class Frameworks { * statement. */ public abstract static class PrepareAction<R> { private final FrameworkConfig config; - public PrepareAction() { this.config = newConfigBuilder() // .defaultSchema(Frameworks.createRootSchema(true)).build(); http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/core/src/test/java/org/apache/calcite/test/JdbcTest.java ---------------------------------------------------------------------- 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 3c0c77c..65d024c 100644 --- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java +++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java @@ -6436,6 +6436,57 @@ public class JdbcTest { } } + @Test public void testExplicitImplicitSchemaSameName() throws Exception { + final SchemaPlus rootSchema = CalciteSchema.createRootSchema(false).plus(); + + // create schema "/a" + final Map<String, Schema> aSubSchemaMap = new HashMap<>(); + final SchemaPlus aSchema = rootSchema.add("a", + new AbstractSchema() { + @Override protected Map<String, Schema> getSubSchemaMap() { + return aSubSchemaMap; + } + }); + + // add explicit schema "/a/b". + aSchema.add("b", new AbstractSchema()); + + // add implicit schema "/a/b" + aSubSchemaMap.put("b", new AbstractSchema()); + + aSchema.setCacheEnabled(true); + + // explicit should win implicit. + assertThat(aSchema.getSubSchemaNames().size(), is(1)); + } + + @Test public void testSimpleCalciteSchema() throws Exception { + final SchemaPlus rootSchema = CalciteSchema.createRootSchema(false, false).plus(); + + // create schema "/a" + final Map<String, Schema> aSubSchemaMap = new HashMap<>(); + final SchemaPlus aSchema = rootSchema.add("a", + new AbstractSchema() { + @Override protected Map<String, Schema> getSubSchemaMap() { + return aSubSchemaMap; + } + }); + + // add explicit schema "/a/b". + aSchema.add("b", new AbstractSchema()); + + // add implicit schema "/a/c" + aSubSchemaMap.put("c", new AbstractSchema()); + + assertThat(aSchema.getSubSchema("c"), notNullValue()); + assertThat(aSchema.getSubSchema("b"), notNullValue()); + + // add implicit schema "/a/b" + aSubSchemaMap.put("b", new AbstractSchema()); + // explicit should win implicit. + assertThat(aSchema.getSubSchemaNames().size(), is(2)); + } + @Test public void testSchemaCaching() throws Exception { final Connection connection = CalciteAssert.that(CalciteAssert.Config.JDBC_FOODMART).connect(); http://git-wip-us.apache.org/repos/asf/calcite/blob/ac8d04ed/site/_docs/howto.md ---------------------------------------------------------------------- diff --git a/site/_docs/howto.md b/site/_docs/howto.md index af33cdd..aff04b2 100644 --- a/site/_docs/howto.md +++ b/site/_docs/howto.md @@ -318,7 +318,7 @@ New adapters can be created by implementing `CalcitePrepare.Context`: {% highlight java %} import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.jdbc.CalcitePrepare; -import org.apache.calcite.jdbc.CalciteRootSchema; +import org.apache.calcite.jdbc.CalciteSchema; public class AdapterContext implements CalcitePrepare.Context { @Override @@ -328,7 +328,7 @@ public class AdapterContext implements CalcitePrepare.Context { } @Override - public CalciteRootSchema getRootSchema() { + public CalciteSchema getRootSchema() { // adapter implementation return rootSchema; }
