Skip to content

Commit f67b532

Browse files
committed
[CALCITE-6728] Changes due to the PR review
1 parent f95b084 commit f67b532

19 files changed

+129
-53
lines changed

core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java

+3-10
Original file line numberDiff line numberDiff line change
@@ -297,21 +297,14 @@ private JdbcTable jdbcTableMapper(MetaImpl.MetaTable tableDef) {
297297

298298
private static MetaImpl.MetaTable metaDataMapper(ResultSet resultSet) {
299299
try {
300-
return new MetaImpl.MetaTable(intern(resultSet.getString(1)), intern(resultSet.getString(2)),
301-
intern(resultSet.getString(3)),
302-
intern(resultSet.getString(4)));
300+
return new MetaImpl.MetaTable(resultSet.getString(1), resultSet.getString(2),
301+
resultSet.getString(3),
302+
resultSet.getString(4));
303303
} catch (SQLException e) {
304304
throw new RuntimeException(e);
305305
}
306306
}
307307

308-
private static @Nullable String intern(@Nullable String string) {
309-
if (string == null) {
310-
return null;
311-
}
312-
return string.intern();
313-
}
314-
315308
private static TableType getTableType(String tableTypeName) {
316309
// Clean up table type. In particular, this ensures that 'SYSTEM TABLE',
317310
// returned by Phoenix among others, maps to TableType.SYSTEM_TABLE.

core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
import org.apache.calcite.schema.SchemaVersion;
2323
import org.apache.calcite.schema.Table;
2424
import org.apache.calcite.schema.TableMacro;
25-
import org.apache.calcite.schema.lookup.CachedLookup;
2625
import org.apache.calcite.schema.lookup.Lookup;
26+
import org.apache.calcite.schema.lookup.SnapshotLookup;
2727
import org.apache.calcite.util.NameMap;
2828
import org.apache.calcite.util.NameMultimap;
2929
import org.apache.calcite.util.NameSet;
@@ -45,7 +45,7 @@
4545
* functions and sub-schemas.
4646
*/
4747
class CachingCalciteSchema extends CalciteSchema {
48-
private final ConcurrentLinkedDeque<CachedLookup<?>> caches = new ConcurrentLinkedDeque<>();
48+
private final ConcurrentLinkedDeque<SnapshotLookup<?>> caches = new ConcurrentLinkedDeque<>();
4949
private final Cached<NameSet> implicitFunctionCache;
5050
private final Cached<NameSet> implicitTypeCache;
5151

@@ -104,10 +104,10 @@ private CachingCalciteSchema(@Nullable CalciteSchema parent, Schema schema,
104104
return new CachingCalciteSchema(this, schema, name);
105105
}
106106

107-
@Override protected <S> Lookup<S> decorateLookup(Lookup<S> lookup) {
108-
CachedLookup<S> cachedLookup = new CachedLookup<>(lookup);
109-
caches.add(cachedLookup);
110-
return cachedLookup;
107+
@Override protected <S> Lookup<S> enhanceLookup(Lookup<S> lookup) {
108+
SnapshotLookup<S> snapshotLookup = new SnapshotLookup<>(lookup);
109+
caches.add(snapshotLookup);
110+
return snapshotLookup;
111111
}
112112

113113
/** Adds a child schema of this schema. */
@@ -231,7 +231,7 @@ private CachingCalciteSchema(@Nullable CalciteSchema parent, Schema schema,
231231
}
232232

233233
private void enableCaches(final boolean cache) {
234-
for (CachedLookup<?> lookupCache : caches) {
234+
for (SnapshotLookup<?> lookupCache : caches) {
235235
lookupCache.enable(cache);
236236
}
237237
}

core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -119,19 +119,19 @@ public Lookup<TableEntry> tables() {
119119
return this.tables.getOrCompute(() ->
120120
Lookup.concat(
121121
Lookup.of(this.tableMap),
122-
decorateLookup(schema.tables().map((s, n) -> tableEntry(n, s)))));
122+
enhanceLookup(schema.tables().map((s, n) -> tableEntry(n, s)))));
123123

124124
}
125125

126126
public Lookup<CalciteSchema> subSchemas() {
127127
return subSchemas.getOrCompute(() ->
128128
Lookup.concat(
129129
Lookup.of(this.subSchemaMap),
130-
decorateLookup(schema.subSchemas().map((s, n) -> createSubSchema(s, n)))));
130+
enhanceLookup(schema.subSchemas().map((s, n) -> createSubSchema(s, n)))));
131131
}
132132

133-
/** The derived class is able to decorate the lookup. */
134-
protected <S> Lookup<S> decorateLookup(Lookup<S> lookup) {
133+
/** The derived class is able to enhance the lookup e.g. by introducing a cache. */
134+
protected <S> Lookup<S> enhanceLookup(Lookup<S> lookup) {
135135
return lookup;
136136
}
137137

@@ -338,8 +338,8 @@ public final Set<String> getTableNames() {
338338
return getTableNames(LikePattern.any());
339339
}
340340

341-
/** Returns the set of filtered table names. Includes implicit and explicit tables
342-
* and functions with zero parameters. */
341+
/** Returns the set of table names filtered by the given pattern.
342+
* Includes implicit and explicit tables and functions with zero parameters. */
343343
public final Set<String> getTableNames(LikePattern pattern) {
344344
return tables().getNames(pattern);
345345
}

core/src/main/java/org/apache/calcite/schema/Schema.java

+11
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ default Lookup<? extends Schema> subSchemas() {
8383
*
8484
* <p>Please use {@link Schema#tables()} and {@link Lookup#get(String)} instead.
8585
*
86+
* <p>Using `getTable` directly does not allow to distinguish between
87+
* casesensitive and caseinsensitive lookups. This method always does a
88+
* casesensitive lookup. Caseinsensitive lookup can be done by loading
89+
* all table names using {@link Schema#getTableNames()}. This can be
90+
* quite timeconsuming for huge databases. To speed this up,
91+
* all table names must be cached. This will require
92+
* a huge amount of additional memory.
93+
*
8694
* @param name Table name
8795
* @return Table, or null
8896
*/
@@ -133,6 +141,9 @@ default Lookup<? extends Schema> subSchemas() {
133141
*
134142
* <p>Please use {@link Schema#subSchemas()} and {@link Lookup#get(String)} instead.
135143
*
144+
* <p>See also comment for {@link Schema#getTable(String)} to find out why
145+
* you should do so.
146+
*
136147
* @param name Sub-schema name
137148
* @return Sub-schema with a given name, or null
138149
*/

core/src/main/java/org/apache/calcite/schema/lookup/CompatibilityLookup.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,14 @@
2626
import java.util.stream.Collectors;
2727

2828
/**
29-
* This class can be used to wrap existing schemas with a pair of {@code get...}
30-
* and {@code get...Names} into a Lookup object.
29+
* This class can be used to implement the methods {@code Schema.tables()}
30+
* and {@code Schema.subSchemas()} of existing schemas.
31+
*
32+
* <p>Existing schema classes are implementing a pair of {@code getTable()}
33+
* and {@code getTableNames()} methods. But these schemas should
34+
* also provide a {@code tables()} method. This class can be used
35+
* to implement this method. See {@code Schema.tables()} for
36+
* an example.
3137
*
3238
* @param <T> Element type
3339
*/
@@ -36,6 +42,12 @@ public class CompatibilityLookup<T> extends IgnoreCaseLookup<T> {
3642
private final Function<String, @Nullable T> get;
3743
private final Supplier<Set<String>> getNames;
3844

45+
/**
46+
* Constructor.
47+
*
48+
* @param get a function to lookup tables or sub schemas by name
49+
* @param getNames a function to list all tables or sub schemas
50+
*/
3951
public CompatibilityLookup(Function<String, @Nullable T> get, Supplier<Set<String>> getNames) {
4052
this.get = get;
4153
this.getNames = getNames;

core/src/main/java/org/apache/calcite/schema/lookup/ConcatLookup.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
import java.util.stream.Stream;
2424

2525
/**
26-
* This class can be used to concat a list of lookups.
26+
* This class can be used to concat a list of lookups into a new lookup object.
27+
*
28+
* <p>The lookup is done from left to right. The first match is returned
29+
* if a name can be found in two or more lookups.
2730
*
2831
* @param <T> Element type
2932
*/

core/src/main/java/org/apache/calcite/schema/lookup/EmptyLookup.java

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
/**
2626
* This class implements an empty Lookup.
2727
*
28+
* <p>This class returns null for any call to {@code EmptyLookup.get(String)} or
29+
* {@code EmptyLookup.getIgnoreCase(String)}.
30+
*
2831
* @param <T> Element type
2932
*/
3033
class EmptyLookup<T> implements Lookup<T> {

core/src/main/java/org/apache/calcite/schema/lookup/IgnoreCaseLookup.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,18 @@
2525
import java.util.Set;
2626

2727
/**
28-
* An abstract base class for lookups. implementing case insensitive lookup
28+
* An abstract base class for lookups implementing caseinsensitive lookup.
2929
*
3030
* @param <T> Element type
3131
*/
3232
public abstract class IgnoreCaseLookup<T> implements Lookup<T> {
3333

34+
/**
35+
* This member is used to lazily load the list of all names into memory.
36+
*
37+
* <p>A {@link NameMap} is used, which is capable to lookup names in a
38+
* caseinsensitive way.
39+
*/
3440
private LazyReference<NameMap<String>> nameMap = new LazyReference<>();
3541

3642
/**
@@ -57,6 +63,9 @@ public abstract class IgnoreCaseLookup<T> implements Lookup<T> {
5763
T result = get(entry.getValue());
5864
return result == null ? null : new Named<>(entry.getKey(), result);
5965
}
66+
// if the name was not found in the cached list of names,
67+
// we try to reload the cache once because the table/schema
68+
// might have been created in the meantime.
6069
retryCounter++;
6170
if (retryCounter > 1) {
6271
return null;

core/src/main/java/org/apache/calcite/schema/lookup/LikePattern.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@
2121
import java.util.regex.Pattern;
2222

2323
/**
24-
* This class is used as parameter to Lookup.getNames
24+
* This class is used to hold a pattern, which is typically
25+
* used in SQL LIKE statements.
26+
*
27+
* <p>The pattern can contain wildcards (`%`) or character ranges (`[a-z]`).
28+
*
29+
* <p>The pattern can also be translated to a {@code Predicate1<String>} which
30+
* can be used to do filtering inside java.
2531
*/
2632
public class LikePattern {
2733
private static final String ANY = "%";
@@ -56,7 +62,7 @@ public static Predicate1<String> matcher(String likePattern) {
5662

5763
/**
5864
* Converts a LIKE-style pattern (where '%' represents a wild-card, escaped
59-
* using '\') to a Java regex.
65+
* using '\') to a Java regex. It's always casesensitive.
6066
*/
6167
public static Pattern likeToRegex(String pattern) {
6268
StringBuilder buf = new StringBuilder("^");

core/src/main/java/org/apache/calcite/schema/lookup/LoadingCacheLookup.java

+17-4
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,23 @@
2323

2424
import org.checkerframework.checker.nullness.qual.Nullable;
2525

26+
import java.time.Duration;
2627
import java.util.Set;
2728
import java.util.concurrent.ExecutionException;
2829
import java.util.concurrent.TimeUnit;
2930

3031
import static java.util.Objects.requireNonNull;
3132

3233
/**
33-
* This class can be used to cache lookups.
34+
* This class is using a {@code LoadingCache} to speed up lookups,
35+
* delegated to another {@link Lookup} instance.
36+
*
37+
* <p>This class is thread safe. All entries are evicted after one minute.
38+
* Negative matches are never cached. If a new entry
39+
* becomes available in the associated {@code Lookup}, it's immediately
40+
* visible outside. If an entry is deleted in the associated {@code Lookup},
41+
* it takes one minute until it disappears if it was cached in the last minute.
42+
* Otherwise, it disappears immediately.
3443
*
3544
* @param <T> Element Type
3645
*/
@@ -40,16 +49,20 @@ public class LoadingCacheLookup<T> implements Lookup<T> {
4049
private final LoadingCache<String, T> cache;
4150
private final LoadingCache<String, Named<T>> cacheIgnoreCase;
4251

43-
public LoadingCacheLookup(Lookup<T> delegate) {
52+
public LoadingCacheLookup(Lookup<T> delegate, Duration expiration) {
4453
this.delegate = delegate;
4554
this.cache = CacheBuilder.newBuilder()
46-
.expireAfterWrite(1, TimeUnit.MINUTES)
55+
.expireAfterWrite(expiration.toMillis(), TimeUnit.MILLISECONDS)
4756
.build(CacheLoader.from(name -> requireNonNull(delegate.get(name))));
4857
this.cacheIgnoreCase = CacheBuilder.newBuilder()
49-
.expireAfterWrite(1, TimeUnit.MINUTES)
58+
.expireAfterWrite(expiration.toMillis(), TimeUnit.MILLISECONDS)
5059
.build(CacheLoader.from(name -> requireNonNull(delegate.getIgnoreCase(name))));
5160
}
5261

62+
public LoadingCacheLookup(Lookup<T> delegate) {
63+
this(delegate, Duration.ofMinutes(1));
64+
}
65+
5366
@Override public @Nullable T get(String name) {
5467
try {
5568
return cache.get(name);

core/src/main/java/org/apache/calcite/schema/lookup/Lookup.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import java.util.function.BiFunction;
2525

2626
/**
27-
* A casesensitive/insensitive lookup for tables, schems, functions ...
27+
* A casesensitive/insensitive lookup for tables, schemas, functions, types ...
2828
*
2929
* @param <T> Element type
3030
*/
@@ -47,13 +47,16 @@ public interface Lookup<T> {
4747

4848
/**
4949
* Returns the names of the entities in matching pattern.
50+
* The search is always casesensitive. This is caused by the fact that
51+
* {@code DatabaseMetaData.getTables(...)} doesn't support caseinsensitive
52+
* lookups.
5053
*
5154
* @return Names of the entities
5255
*/
5356
Set<String> getNames(LikePattern pattern);
5457

5558
default <S> Lookup<S> map(BiFunction<T, String, S> mapper) {
56-
return new MappedLookup<>(this, mapper);
59+
return new TransformingLookup<>(this, mapper);
5760
}
5861

5962
/**

core/src/main/java/org/apache/calcite/schema/lookup/CachedLookup.java core/src/main/java/org/apache/calcite/schema/lookup/SnapshotLookup.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@
2828
*
2929
* @param <T> Element Type
3030
*/
31-
public class CachedLookup<T> implements Lookup<T> {
31+
public class SnapshotLookup<T> implements Lookup<T> {
3232

3333
private final Lookup<T> delegate;
3434
private LazyReference<Lookup<T>> cachedDelegate = new LazyReference<>();
3535
private boolean enabled = true;
3636

37-
public CachedLookup(Lookup<T> delegate) {
37+
public SnapshotLookup(Lookup<T> delegate) {
3838
this.delegate = delegate;
3939
}
4040

core/src/main/java/org/apache/calcite/schema/lookup/MappedLookup.java core/src/main/java/org/apache/calcite/schema/lookup/TransformingLookup.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,25 @@
2727
* @param <S> Source element type
2828
* @param <T> Target element type
2929
*/
30-
class MappedLookup<S, T> implements Lookup<T> {
30+
class TransformingLookup<S, T> implements Lookup<T> {
3131
private final Lookup<S> lookup;
32-
private final BiFunction<S, String, T> mapper;
32+
private final BiFunction<S, String, T> transform;
3333

34-
MappedLookup(Lookup<S> lookup, BiFunction<S, String, T> mapper) {
34+
TransformingLookup(Lookup<S> lookup, BiFunction<S, String, T> transform) {
3535
this.lookup = lookup;
36-
this.mapper = mapper;
36+
this.transform = transform;
3737
}
3838

3939
@Override public @Nullable T get(String name) {
4040
S entity = lookup.get(name);
41-
return entity == null ? null : mapper.apply(entity, name);
41+
return entity == null ? null : transform.apply(entity, name);
4242
}
4343

4444
@Override public @Nullable Named<T> getIgnoreCase(String name) {
4545
Named<S> named = lookup.getIgnoreCase(name);
4646
return named == null
4747
? null
48-
: new Named<>(named.name(), mapper.apply(named.entity(), named.name()));
48+
: new Named<>(named.name(), transform.apply(named.entity(), named.name()));
4949
}
5050

5151
@Override public Set<String> getNames(LikePattern pattern) {

core/src/main/java/org/apache/calcite/util/LazyReference.java

+13
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ public class LazyReference<T> {
2828

2929
private final AtomicReference<T> value = new AtomicReference<>();
3030

31+
/**
32+
* Atomically sets the value to {@code supplier.get()}
33+
* if the current value was not set yet.
34+
*
35+
* <p>This method is reentrant. Different threads will
36+
* get the same result.
37+
*
38+
* @param supplier supplier for the new value
39+
* @return the current value.
40+
*/
3141
public T getOrCompute(Supplier<T> supplier) {
3242
while (true) {
3343
T result = value.get();
@@ -41,6 +51,9 @@ public T getOrCompute(Supplier<T> supplier) {
4151
}
4252
}
4353

54+
/**
55+
* Resets the current value.
56+
*/
4457
public void reset() {
4558
value.set((T) null);
4659
}

0 commit comments

Comments
 (0)