You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2018/02/16 21:51:12 UTC
[1/7] calcite git commit: Clean up SqlTypeAssignmentRules
Repository: calcite
Updated Branches:
refs/heads/master 0ced3b7f5 -> 707f4de9c
Clean up SqlTypeAssignmentRules
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/becb6dfb
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/becb6dfb
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/becb6dfb
Branch: refs/heads/master
Commit: becb6dfb85fad583d75aeaba13ac71d03bb5d4a8
Parents: fd68f25
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jan 8 19:58:41 2018 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Feb 16 10:18:01 2018 -0800
----------------------------------------------------------------------
.../sql/type/SqlTypeAssignmentRules.java | 464 ++++++++++---------
.../apache/calcite/sql/type/SqlTypeUtil.java | 4 +-
.../org/apache/calcite/test/RexProgramTest.java | 17 +-
3 files changed, 259 insertions(+), 226 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/becb6dfb/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
index cd46c39..038ead3 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
@@ -16,80 +16,96 @@
*/
package org.apache.calcite.sql.type;
+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.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nonnull;
/**
- * Class to hold rules to determine if a type is assignable from another type.
- *
- * <p>REVIEW 7/05/04 Wael: We should split this up in Cast rules, symmetric and
- * asymmetric assignable rules
+ * Rules that determine whether a type is assignable from another type.
*/
public class SqlTypeAssignmentRules {
//~ Static fields/initializers ---------------------------------------------
- private static SqlTypeAssignmentRules instance = null;
+ private static final SqlTypeAssignmentRules INSTANCE;
+ private static final SqlTypeAssignmentRules COERCE_INSTANCE;
- private final Map<SqlTypeName, Set<SqlTypeName>> rules;
- private final Map<SqlTypeName, Set<SqlTypeName>> coerceRules;
+ private final Map<SqlTypeName, ImmutableSet<SqlTypeName>> map;
//~ Constructors -----------------------------------------------------------
- private SqlTypeAssignmentRules() {
- rules = new HashMap<>();
+ private SqlTypeAssignmentRules(
+ Map<SqlTypeName, ImmutableSet<SqlTypeName>> map) {
+ this.map = ImmutableMap.copyOf(map);
+ }
+
+ static {
+ final Builder rules = new Builder();
- Set<SqlTypeName> rule;
+ final Set<SqlTypeName> rule = new HashSet<>();
// IntervalYearMonth is assignable from...
for (SqlTypeName interval : SqlTypeName.YEAR_INTERVAL_TYPES) {
- rules.put(interval, SqlTypeName.YEAR_INTERVAL_TYPES);
+ rules.add(interval, SqlTypeName.YEAR_INTERVAL_TYPES);
}
for (SqlTypeName interval : SqlTypeName.DAY_INTERVAL_TYPES) {
- rules.put(interval, SqlTypeName.DAY_INTERVAL_TYPES);
+ rules.add(interval, SqlTypeName.DAY_INTERVAL_TYPES);
+ }
+ for (SqlTypeName interval : SqlTypeName.DAY_INTERVAL_TYPES) {
+ final Set<SqlTypeName> dayIntervalTypes = SqlTypeName.DAY_INTERVAL_TYPES;
+ rules.add(interval, dayIntervalTypes);
}
- // Multiset is assignable from...
- rules.put(SqlTypeName.MULTISET, EnumSet.of(SqlTypeName.MULTISET));
+ // MULTISET is assignable from...
+ rules.add(SqlTypeName.MULTISET, EnumSet.of(SqlTypeName.MULTISET));
- // Tinyint is assignable from...
- rules.put(SqlTypeName.TINYINT, EnumSet.of(SqlTypeName.TINYINT));
+ // TINYINT is assignable from...
+ rules.add(SqlTypeName.TINYINT, EnumSet.of(SqlTypeName.TINYINT));
- // Smallint is assignable from...
- rule = new HashSet<>();
+ // SMALLINT is assignable from...
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
- rules.put(SqlTypeName.SMALLINT, rule);
+ rules.add(SqlTypeName.SMALLINT, rule);
- // Int is assignable from...
- rule = new HashSet<>();
+ // INTEGER is assignable from...
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
rule.add(SqlTypeName.INTEGER);
- rules.put(SqlTypeName.INTEGER, rule);
+ rules.add(SqlTypeName.INTEGER, rule);
- // BigInt is assignable from...
- rule = new HashSet<>();
+ // BIGINT is assignable from...
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
rule.add(SqlTypeName.INTEGER);
rule.add(SqlTypeName.BIGINT);
- rules.put(SqlTypeName.BIGINT, rule);
+ rules.add(SqlTypeName.BIGINT, rule);
- // Float is assignable from...
- rule = new HashSet<>();
+ // FLOAT (up to 64 bit floating point) is assignable from...
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
rule.add(SqlTypeName.INTEGER);
rule.add(SqlTypeName.BIGINT);
rule.add(SqlTypeName.DECIMAL);
rule.add(SqlTypeName.FLOAT);
- rules.put(SqlTypeName.FLOAT, rule);
+ rules.add(SqlTypeName.FLOAT, rule);
- // Real is assignable from...
- rule = new HashSet<>();
+ // REAL (32 bit floating point) is assignable from...
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
rule.add(SqlTypeName.INTEGER);
@@ -97,10 +113,10 @@ public class SqlTypeAssignmentRules {
rule.add(SqlTypeName.DECIMAL);
rule.add(SqlTypeName.FLOAT);
rule.add(SqlTypeName.REAL);
- rules.put(SqlTypeName.REAL, rule);
+ rules.add(SqlTypeName.REAL, rule);
- // Double is assignable from...
- rule = new HashSet<>();
+ // DOUBLE is assignable from...
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
rule.add(SqlTypeName.INTEGER);
@@ -109,10 +125,10 @@ public class SqlTypeAssignmentRules {
rule.add(SqlTypeName.FLOAT);
rule.add(SqlTypeName.REAL);
rule.add(SqlTypeName.DOUBLE);
- rules.put(SqlTypeName.DOUBLE, rule);
+ rules.add(SqlTypeName.DOUBLE, rule);
- // Decimal is assignable from...
- rule = new HashSet<>();
+ // DECIMAL is assignable from...
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
rule.add(SqlTypeName.INTEGER);
@@ -120,63 +136,63 @@ public class SqlTypeAssignmentRules {
rule.add(SqlTypeName.REAL);
rule.add(SqlTypeName.DOUBLE);
rule.add(SqlTypeName.DECIMAL);
- rules.put(SqlTypeName.DECIMAL, rule);
+ rules.add(SqlTypeName.DECIMAL, rule);
- // VarBinary is assignable from...
- rule = new HashSet<>();
+ // VARBINARY is assignable from...
+ rule.clear();
rule.add(SqlTypeName.VARBINARY);
rule.add(SqlTypeName.BINARY);
- rules.put(SqlTypeName.VARBINARY, rule);
+ rules.add(SqlTypeName.VARBINARY, rule);
- // Char is assignable from...
- rules.put(SqlTypeName.CHAR, EnumSet.of(SqlTypeName.CHAR));
+ // CHAR is assignable from...
+ rules.add(SqlTypeName.CHAR, EnumSet.of(SqlTypeName.CHAR));
- // VarChar is assignable from...
- rule = new HashSet<>();
+ // VARCHAR is assignable from...
+ rule.clear();
rule.add(SqlTypeName.CHAR);
rule.add(SqlTypeName.VARCHAR);
- rules.put(SqlTypeName.VARCHAR, rule);
+ rules.add(SqlTypeName.VARCHAR, rule);
- // Boolean is assignable from...
- rules.put(SqlTypeName.BOOLEAN, EnumSet.of(SqlTypeName.BOOLEAN));
+ // BOOLEAN is assignable from...
+ rules.add(SqlTypeName.BOOLEAN, EnumSet.of(SqlTypeName.BOOLEAN));
- // Binary is assignable from...
- rule = new HashSet<>();
+ // BINARY is assignable from...
+ rule.clear();
rule.add(SqlTypeName.BINARY);
rule.add(SqlTypeName.VARBINARY);
- rules.put(SqlTypeName.BINARY, rule);
+ rules.add(SqlTypeName.BINARY, rule);
- // Date is assignable from ...
- rule = new HashSet<>();
+ // DATE is assignable from...
+ rule.clear();
rule.add(SqlTypeName.DATE);
rule.add(SqlTypeName.TIMESTAMP);
- rules.put(SqlTypeName.DATE, rule);
+ rules.add(SqlTypeName.DATE, rule);
- // Time is assignable from ...
- rule = new HashSet<>();
+ // TIME is assignable from...
+ rule.clear();
rule.add(SqlTypeName.TIME);
rule.add(SqlTypeName.TIMESTAMP);
- rules.put(SqlTypeName.TIME, rule);
+ rules.add(SqlTypeName.TIME, rule);
- // Time with local time-zone is assignable from ...
- rules.put(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE,
+ // TIME WITH LOCAL TIME ZONE is assignable from...
+ rules.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE,
EnumSet.of(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE));
- // Timestamp is assignable from ...
- rules.put(SqlTypeName.TIMESTAMP, EnumSet.of(SqlTypeName.TIMESTAMP));
+ // TIMESTAMP is assignable from ...
+ rules.add(SqlTypeName.TIMESTAMP, EnumSet.of(SqlTypeName.TIMESTAMP));
- // Timestamp with local time-zone is assignable from ...
- rules.put(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE,
+ // TIMESTAMP WITH LOCAL TIME ZONE is assignable from...
+ rules.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE,
EnumSet.of(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE));
- // Geometry is assignable from ...
- rules.put(SqlTypeName.GEOMETRY, EnumSet.of(SqlTypeName.GEOMETRY));
+ // GEOMETRY is assignable from ...
+ rules.add(SqlTypeName.GEOMETRY, EnumSet.of(SqlTypeName.GEOMETRY));
- // Array is assignable from ...
- rules.put(SqlTypeName.ARRAY, EnumSet.of(SqlTypeName.ARRAY));
+ // ARRAY is assignable from ...
+ rules.add(SqlTypeName.ARRAY, EnumSet.of(SqlTypeName.ARRAY));
- // Any is assignable from ...
- rule = new HashSet<>();
+ // ANY is assignable from ...
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
rule.add(SqlTypeName.INTEGER);
@@ -187,14 +203,14 @@ public class SqlTypeAssignmentRules {
rule.add(SqlTypeName.TIME);
rule.add(SqlTypeName.DATE);
rule.add(SqlTypeName.TIMESTAMP);
- rules.put(SqlTypeName.ANY, rule);
+ rules.add(SqlTypeName.ANY, rule);
// we use coerceRules when we're casting
- coerceRules = copy(rules);
+ final Builder coerceRules = new Builder(rules);
- // Make numbers symmetrical and
- // make varchar/char castable to/from numbers
- rule = new HashSet<>();
+ // Make numbers symmetrical,
+ // and make VARCHAR and CHAR castable to/from numbers
+ rule.clear();
rule.add(SqlTypeName.TINYINT);
rule.add(SqlTypeName.SMALLINT);
rule.add(SqlTypeName.INTEGER);
@@ -207,148 +223,156 @@ public class SqlTypeAssignmentRules {
rule.add(SqlTypeName.CHAR);
rule.add(SqlTypeName.VARCHAR);
- coerceRules.put(
- SqlTypeName.TINYINT,
- copy(rule));
- coerceRules.put(
- SqlTypeName.SMALLINT,
- copy(rule));
- coerceRules.put(
- SqlTypeName.INTEGER,
- copy(rule));
- coerceRules.put(
- SqlTypeName.BIGINT,
- copy(rule));
- coerceRules.put(
- SqlTypeName.FLOAT,
- copy(rule));
- coerceRules.put(
- SqlTypeName.REAL,
- copy(rule));
- coerceRules.put(
- SqlTypeName.DECIMAL,
- copy(rule));
- coerceRules.put(
- SqlTypeName.DOUBLE,
- copy(rule));
- coerceRules.put(
- SqlTypeName.CHAR,
- copy(rule));
- coerceRules.put(
- SqlTypeName.VARCHAR,
- copy(rule));
-
- // Exact Numerics are castable from intervals
+ coerceRules.add(SqlTypeName.TINYINT, rule);
+ coerceRules.add(SqlTypeName.SMALLINT, rule);
+ coerceRules.add(SqlTypeName.INTEGER, rule);
+ coerceRules.add(SqlTypeName.BIGINT, rule);
+ coerceRules.add(SqlTypeName.FLOAT, rule);
+ coerceRules.add(SqlTypeName.REAL, rule);
+ coerceRules.add(SqlTypeName.DECIMAL, rule);
+ coerceRules.add(SqlTypeName.DOUBLE, rule);
+ coerceRules.add(SqlTypeName.CHAR, rule);
+ coerceRules.add(SqlTypeName.VARCHAR, rule);
+
+ // Exact numeric types are castable from intervals
for (SqlTypeName exactType : SqlTypeName.EXACT_TYPES) {
- rule = coerceRules.get(exactType);
- rule.addAll(SqlTypeName.INTERVAL_TYPES);
+ coerceRules.add(exactType,
+ coerceRules.copyValues(exactType)
+ .addAll(SqlTypeName.INTERVAL_TYPES)
+ .build());
}
- // intervals are castable from Exact Numeric
+ // Intervals are castable from exact numeric
for (SqlTypeName typeName : SqlTypeName.INTERVAL_TYPES) {
- rule = coerceRules.get(typeName);
- rule.add(SqlTypeName.TINYINT);
- rule.add(SqlTypeName.SMALLINT);
- rule.add(SqlTypeName.INTEGER);
- rule.add(SqlTypeName.BIGINT);
- rule.add(SqlTypeName.DECIMAL);
- rule.add(SqlTypeName.VARCHAR);
+ coerceRules.add(typeName,
+ coerceRules.copyValues(typeName)
+ .add(SqlTypeName.TINYINT)
+ .add(SqlTypeName.SMALLINT)
+ .add(SqlTypeName.INTEGER)
+ .add(SqlTypeName.BIGINT)
+ .add(SqlTypeName.DECIMAL)
+ .add(SqlTypeName.VARCHAR)
+ .build());
}
- // varchar is castable from Boolean, Date, time, timestamp, numbers and
+ // VARCHAR is castable from BOOLEAN, DATE, TIMESTAMP, numeric types and
// intervals
- rule = coerceRules.get(SqlTypeName.VARCHAR);
- rule.add(SqlTypeName.BOOLEAN);
- rule.add(SqlTypeName.DATE);
- rule.add(SqlTypeName.TIME);
- rule.add(SqlTypeName.TIMESTAMP);
- rule.addAll(SqlTypeName.INTERVAL_TYPES);
-
- // char is castable from Boolean, Date, time and timestamp and numbers
- rule = coerceRules.get(SqlTypeName.CHAR);
- rule.add(SqlTypeName.BOOLEAN);
- rule.add(SqlTypeName.DATE);
- rule.add(SqlTypeName.TIME);
- rule.add(SqlTypeName.TIMESTAMP);
- rule.addAll(SqlTypeName.INTERVAL_TYPES);
-
- // Boolean is castable from char and varchar
- rule = coerceRules.get(SqlTypeName.BOOLEAN);
- rule.add(SqlTypeName.CHAR);
- rule.add(SqlTypeName.VARCHAR);
-
- // Date, time, and timestamp are castable from
- // char and varchar
- // Date is castable from ...
- rule = new HashSet<>();
- rule.add(SqlTypeName.DATE);
- rule.add(SqlTypeName.TIMESTAMP);
- rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.CHAR);
- rule.add(SqlTypeName.VARCHAR);
- coerceRules.put(SqlTypeName.DATE, rule);
-
- // Time is castable from ...
- rule = new HashSet<>();
- rule.add(SqlTypeName.TIME);
- rule.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.TIMESTAMP);
- rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.CHAR);
- rule.add(SqlTypeName.VARCHAR);
- coerceRules.put(SqlTypeName.TIME, rule);
-
- // Time with local time-zone is castable from ...
- rule = new HashSet<>();
- rule.add(SqlTypeName.TIME);
- rule.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.TIMESTAMP);
- rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.CHAR);
- rule.add(SqlTypeName.VARCHAR);
- coerceRules.put(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE, rule);
-
- // Timestamp is castable from ...
- rule = new HashSet<>();
- rule.add(SqlTypeName.TIMESTAMP);
- rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.DATE);
- rule.add(SqlTypeName.TIME);
- rule.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.CHAR);
- rule.add(SqlTypeName.VARCHAR);
- coerceRules.put(SqlTypeName.TIMESTAMP, rule);
-
- // Timestamp with local time-zone is castable from ...
- rule = new HashSet<>();
- rule.add(SqlTypeName.TIMESTAMP);
- rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.DATE);
- rule.add(SqlTypeName.TIME);
- rule.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
- rule.add(SqlTypeName.CHAR);
- rule.add(SqlTypeName.VARCHAR);
- coerceRules.put(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE, rule);
+ coerceRules.add(SqlTypeName.VARCHAR,
+ coerceRules.copyValues(SqlTypeName.VARCHAR)
+ .add(SqlTypeName.BOOLEAN)
+ .add(SqlTypeName.DATE)
+ .add(SqlTypeName.TIME)
+ .add(SqlTypeName.TIMESTAMP)
+ .addAll(SqlTypeName.INTERVAL_TYPES)
+ .build());
+
+ // CHAR is castable from BOOLEAN, DATE, TIME, TIMESTAMP and numeric types
+ coerceRules.add(SqlTypeName.CHAR,
+ coerceRules.copyValues(SqlTypeName.CHAR)
+ .add(SqlTypeName.BOOLEAN)
+ .add(SqlTypeName.DATE)
+ .add(SqlTypeName.TIME)
+ .add(SqlTypeName.TIMESTAMP)
+ .addAll(SqlTypeName.INTERVAL_TYPES)
+ .build());
+
+ // BOOLEAN is castable from CHAR and VARCHAR
+ coerceRules.add(SqlTypeName.BOOLEAN,
+ coerceRules.copyValues(SqlTypeName.BOOLEAN)
+ .add(SqlTypeName.CHAR)
+ .add(SqlTypeName.VARCHAR)
+ .build());
+
+ // DATE, TIME, and TIMESTAMP are castable from
+ // CHAR and VARCHAR.
+
+ // DATE is castable from...
+ coerceRules.add(SqlTypeName.DATE,
+ coerceRules.copyValues(SqlTypeName.DATE)
+ .add(SqlTypeName.DATE)
+ .add(SqlTypeName.TIMESTAMP)
+ .add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.CHAR)
+ .add(SqlTypeName.VARCHAR)
+ .build());
+
+ // TIME is castable from...
+ coerceRules.add(SqlTypeName.TIME,
+ coerceRules.copyValues(SqlTypeName.TIME)
+ .add(SqlTypeName.TIME)
+ .add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.TIMESTAMP)
+ .add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.CHAR)
+ .add(SqlTypeName.VARCHAR)
+ .build());
+
+ // TIME WITH LOCAL TIME ZONE is castable from...
+ coerceRules.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE,
+ coerceRules.copyValues(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.TIME)
+ .add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.TIMESTAMP)
+ .add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.CHAR)
+ .add(SqlTypeName.VARCHAR)
+ .build());
+
+ // TIMESTAMP is castable from...
+ coerceRules.add(SqlTypeName.TIMESTAMP,
+ coerceRules.copyValues(SqlTypeName.TIMESTAMP)
+ .add(SqlTypeName.TIMESTAMP)
+ .add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.DATE)
+ .add(SqlTypeName.TIME)
+ .add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.CHAR)
+ .add(SqlTypeName.VARCHAR)
+ .build());
+
+ // TIMESTAMP WITH LOCAL TIME ZONE is castable from...
+ coerceRules.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE,
+ coerceRules.copyValues(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.TIMESTAMP)
+ .add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.DATE)
+ .add(SqlTypeName.TIME)
+ .add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE)
+ .add(SqlTypeName.CHAR)
+ .add(SqlTypeName.VARCHAR)
+ .build());
+
+ INSTANCE = new SqlTypeAssignmentRules(rules.map);
+ COERCE_INSTANCE = new SqlTypeAssignmentRules(coerceRules.map);
}
//~ Methods ----------------------------------------------------------------
+ /** Returns an instance that does not coerce. */
public static synchronized SqlTypeAssignmentRules instance() {
- if (instance == null) {
- instance = new SqlTypeAssignmentRules();
- }
- return instance;
+ return instance(false);
+ }
+
+ /** Returns an instance. */
+ public static synchronized SqlTypeAssignmentRules instance(boolean coerce) {
+ return coerce ? COERCE_INSTANCE : INSTANCE;
}
+ @Deprecated
public boolean canCastFrom(
SqlTypeName to,
SqlTypeName from,
boolean coerce) {
- assert to != null;
- assert from != null;
+ return instance(coerce).canCastFrom(to, from);
+ }
- Map<SqlTypeName, Set<SqlTypeName>> ruleset =
- coerce ? coerceRules : rules;
+ /** Returns whether it is valid to cast a value of from type {@code from} to
+ * type {@code to}. */
+ public boolean canCastFrom(
+ SqlTypeName to,
+ SqlTypeName from) {
+ Preconditions.checkNotNull(to);
+ Preconditions.checkNotNull(from);
if (to == SqlTypeName.NULL) {
return false;
@@ -356,7 +380,7 @@ public class SqlTypeAssignmentRules {
return true;
}
- final Set<SqlTypeName> rule = ruleset.get(to);
+ final Set<SqlTypeName> rule = map.get(to);
if (rule == null) {
// if you hit this assert, see the constructor of this class on how
// to add new rule
@@ -366,21 +390,43 @@ public class SqlTypeAssignmentRules {
return rule.contains(from);
}
- @SuppressWarnings("unchecked")
- private static <K, V> Map<K, V> copy(Map<K, V> map) {
- Map<K, V> copy = new HashMap<>();
- for (Map.Entry<K, V> e : map.entrySet()) {
- if (e.getValue() instanceof Set) {
- copy.put(e.getKey(), (V) copy((Set) e.getValue()));
- } else {
- copy.put(e.getKey(), e.getValue());
+
+ /** Keeps state while maps are building build. */
+ private static class Builder {
+ final Map<SqlTypeName, ImmutableSet<SqlTypeName>> map;
+ final LoadingCache<Set<SqlTypeName>, ImmutableSet<SqlTypeName>> sets;
+
+ /** Creates an empty Builder. */
+ Builder() {
+ this.map = new HashMap<>();
+ this.sets =
+ CacheBuilder.newBuilder().build(
+ new CacheLoader<Set<SqlTypeName>, ImmutableSet<SqlTypeName>>() {
+ public ImmutableSet<SqlTypeName> load(
+ @Nonnull Set<SqlTypeName> key) {
+ return Sets.immutableEnumSet(key);
+ }
+ });
+ }
+
+ /** Creates a Builder as a copy of another Builder. */
+ Builder(Builder builder) {
+ this.map = new HashMap<>(builder.map);
+ this.sets = builder.sets; // share the same canonical sets
+ }
+
+ void add(SqlTypeName fromType, Set<SqlTypeName> toTypes) {
+ try {
+ map.put(fromType, sets.get(toTypes));
+ } catch (ExecutionException e) {
+ throw new RuntimeException("populating SqlTypeAssignmentRules", e);
}
}
- return copy;
- }
- private static <T> HashSet<T> copy(Set<T> set) {
- return new HashSet<T>(set);
+ ImmutableSet.Builder<SqlTypeName> copyValues(SqlTypeName typeName) {
+ return ImmutableSet.<SqlTypeName>builder()
+ .addAll(map.get(typeName));
+ }
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/becb6dfb/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
index 9113dd8..c8fbe03 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
@@ -859,8 +859,8 @@ public abstract class SqlTypeUtil {
// where internally a cast across character repertoires is OK. Should
// probably clean that up.
- SqlTypeAssignmentRules rules = SqlTypeAssignmentRules.instance();
- return rules.canCastFrom(toTypeName, fromTypeName, coerce);
+ SqlTypeAssignmentRules rules = SqlTypeAssignmentRules.instance(coerce);
+ return rules.canCastFrom(toTypeName, fromTypeName);
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/becb6dfb/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
index 9501959..94eb792 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -69,7 +69,6 @@ import org.junit.Test;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
@@ -1597,8 +1596,8 @@ public class RexProgramTest {
for (RelDataType fromType : types) {
for (RelDataType toType : types) {
- if (SqlTypeAssignmentRules.instance().canCastFrom(
- toType.getSqlTypeName(), fromType.getSqlTypeName(), false)) {
+ if (SqlTypeAssignmentRules.instance(false)
+ .canCastFrom(toType.getSqlTypeName(), fromType.getSqlTypeName())) {
for (RexLiteral literal : map.get(fromType.getSqlTypeName())) {
final RexNode cast = rexBuilder.makeCast(toType, literal);
if (cast instanceof RexLiteral) {
@@ -1824,17 +1823,6 @@ public class RexProgramTest {
RexUtil.retainDeterministic(RelOptUtil.conjunctions(n)).size());
}
- private Calendar cal(int y, int m, int d, int h, int mm, int s) {
- final Calendar c = Util.calendar();
- c.set(Calendar.YEAR, y);
- c.set(Calendar.MONTH, m);
- c.set(Calendar.DAY_OF_MONTH, d);
- c.set(Calendar.HOUR_OF_DAY, h);
- c.set(Calendar.MINUTE, mm);
- c.set(Calendar.SECOND, s);
- return c;
- }
-
@Test public void testConstantMap() {
final RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER);
final RelDataType rowType = typeFactory.builder()
@@ -1865,7 +1853,6 @@ public class RexProgramTest {
// Contradictory constraints yield no constants
final RexNode ref0 = rexBuilder.makeInputRef(rowType, 0);
- final RexNode ref1 = rexBuilder.makeInputRef(rowType, 1);
final ImmutableMap<RexNode, RexNode> map2 =
RexUtil.predicateConstants(RexNode.class, rexBuilder,
ImmutableList.of(eq(ref0, literal1),
[7/7] calcite git commit: [CALCITE-2059] Apache Geode Adapter
(Christian Tzolov)
Posted by jh...@apache.org.
[CALCITE-2059] Apache Geode Adapter (Christian Tzolov)
- Downgrade Geode from 1.4.0 to 1.3.0 - Geode server allows connections
only from clients with same or lower version
- Add links to presentations and tutorials
Close apache/calcite#581
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/707f4de9
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/707f4de9
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/707f4de9
Branch: refs/heads/master
Commit: 707f4de9cafc474d0daf807b1e4c339f6eb42d7e
Parents: 3c67a60
Author: Christian Tzolov <ch...@gmail.com>
Authored: Thu Nov 3 06:30:04 2016 +0100
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Feb 16 10:18:02 2018 -0800
----------------------------------------------------------------------
geode/README.md | 2 +
geode/pom.xml | 189 ++++++++
.../adapter/geode/rel/GeodeAggregate.java | 135 ++++++
.../adapter/geode/rel/GeodeEnumerator.java | 93 ++++
.../calcite/adapter/geode/rel/GeodeFilter.java | 238 ++++++++++
.../calcite/adapter/geode/rel/GeodeProject.java | 75 +++
.../calcite/adapter/geode/rel/GeodeRel.java | 122 +++++
.../calcite/adapter/geode/rel/GeodeRules.java | 370 +++++++++++++++
.../calcite/adapter/geode/rel/GeodeSchema.java | 88 ++++
.../adapter/geode/rel/GeodeSchemaFactory.java | 69 +++
.../calcite/adapter/geode/rel/GeodeSort.java | 106 +++++
.../calcite/adapter/geode/rel/GeodeTable.java | 256 ++++++++++
.../adapter/geode/rel/GeodeTableScan.java | 80 ++++
.../geode/rel/GeodeToEnumerableConverter.java | 164 +++++++
.../rel/GeodeToEnumerableConverterRule.java | 43 ++
.../calcite/adapter/geode/rel/package-info.java | 26 ++
.../geode/simple/GeodeSimpleEnumerator.java | 76 +++
.../geode/simple/GeodeSimpleScannableTable.java | 75 +++
.../adapter/geode/simple/GeodeSimpleSchema.java | 84 ++++
.../geode/simple/GeodeSimpleSchemaFactory.java | 53 +++
.../adapter/geode/simple/package-info.java | 26 ++
.../calcite/adapter/geode/util/GeodeUtils.java | 278 +++++++++++
.../geode/util/JavaTypeFactoryExtImpl.java | 123 +++++
.../adapter/geode/util/package-info.java | 26 ++
.../adapter/geode/rel/BaseGeodeAdapterIT.java | 168 +++++++
.../geode/rel/GeodeAdapterBookshopIT.java | 468 +++++++++++++++++++
.../adapter/geode/rel/GeodeAdapterIT.java | 99 ++++
.../calcite/adapter/geode/rel/GeodeZipsIT.java | 199 ++++++++
.../geode/rel/RelationalJdbcExample.java | 103 ++++
.../geode/simple/BookMasterRegionTest.java | 57 +++
.../adapter/geode/simple/SimpleJdbcExample.java | 95 ++++
.../src/test/resources/model-bookshop-all.json | 35 ++
geode/src/test/resources/model-bookshop.json | 35 ++
.../resources/model-geode-pg-federation.json | 54 +++
.../src/test/resources/model-with-classes.json | 39 ++
geode/src/test/resources/model-zips.json | 47 ++
geode/src/test/resources/model.json | 35 ++
geode/src/test/resources/model2.json | 35 ++
pom.xml | 7 +
site/_docs/adapter.md | 1 +
site/_docs/geode_adapter.md | 180 +++++++
sqlline | 2 +-
sqlline.bat | 2 +-
43 files changed, 4456 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/README.md
----------------------------------------------------------------------
diff --git a/geode/README.md b/geode/README.md
new file mode 100644
index 0000000..852e471
--- /dev/null
+++ b/geode/README.md
@@ -0,0 +1,2 @@
+##Apache Geode SQL/JBC Adapter
+
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/pom.xml
----------------------------------------------------------------------
diff --git a/geode/pom.xml b/geode/pom.xml
new file mode 100644
index 0000000..36c75ef
--- /dev/null
+++ b/geode/pom.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.calcite</groupId>
+ <artifactId>calcite</artifactId>
+ <version>1.16.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>calcite-geode</artifactId>
+ <packaging>jar</packaging>
+ <version>1.16.0-SNAPSHOT</version>
+ <name>Calcite Geode</name>
+ <description>Geode adapter for Calcite</description>
+
+ <properties>
+ <top.dir>${project.basedir}/..</top.dir>
+ </properties>
+
+ <dependencies>
+ <!-- Sorted by groupId, artifactId; calcite dependencies first. Put versions
+ in dependencyManagement in the root POM, not here. -->
+ <dependency>
+ <groupId>org.apache.calcite</groupId>
+ <artifactId>calcite-core</artifactId>
+ <type>jar</type>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.calcite</groupId>
+ <artifactId>calcite-core</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.calcite</groupId>
+ <artifactId>calcite-linq4j</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.geode</groupId>
+ <artifactId>geode-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>uberjdbc</id>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.geode</groupId>
+ <artifactId>geode-core</artifactId>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.4.3</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <filters>
+ <filter>
+ <artifact>*:*</artifact>
+ <excludes>
+ <exclude>META-INF/*.SF</exclude>
+ <exclude>META-INF/*.DSA</exclude>
+ <exclude>META-INF/*.RSA</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ <createDependencyReducedPom>false</createDependencyReducedPom>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <build>
+ <plugins>
+ <!-- Sorted by groupId, artifactId. Put versions in pluginManagement in
+ the root POM, not here. -->
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>${maven-dependency-plugin.version}</version>
+ <executions>
+ <execution>
+ <id>analyze</id>
+ <goals>
+ <goal>analyze-only</goal>
+ </goals>
+ <configuration>
+ <failOnWarning>true</failOnWarning>
+ <!-- ignore "unused but declared" warnings -->
+ <ignoredUnusedDeclaredDependencies>
+ <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-api</ignoredUnusedDeclaredDependency>
+ <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-log4j12</ignoredUnusedDeclaredDependency>
+ </ignoredUnusedDeclaredDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ </plugin>
+ <!-- Parent module has the same plugin and does the work of generating
+ -sources.jar for each project. But without the plugin declared here, IDEs
+ don't know the sources are available. -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>jar-no-fork</goal>
+ <goal>test-jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeAggregate.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeAggregate.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeAggregate.java
new file mode 100644
index 0000000..faab698
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeAggregate.java
@@ -0,0 +1,135 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Aggregate;
+import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.Util;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of
+ * {@link org.apache.calcite.rel.core.Aggregate} relational expression
+ * in Geode.
+ */
+public class GeodeAggregate extends Aggregate implements GeodeRel {
+
+ /** Creates a GeodeAggregate. */
+ public GeodeAggregate(RelOptCluster cluster,
+ RelTraitSet traitSet,
+ RelNode input,
+ boolean indicator,
+ ImmutableBitSet groupSet,
+ List<ImmutableBitSet> groupSets,
+ List<AggregateCall> aggCalls) {
+ super(cluster, traitSet, input, indicator, groupSet, groupSets, aggCalls);
+
+ assert getConvention() == GeodeRel.CONVENTION;
+ assert getConvention() == this.input.getConvention();
+ assert getConvention() == input.getConvention();
+ assert this.groupSets.size() == 1 : "Grouping sets not supported";
+
+ for (AggregateCall aggCall : aggCalls) {
+ if (aggCall.isDistinct()) {
+ System.out.println("DISTINCT based aggregation!");
+ }
+ }
+ }
+
+ @Override public Aggregate copy(RelTraitSet traitSet, RelNode input, boolean indicator,
+ ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets,
+ List<AggregateCall> aggCalls) {
+ return new GeodeAggregate(getCluster(), traitSet, input, indicator, groupSet, groupSets,
+ aggCalls);
+ }
+
+ @Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
+ return super.computeSelfCost(planner, mq).multiplyBy(0.1);
+ }
+
+ @Override public void implement(GeodeImplementContext geodeImplementContext) {
+
+ ((GeodeRel) getInput()).implement(geodeImplementContext);
+
+ List<String> inputFields = fieldNames(getInput().getRowType());
+
+ List<String> groupByFields = new ArrayList<>();
+
+ // GROUP BY field == cardinality of 1, GROUP BY field1, field2 => cardinality of 2 ...
+ if (groupSet.cardinality() == 1) {
+ final String groupByFieldName = inputFields.get(groupSet.nth(0));
+ groupByFields.add(groupByFieldName);
+ } else {
+ for (int group : groupSet) {
+ groupByFields.add(inputFields.get(group));
+ }
+ }
+
+ geodeImplementContext.addGroupBy(groupByFields);
+
+ // Find the aggregate functions (e.g. MAX, SUM ...)
+ Builder<String, String> aggregateFunctionMap = ImmutableMap.builder();
+ for (AggregateCall aggCall : aggCalls) {
+
+ ArrayList<Object> aggCallFieldNames = new ArrayList<>();
+ for (int i : aggCall.getArgList()) {
+ aggCallFieldNames.add(inputFields.get(i));
+ }
+ String functionName = aggCall.getAggregation().getName();
+
+ // Workaround to handle count(*) case. Geode doesn't allow "AS" aliases on
+ // 'count(*)' but allows it for count('any column name'). So we are
+ // converting the count(*) into count (first input ColumnName).
+ if ("COUNT".equalsIgnoreCase(functionName) && aggCallFieldNames.isEmpty()) {
+ aggCallFieldNames.add(inputFields.get(0));
+ }
+
+ String oqlAggregateCall = Util.toString(aggCallFieldNames, " " + functionName + "(", ", ",
+ ")");
+
+ aggregateFunctionMap.put(aggCall.getName(), oqlAggregateCall);
+ }
+
+ geodeImplementContext.addAggregateFunctions(aggregateFunctionMap.build());
+
+ }
+
+ private List<String> fieldNames(RelDataType relDataType) {
+ ArrayList<String> names = new ArrayList<>();
+
+ for (RelDataTypeField rdtf : relDataType.getFieldList()) {
+ names.add(rdtf.getName());
+ }
+ return names;
+ }
+}
+
+// End GeodeAggregate.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeEnumerator.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeEnumerator.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeEnumerator.java
new file mode 100644
index 0000000..3325819
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeEnumerator.java
@@ -0,0 +1,93 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelDataTypeSystem;
+import org.apache.calcite.rel.type.RelProtoDataType;
+import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
+
+import org.apache.geode.cache.query.SelectResults;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.apache.calcite.adapter.geode.util.GeodeUtils.convertToRowValues;
+
+/**
+ * Enumerator that reads from a Geode Regions.
+ */
+class GeodeEnumerator implements Enumerator<Object> {
+
+ protected static final Logger LOGGER = LoggerFactory.getLogger(GeodeEnumerator.class.getName());
+
+ private Iterator iterator;
+ private Object current;
+ private List<RelDataTypeField> fieldTypes;
+
+ /**
+ * Creates a GeodeEnumerator.
+ *
+ * @param results Geode result set ({@link SelectResults})
+ * @param protoRowType The type of resulting rows
+ */
+ GeodeEnumerator(SelectResults results, RelProtoDataType protoRowType) {
+ if (results == null) {
+ LOGGER.warn("Null OQL results!");
+ }
+ this.iterator = (results == null) ? Collections.emptyIterator() : results.iterator();
+ this.current = null;
+
+ final RelDataTypeFactory typeFactory =
+ new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+ this.fieldTypes = protoRowType.apply(typeFactory).getFieldList();
+ }
+
+ /**
+ * Produces the next row from the results.
+ *
+ * @return A rel row from the results
+ */
+ @Override public Object current() {
+ return convertToRowValues(fieldTypes, current);
+ }
+
+ @Override public boolean moveNext() {
+ if (iterator.hasNext()) {
+ current = iterator.next();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override public void reset() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void close() {
+ // Nothing to do here
+ }
+}
+
+// End GeodeEnumerator.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeFilter.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeFilter.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeFilter.java
new file mode 100644
index 0000000..e4e5ac9
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeFilter.java
@@ -0,0 +1,238 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.Util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.apache.calcite.sql.type.SqlTypeName.CHAR;
+import static org.apache.calcite.sql.type.SqlTypeName.NUMERIC_TYPES;
+
+/**
+ * Implementation of
+ * {@link Filter} relational expression in Geode.
+ */
+public class GeodeFilter extends Filter implements GeodeRel {
+
+ private final String match;
+
+ public GeodeFilter(RelOptCluster cluster, RelTraitSet traitSet,
+ RelNode input, RexNode condition) {
+
+ super(cluster, traitSet, input, condition);
+
+ Translator translator = new Translator(getRowType());
+ this.match = translator.translateMatch(condition);
+
+ assert getConvention() == GeodeRel.CONVENTION;
+ assert getConvention() == input.getConvention();
+ }
+
+ @Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
+ return super.computeSelfCost(planner, mq).multiplyBy(0.1);
+ }
+
+ @Override public GeodeFilter copy(RelTraitSet traitSet, RelNode input, RexNode condition) {
+ return new GeodeFilter(getCluster(), traitSet, input, condition);
+ }
+
+ @Override public void implement(GeodeImplementContext geodeImplementContext) {
+ // first call the input down the tree.
+ ((GeodeRel) getInput()).implement(geodeImplementContext);
+ geodeImplementContext.addPredicates(Collections.singletonList(match));
+ }
+
+ /**
+ * Translates {@link RexNode} expressions into Geode expression strings.
+ */
+ static class Translator {
+ private final RelDataType rowType;
+
+ private final List<String> fieldNames;
+
+ Translator(RelDataType rowType) {
+ this.rowType = rowType;
+ this.fieldNames = GeodeRules.geodeFieldNames(rowType);
+ }
+
+ /**
+ * Converts the value of a literal to a string.
+ *
+ * @param literal Literal to translate
+ * @return String representation of the literal
+ */
+ private static String literalValue(RexLiteral literal) {
+ Object value = literal.getValue2();
+ StringBuilder buf = new StringBuilder();
+ buf.append(value);
+ return buf.toString();
+ }
+
+ /**
+ * Produce the OQL predicate string for the given condition.
+ *
+ * @param condition Condition to translate
+ * @return OQL predicate string
+ */
+ private String translateMatch(RexNode condition) {
+ // Returns condition decomposed by OR
+ List<RexNode> disjunctions = RelOptUtil.disjunctions(condition);
+ if (disjunctions.size() == 1) {
+ return translateAnd(disjunctions.get(0));
+ } else {
+ return translateOr(disjunctions);
+ }
+ }
+
+ /**
+ * Translate a conjunctive predicate to a OQL string.
+ *
+ * @param condition A conjunctive predicate
+ * @return OQL string for the predicate
+ */
+ private String translateAnd(RexNode condition) {
+ List<String> predicates = new ArrayList<String>();
+ for (RexNode node : RelOptUtil.conjunctions(condition)) {
+ predicates.add(translateMatch2(node));
+ }
+
+ return Util.toString(predicates, "", " AND ", "");
+ }
+
+ private String translateOr(List<RexNode> disjunctions) {
+ List<String> predicates = new ArrayList<String>();
+ for (RexNode node : disjunctions) {
+ if (RelOptUtil.conjunctions(node).size() > 1) {
+ predicates.add("(" + translateMatch(node) + ")");
+ } else {
+ predicates.add(translateMatch2(node));
+ }
+ }
+
+ return Util.toString(predicates, "", " OR ", "");
+ }
+
+ /**
+ * Translate a binary relation.
+ */
+ private String translateMatch2(RexNode node) {
+ // We currently only use equality, but inequalities on clustering keys
+ // should be possible in the future
+ switch (node.getKind()) {
+ case EQUALS:
+ return translateBinary("=", "=", (RexCall) node);
+ case LESS_THAN:
+ return translateBinary("<", ">", (RexCall) node);
+ case LESS_THAN_OR_EQUAL:
+ return translateBinary("<=", ">=", (RexCall) node);
+ case GREATER_THAN:
+ return translateBinary(">", "<", (RexCall) node);
+ case GREATER_THAN_OR_EQUAL:
+ return translateBinary(">=", "<=", (RexCall) node);
+ default:
+ throw new AssertionError("cannot translate " + node);
+ }
+ }
+
+ /**
+ * Translates a call to a binary operator, reversing arguments if
+ * necessary.
+ */
+ private String translateBinary(String op, String rop, RexCall call) {
+ final RexNode left = call.operands.get(0);
+ final RexNode right = call.operands.get(1);
+ String expression = translateBinary2(op, left, right);
+ if (expression != null) {
+ return expression;
+ }
+ expression = translateBinary2(rop, right, left);
+ if (expression != null) {
+ return expression;
+ }
+ throw new AssertionError("cannot translate op " + op + " call " + call);
+ }
+
+ /**
+ * Translates a call to a binary operator. Returns null on failure.
+ */
+ private String translateBinary2(String op, RexNode left, RexNode right) {
+ switch (right.getKind()) {
+ case LITERAL:
+ break;
+ default:
+ return null;
+ }
+
+ final RexLiteral rightLiteral = (RexLiteral) right;
+ switch (left.getKind()) {
+ case INPUT_REF:
+ final RexInputRef left1 = (RexInputRef) left;
+ String name = fieldNames.get(left1.getIndex());
+ return translateOp2(op, name, rightLiteral);
+ case CAST:
+ // FIXME This will not work in all cases (for example, we ignore string encoding)
+ return translateBinary2(op, ((RexCall) left).operands.get(0), right);
+ case OTHER_FUNCTION:
+ String item = left.accept(new GeodeRules.RexToGeodeTranslator(this.fieldNames));
+ return (item == null) ? null : item + " " + op + " " + quoteCharLiteral(rightLiteral);
+ default:
+ return null;
+ }
+ }
+
+ private String quoteCharLiteral(RexLiteral literal) {
+ String value = literalValue(literal);
+ if (literal.getTypeName() == CHAR) {
+ value = "'" + value + "'";
+ }
+ return value;
+ }
+
+ /**
+ * Combines a field name, operator, and literal to produce a predicate string.
+ */
+ private String translateOp2(String op, String name, RexLiteral right) {
+ String valueString = literalValue(right);
+ SqlTypeName typeName = rowType.getField(name, true, false).getType().getSqlTypeName();
+ if (NUMERIC_TYPES.contains(typeName)) {
+ // leave the value as it is
+ } else if (typeName != SqlTypeName.CHAR) {
+ valueString = "'" + valueString + "'";
+ }
+ return name + " " + op + " " + valueString;
+ }
+ }
+}
+
+// End GeodeFilter.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeProject.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeProject.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeProject.java
new file mode 100644
index 0000000..c8f328c
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeProject.java
@@ -0,0 +1,75 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.adapter.geode.rel.GeodeRules.RexToGeodeTranslator;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.util.Pair;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation of
+ * {@link Project}
+ * relational expression in Geode.
+ */
+public class GeodeProject extends Project implements GeodeRel {
+
+ public GeodeProject(RelOptCluster cluster, RelTraitSet traitSet,
+ RelNode input, List<? extends RexNode> projects, RelDataType rowType) {
+ super(cluster, traitSet, input, projects, rowType);
+ assert getConvention() == GeodeRel.CONVENTION;
+ assert getConvention() == input.getConvention();
+ }
+
+ @Override public Project copy(RelTraitSet traitSet, RelNode input,
+ List<RexNode> projects, RelDataType rowType) {
+ return new GeodeProject(getCluster(), traitSet, input, projects, rowType);
+ }
+
+ @Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) {
+ return super.computeSelfCost(planner, mq).multiplyBy(0.1);
+ }
+
+ @Override public void implement(GeodeImplementContext geodeImplementContext) {
+
+ ((GeodeRel) getInput()).implement(geodeImplementContext);
+
+ final RexToGeodeTranslator translator =
+ new RexToGeodeTranslator(
+ GeodeRules.geodeFieldNames(getInput().getRowType()));
+ final Map<String, String> fields = new LinkedHashMap<>();
+ for (Pair<RexNode, String> pair : getNamedProjects()) {
+ final String name = pair.right;
+ final String originalName = pair.left.accept(translator);
+ fields.put(originalName, name);
+ }
+ geodeImplementContext.addSelectFields(fields);
+ }
+}
+
+// End GeodeProject.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeRel.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeRel.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeRel.java
new file mode 100644
index 0000000..ebf1d0d
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeRel.java
@@ -0,0 +1,122 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.RelNode;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Relational expression that uses Geode calling convention.
+ */
+public interface GeodeRel extends RelNode {
+
+ /**
+ * Calling convention for relational operations that occur in Geode.
+ */
+ Convention CONVENTION = new Convention.Impl("GEODE", GeodeRel.class);
+
+ /**
+ * Callback for the implementation process that collects the context from the
+ * {@link GeodeRel} required to convert the relational tree into physical such.
+ *
+ * @param geodeImplementContext Context class that collects the feedback from the
+ * call back method calls
+ */
+ void implement(GeodeImplementContext geodeImplementContext);
+
+ /**
+ * Shared context used by the {@link GeodeRel} relations.
+ *
+ * <p>Callback context class for the implementation process that converts a
+ * tree of {@code GeodeRel} nodes into an OQL query.
+ */
+ class GeodeImplementContext {
+ final Map<String, String> selectFields = new LinkedHashMap<>();
+
+ final List<String> whereClause = new ArrayList<>();
+
+ final List<String> orderByFields = new ArrayList<>();
+
+ final List<String> groupByFields = new ArrayList<>();
+
+ final Map<String, String> oqlAggregateFunctions = new LinkedHashMap<>();
+
+ String limitValue = null;
+
+ RelOptTable table;
+
+ GeodeTable geodeTable;
+
+ /**
+ * Adds new projected fields.
+ *
+ * @param fields New fields to be projected from a query
+ */
+ public void addSelectFields(Map<String, String> fields) {
+ if (fields != null) {
+ selectFields.putAll(fields);
+ }
+ }
+
+ /**
+ * Adds new restricted predicates.
+ *
+ * @param predicates New predicates to be applied to the query
+ */
+ public void addPredicates(List<String> predicates) {
+ if (predicates != null) {
+ whereClause.addAll(predicates);
+ }
+ }
+
+ public void addOrderByFields(List<String> orderByFieldLists) {
+ orderByFields.addAll(orderByFieldLists);
+ }
+
+ public void setLimit(String limit) {
+ limitValue = limit;
+ }
+
+ public void addGroupBy(List<String> groupByFields) {
+ this.groupByFields.addAll(groupByFields);
+ }
+
+ public void addAggregateFunctions(Map<String, String> oqlAggregateFunctions) {
+ this.oqlAggregateFunctions.putAll(oqlAggregateFunctions);
+ }
+
+ @Override public String toString() {
+ return "GeodeImplementContext{"
+ + "selectFields=" + selectFields
+ + ", whereClause=" + whereClause
+ + ", orderByFields=" + orderByFields
+ + ", limitValue='" + limitValue + '\''
+ + ", groupByFields=" + groupByFields
+ + ", table=" + table
+ + ", geodeTable=" + geodeTable
+ + '}';
+ }
+ }
+}
+
+// End GeodeRel.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeRules.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeRules.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeRules.java
new file mode 100644
index 0000000..bfac3f0
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeRules.java
@@ -0,0 +1,370 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.ConverterRule;
+import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.logical.LogicalAggregate;
+import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
+
+import com.google.common.base.Predicate;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Rules and relational operators for {@link GeodeRel#CONVENTION} calling convention.
+ */
+public class GeodeRules {
+
+ public static final RelOptRule[] RULES = {
+ GeodeFilterRule.INSTANCE,
+ GeodeProjectRule.INSTANCE,
+ GeodeSortLimitRule.INSTANCE,
+ GeodeAggregateRule.INSTANCE
+ };
+
+ private GeodeRules() {
+ }
+
+ /**
+ * Returns 'string' if it is a call to item['string'], null otherwise.
+ */
+ static String isItem(RexCall call) {
+ if (call.getOperator() != SqlStdOperatorTable.ITEM) {
+ return null;
+ }
+ final RexNode op0 = call.getOperands().get(0);
+ final RexNode op1 = call.getOperands().get(1);
+
+ if (op0 instanceof RexInputRef
+ && ((RexInputRef) op0).getIndex() == 0
+ && op1 instanceof RexLiteral
+ && ((RexLiteral) op1).getValue2() instanceof String) {
+ return (String) ((RexLiteral) op1).getValue2();
+ }
+ return null;
+ }
+
+ static List<String> geodeFieldNames(final RelDataType rowType) {
+
+ List<String> fieldNames = new AbstractList<String>() {
+ @Override public String get(int index) {
+ return rowType.getFieldList().get(index).getName();
+ }
+
+ @Override public int size() {
+ return rowType.getFieldCount();
+ }
+ };
+
+ return SqlValidatorUtil.uniquify(fieldNames, true);
+ }
+
+ /**
+ * Translator from {@link RexNode} to strings in Geode's expression language.
+ */
+ static class RexToGeodeTranslator extends RexVisitorImpl<String> {
+
+ private final List<String> inFields;
+
+ protected RexToGeodeTranslator(List<String> inFields) {
+ super(true);
+ this.inFields = inFields;
+ }
+
+ @Override public String visitInputRef(RexInputRef inputRef) {
+ return inFields.get(inputRef.getIndex());
+ }
+
+ @Override public String visitCall(RexCall call) {
+ final List<String> strings = visitList(call.operands);
+ if (call.getOperator() == SqlStdOperatorTable.ITEM) {
+ final RexNode op1 = call.getOperands().get(1);
+ if (op1 instanceof RexLiteral) {
+ if (op1.getType().getSqlTypeName() == SqlTypeName.INTEGER) {
+ return stripQuotes(strings.get(0)) + "[" + ((RexLiteral) op1).getValue2() + "]";
+ } else if (op1.getType().getSqlTypeName() == SqlTypeName.CHAR) {
+ return stripQuotes(strings.get(0)) + "." + ((RexLiteral) op1).getValue2();
+ }
+ }
+ }
+
+ return super.visitCall(call);
+ }
+
+ private String stripQuotes(String s) {
+ return s.startsWith("'") && s.endsWith("'") ? s.substring(1, s.length() - 1) : s;
+ }
+
+ List<String> visitList(List<RexNode> list) {
+ final List<String> strings = new ArrayList<>();
+ for (RexNode node : list) {
+ strings.add(node.accept(this));
+ }
+ return strings;
+ }
+ }
+
+ /**
+ * Rule to convert a {@link LogicalProject} to a {@link GeodeProject}.
+ */
+ private static class GeodeProjectRule extends GeodeConverterRule {
+
+ private static final GeodeProjectRule INSTANCE = new GeodeProjectRule();
+
+ private GeodeProjectRule() {
+ super(LogicalProject.class, "GeodeProjectRule");
+ }
+
+ @Override public boolean matches(RelOptRuleCall call) {
+ LogicalProject project = call.rel(0);
+ for (RexNode e : project.getProjects()) {
+ if (e.getType().getSqlTypeName() == SqlTypeName.GEOMETRY) {
+ // For spatial Functions Drop to Calcite Enumerable
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override public RelNode convert(RelNode rel) {
+ final LogicalProject project = (LogicalProject) rel;
+ final RelTraitSet traitSet = project.getTraitSet().replace(out);
+ return new GeodeProject(
+ project.getCluster(),
+ traitSet,
+ convert(project.getInput(), out),
+ project.getProjects(),
+ project.getRowType());
+ }
+ }
+
+ /**
+ * Rule to convert {@link org.apache.calcite.rel.core.Aggregate} to a
+ * {@link GeodeAggregate}.
+ */
+ private static class GeodeAggregateRule extends GeodeConverterRule {
+
+ private static final GeodeAggregateRule INSTANCE = new GeodeAggregateRule();
+
+ GeodeAggregateRule() {
+ super(LogicalAggregate.class, "GeodeAggregateRule");
+ }
+
+ @Override public RelNode convert(RelNode rel) {
+ final LogicalAggregate aggregate = (LogicalAggregate) rel;
+ final RelTraitSet traitSet = aggregate.getTraitSet().replace(out);
+ return new GeodeAggregate(
+ aggregate.getCluster(),
+ traitSet,
+ convert(aggregate.getInput(), traitSet.simplify()),
+ aggregate.indicator,
+ aggregate.getGroupSet(),
+ aggregate.getGroupSets(),
+ aggregate.getAggCallList());
+ }
+ }
+
+ /**
+ * Rule to convert the Limit in {@link org.apache.calcite.rel.core.Sort} to a
+ * {@link GeodeSort}.
+ */
+ private static class GeodeSortLimitRule extends RelOptRule {
+
+ private static final GeodeSortLimitRule INSTANCE =
+ new GeodeSortLimitRule(
+ new Predicate<Sort>() {
+ public boolean apply(Sort input) {
+ // OQL doesn't support for offsets (e.g. LIMIT 10 OFFSET 500)
+ return input.offset == null;
+ }
+ });
+
+ GeodeSortLimitRule(Predicate<Sort> predicate) {
+ super(operand(Sort.class, null, predicate, any()), "GeodeSortLimitRule");
+ }
+
+ @Override public void onMatch(RelOptRuleCall call) {
+ final Sort sort = call.rel(0);
+
+ final RelTraitSet traitSet = sort.getTraitSet()
+ .replace(GeodeRel.CONVENTION)
+ .replace(sort.getCollation());
+
+ GeodeSort geodeSort = new GeodeSort(sort.getCluster(), traitSet,
+ convert(sort.getInput(), traitSet.replace(RelCollations.EMPTY)),
+ sort.getCollation(), sort.fetch);
+
+ call.transformTo(geodeSort);
+ }
+ }
+
+ /**
+ * Rule to convert a {@link LogicalFilter} to a
+ * {@link GeodeFilter}.
+ */
+ private static class GeodeFilterRule extends RelOptRule {
+
+ private static final GeodeFilterRule INSTANCE = new GeodeFilterRule();
+
+ private GeodeFilterRule() {
+ super(operand(LogicalFilter.class, operand(GeodeTableScan.class, none())),
+ "GeodeFilterRule");
+ }
+
+ @Override public boolean matches(RelOptRuleCall call) {
+ // Get the condition from the filter operation
+ LogicalFilter filter = call.rel(0);
+ RexNode condition = filter.getCondition();
+
+ List<String> fieldNames = GeodeRules.geodeFieldNames(filter.getInput().getRowType());
+
+ List<RexNode> disjunctions = RelOptUtil.disjunctions(condition);
+ if (disjunctions.size() != 1) {
+ return true;
+ } else {
+ // Check that all conjunctions are primary field conditions.
+ condition = disjunctions.get(0);
+ for (RexNode predicate : RelOptUtil.conjunctions(condition)) {
+ if (!isEqualityOnKey(predicate, fieldNames)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if the node is a supported predicate (primary field condition).
+ *
+ * @param node Condition node to check
+ * @param fieldNames Names of all columns in the table
+ * @return True if the node represents an equality predicate on a primary key
+ */
+ private boolean isEqualityOnKey(RexNode node, List<String> fieldNames) {
+
+ RexCall call = (RexCall) node;
+ final RexNode left = call.operands.get(0);
+ final RexNode right = call.operands.get(1);
+
+ if (checkConditionContainsInputRefOrLiterals(left, right, fieldNames)) {
+ return true;
+ }
+ return checkConditionContainsInputRefOrLiterals(right, left, fieldNames);
+
+ }
+
+ /**
+ * Checks whether a condition contains input refs of literals.
+ *
+ * @param left Left operand of the equality
+ * @param right Right operand of the equality
+ * @param fieldNames Names of all columns in the table
+ * @return Whether condition is supported
+ */
+ private boolean checkConditionContainsInputRefOrLiterals(RexNode left,
+ RexNode right, List<String> fieldNames) {
+ // FIXME Ignore casts for rel and assume they aren't really necessary
+ if (left.isA(SqlKind.CAST)) {
+ left = ((RexCall) left).getOperands().get(0);
+ }
+
+ if (right.isA(SqlKind.CAST)) {
+ right = ((RexCall) right).getOperands().get(0);
+ }
+
+ if (left.isA(SqlKind.INPUT_REF) && right.isA(SqlKind.LITERAL)) {
+ final RexInputRef left1 = (RexInputRef) left;
+ String name = fieldNames.get(left1.getIndex());
+ return name != null;
+ } else if (left.isA(SqlKind.INPUT_REF) && right.isA(SqlKind.INPUT_REF)) {
+
+ final RexInputRef left1 = (RexInputRef) left;
+ String leftName = fieldNames.get(left1.getIndex());
+
+ final RexInputRef right1 = (RexInputRef) right;
+ String rightName = fieldNames.get(right1.getIndex());
+
+ return (leftName != null) && (rightName != null);
+ }
+ if (left.isA(SqlKind.OTHER_FUNCTION) && right.isA(SqlKind.LITERAL)) {
+ if (((RexCall) left).getOperator() != SqlStdOperatorTable.ITEM) {
+ return false;
+ }
+ // Should be ITEM
+ return true;
+ }
+
+ return false;
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ LogicalFilter filter = call.rel(0);
+ GeodeTableScan scan = call.rel(1);
+ if (filter.getTraitSet().contains(Convention.NONE)) {
+ final RelNode converted = convert(filter, scan);
+ call.transformTo(converted);
+ }
+ }
+
+ private RelNode convert(LogicalFilter filter, GeodeTableScan scan) {
+ final RelTraitSet traitSet = filter.getTraitSet().replace(GeodeRel.CONVENTION);
+ return new GeodeFilter(
+ filter.getCluster(),
+ traitSet,
+ convert(filter.getInput(), GeodeRel.CONVENTION),
+ filter.getCondition());
+ }
+ }
+
+ /**
+ * Base class for planner rules that convert a relational
+ * expression to Geode calling convention.
+ */
+ abstract static class GeodeConverterRule extends ConverterRule {
+ protected final Convention out;
+
+ GeodeConverterRule(Class<? extends RelNode> clazz, String description) {
+ super(clazz, Convention.NONE, GeodeRel.CONVENTION, description);
+ this.out = GeodeRel.CONVENTION;
+ }
+ }
+}
+
+// End GeodeRules.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSchema.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSchema.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSchema.java
new file mode 100644
index 0000000..2e38741
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSchema.java
@@ -0,0 +1,88 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.adapter.geode.util.GeodeUtils;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.impl.AbstractSchema;
+import org.apache.calcite.util.trace.CalciteTrace;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.slf4j.Logger;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import static org.apache.calcite.adapter.geode.util.GeodeUtils.createClientCache;
+import static org.apache.calcite.adapter.geode.util.GeodeUtils.createRelDataType;
+
+/**
+ * Schema mapped onto a Geode Region.
+ */
+public class GeodeSchema extends AbstractSchema {
+
+ protected static final Logger LOGGER = CalciteTrace.getPlannerTracer();
+
+ final ClientCache clientCache;
+ private final SchemaPlus parentSchema;
+ private String[] regionNames;
+ private ImmutableMap<String, Table> tableMap;
+
+ public GeodeSchema(String locatorHost, int locatorPort,
+ String[] regionNames, String pdxAutoSerializerPackageExp,
+ SchemaPlus parentSchema) {
+ super();
+ this.regionNames = regionNames;
+ this.parentSchema = parentSchema;
+
+ this.clientCache = createClientCache(locatorHost, locatorPort,
+ pdxAutoSerializerPackageExp, true);
+ }
+
+ @Override protected Map<String, Table> getTableMap() {
+
+ if (tableMap == null) {
+
+ final ImmutableMap.Builder<String, Table> builder = ImmutableMap.builder();
+
+ // Extract the first entity of each Regions and use it to build a table types
+ for (String regionName : regionNames) {
+ Region region = GeodeUtils.createRegionProxy(clientCache, regionName);
+
+ Iterator regionIterator = region.keySetOnServer().iterator();
+
+ Object firstRegionEntry = region.get(regionIterator.next());
+ // TODO: how to handle empty Regions? JMX?
+ Table table = new GeodeTable(this, regionName, createRelDataType(firstRegionEntry),
+ clientCache);
+
+ builder.put(regionName, table);
+ }
+
+ tableMap = builder.build();
+ }
+
+ return tableMap;
+ }
+}
+
+// End GeodeSchema.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSchemaFactory.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSchemaFactory.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSchemaFactory.java
new file mode 100644
index 0000000..8052925
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSchemaFactory.java
@@ -0,0 +1,69 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.model.ModelHandler;
+import org.apache.calcite.runtime.GeoFunctions;
+import org.apache.calcite.schema.Schema;
+import org.apache.calcite.schema.SchemaFactory;
+import org.apache.calcite.schema.SchemaPlus;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.Map;
+
+/**
+ * Factory that creates a {@link GeodeSchema}.
+ */
+@SuppressWarnings("UnusedDeclaration")
+public class GeodeSchemaFactory implements SchemaFactory {
+
+ public static final String LOCATOR_HOST = "locatorHost";
+ public static final String LOCATOR_PORT = "locatorPort";
+ public static final String REGIONS = "regions";
+ public static final String PDX_SERIALIZABLE_PACKAGE_PATH = "pdxSerializablePackagePath";
+ public static final String ALLOW_SPATIAL_FUNCTIONS = "spatialFunction";
+ public static final String COMMA_DELIMITER = ",";
+
+ public GeodeSchemaFactory() {
+ // Do Nothing
+ }
+
+ public synchronized Schema create(SchemaPlus parentSchema, String name,
+ Map<String, Object> operand) {
+ Map map = (Map) operand;
+ String locatorHost = (String) map.get(LOCATOR_HOST);
+ int locatorPort = Integer.valueOf((String) map.get(LOCATOR_PORT));
+ String[] regionNames = ((String) map.get(REGIONS)).split(COMMA_DELIMITER);
+ String pbxSerializablePackagePath = (String) map.get(PDX_SERIALIZABLE_PACKAGE_PATH);
+
+ boolean allowSpatialFunctions = true;
+ if (map.containsKey(ALLOW_SPATIAL_FUNCTIONS)) {
+ allowSpatialFunctions = Boolean.valueOf((String) map.get(ALLOW_SPATIAL_FUNCTIONS));
+ }
+
+ if (allowSpatialFunctions) {
+ ModelHandler.addFunctions(parentSchema, null, ImmutableList.<String>of(),
+ GeoFunctions.class.getName(), "*", true);
+ }
+
+ return new GeodeSchema(locatorHost, locatorPort, regionNames,
+ pbxSerializablePackagePath, parentSchema);
+ }
+}
+
+// End GeodeSchemaFactory.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSort.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSort.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSort.java
new file mode 100644
index 0000000..a1a3c2c
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeSort.java
@@ -0,0 +1,106 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of
+ * {@link Sort}
+ * relational expression in Geode.
+ */
+public class GeodeSort extends Sort implements GeodeRel {
+
+ public static final String ASC = "ASC";
+ public static final String DESC = "DESC";
+
+ /** Creates a GeodeSort. */
+ public GeodeSort(RelOptCluster cluster, RelTraitSet traitSet,
+ RelNode input, RelCollation collation, RexNode fetch) {
+ super(cluster, traitSet, input, collation, null, fetch);
+
+ assert getConvention() == GeodeRel.CONVENTION;
+ assert getConvention() == input.getConvention();
+ }
+
+ @Override public RelOptCost computeSelfCost(RelOptPlanner planner,
+ RelMetadataQuery mq) {
+
+ RelOptCost cost = super.computeSelfCost(planner, mq);
+
+ if (fetch != null) {
+ return cost.multiplyBy(0.05);
+ } else {
+ return cost;
+ }
+ }
+
+ @Override public Sort copy(RelTraitSet traitSet, RelNode input,
+ RelCollation newCollation, RexNode offset, RexNode fetch) {
+ return new GeodeSort(getCluster(), traitSet, input, collation, fetch);
+ }
+
+ @Override public void implement(GeodeImplementContext geodeImplementContext) {
+
+ ((GeodeRel) getInput()).implement(geodeImplementContext);
+
+
+ List<RelFieldCollation> sortCollations = collation.getFieldCollations();
+
+ if (!sortCollations.isEmpty()) {
+
+ List<String> orderByFields = new ArrayList<String>();
+
+ for (RelFieldCollation fieldCollation : sortCollations) {
+ final String name = fieldName(fieldCollation.getFieldIndex());
+ orderByFields.add(name + " " + direction(fieldCollation.getDirection()));
+ }
+ geodeImplementContext.addOrderByFields(orderByFields);
+ }
+
+
+ if (fetch != null) {
+ geodeImplementContext.setLimit(((RexLiteral) fetch).getValue().toString());
+ }
+ }
+
+ private String fieldName(int index) {
+ return getRowType().getFieldList().get(index).getName();
+ }
+
+ private String direction(RelFieldCollation.Direction relDirection) {
+ if (relDirection == RelFieldCollation.Direction.DESCENDING) {
+ return DESC;
+ }
+ return ASC;
+ }
+}
+
+// End GeodeSort.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeTable.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeTable.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeTable.java
new file mode 100644
index 0000000..c39b94c
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeTable.java
@@ -0,0 +1,256 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.adapter.geode.util.JavaTypeFactoryExtImpl;
+import org.apache.calcite.adapter.java.AbstractQueryableTable;
+import org.apache.calcite.linq4j.AbstractEnumerable;
+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.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.rel.type.RelProtoDataType;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.TranslatableTable;
+import org.apache.calcite.schema.impl.AbstractTableQueryable;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.Util;
+
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.query.QueryService;
+import org.apache.geode.cache.query.SelectResults;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Table based on a Geode Region
+ */
+public class GeodeTable extends AbstractQueryableTable implements TranslatableTable {
+
+ protected static final Logger LOGGER = LoggerFactory.getLogger(GeodeTable.class.getName());
+
+ private GeodeSchema schema;
+
+ private String regionName;
+
+ private RelDataType relDataType;
+
+ private ClientCache clientCache;
+
+ public GeodeTable(GeodeSchema schema,
+ String regionName,
+ RelDataType relDataType,
+ ClientCache clientCache) {
+ super(Object[].class);
+ this.schema = schema;
+ this.regionName = regionName;
+ this.relDataType = relDataType;
+ this.clientCache = clientCache;
+ }
+
+ public String toString() {
+ return "GeodeTable {" + regionName + "}";
+ }
+
+ /**
+ * Executes an OQL query on the underlying table.
+ *
+ * <p>Called by the {@link GeodeQueryable} which in turn is
+ * called via the generated code.
+ *
+ * @param clientCache Geode client cache
+ * @param fields List of fields to project
+ * @param predicates A list of predicates which should be used in the query
+ * @return Enumerator of results
+ */
+ public Enumerable<Object> query(final ClientCache clientCache,
+ final List<Map.Entry<String, Class>> fields,
+ final List<Map.Entry<String, String>> selectFields,
+ final List<Map.Entry<String, String>> aggregateFunctions,
+ final List<String> groupByFields,
+ List<String> predicates,
+ List<String> orderByFields,
+ String limit) {
+
+ final RelDataTypeFactory typeFactory = new JavaTypeFactoryExtImpl();
+ final RelDataTypeFactory.Builder fieldInfo = typeFactory.builder();
+
+ for (Map.Entry<String, Class> field : fields) {
+ SqlTypeName typeName = typeFactory.createJavaType(field.getValue()).getSqlTypeName();
+ fieldInfo.add(field.getKey(), typeFactory.createSqlType(typeName)).nullable(true);
+ }
+
+ final RelProtoDataType resultRowType = RelDataTypeImpl.proto(fieldInfo.build());
+
+ ImmutableMap<String, String> aggFuncMap = ImmutableMap.of();
+ if (!aggregateFunctions.isEmpty()) {
+ ImmutableMap.Builder<String, String> aggFuncMapBuilder = ImmutableMap.builder();
+ for (Map.Entry<String, String> e : aggregateFunctions) {
+ aggFuncMapBuilder.put(e.getKey(), e.getValue());
+ }
+ aggFuncMap = aggFuncMapBuilder.build();
+ }
+
+ // Construct the list of fields to project
+ Builder<String> selectBuilder = ImmutableList.builder();
+ if (!groupByFields.isEmpty()) {
+ for (String groupByField : groupByFields) {
+ selectBuilder.add(groupByField + " AS " + groupByField);
+ }
+ if (!aggFuncMap.isEmpty()) {
+ for (Map.Entry<String, String> e : aggFuncMap.entrySet()) {
+ selectBuilder.add(e.getValue() + " AS " + e.getKey());
+ }
+ }
+ } else {
+ if (selectFields.isEmpty()) {
+ if (!aggFuncMap.isEmpty()) {
+ for (Map.Entry<String, String> e : aggFuncMap.entrySet()) {
+ selectBuilder.add(e.getValue() + " AS " + e.getKey());
+ }
+ } else {
+ selectBuilder.add("*");
+ }
+ } else {
+ for (Map.Entry<String, String> field : selectFields) {
+ selectBuilder.add(field.getKey() + " AS " + field.getValue());
+ }
+ }
+ }
+
+ final String oqlSelectStatement = Util.toString(selectBuilder.build(), " ", ", ", "");
+
+ // Combine all predicates conjunctively
+ String whereClause = "";
+ if (!predicates.isEmpty()) {
+ whereClause = " WHERE ";
+ whereClause += Util.toString(predicates, "", " AND ", "");
+ }
+
+ // Build and issue the query and return an Enumerator over the results
+ StringBuilder queryBuilder = new StringBuilder("SELECT ");
+ queryBuilder.append(oqlSelectStatement);
+ queryBuilder.append(" FROM /" + regionName);
+ queryBuilder.append(whereClause);
+
+ if (!groupByFields.isEmpty()) {
+ queryBuilder.append(Util.toString(groupByFields, " GROUP BY ", ", ", ""));
+ }
+
+ if (!orderByFields.isEmpty()) {
+ queryBuilder.append(Util.toString(orderByFields, " ORDER BY ", ", ", ""));
+ }
+ if (limit != null) {
+ queryBuilder.append(" LIMIT " + limit);
+ }
+
+ final String oqlQuery = queryBuilder.toString();
+
+ LOGGER.info("OQL: " + oqlQuery);
+
+ return new AbstractEnumerable<Object>() {
+ public Enumerator<Object> enumerator() {
+ SelectResults results = null;
+ QueryService queryService = clientCache.getQueryService();
+
+ try {
+ results = (SelectResults) queryService.newQuery(oqlQuery).execute();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return new GeodeEnumerator(results, resultRowType);
+ }
+ };
+ }
+
+ public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
+ SchemaPlus schema, String tableName) {
+ return new GeodeQueryable<>(queryProvider, schema, this, tableName);
+ }
+
+ @Override public RelNode toRel(
+ RelOptTable.ToRelContext context,
+ RelOptTable relOptTable) {
+
+ final RelOptCluster cluster = context.getCluster();
+ return new GeodeTableScan(cluster, cluster.traitSetOf(GeodeRel.CONVENTION),
+ relOptTable, this, null);
+ }
+
+ @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+ return relDataType;
+ }
+
+ /**
+ * Implementation of {@link Queryable} based on a {@link GeodeTable}.
+ *
+ * @param <T> type
+ */
+ public static class GeodeQueryable<T> extends AbstractTableQueryable<T> {
+
+ public GeodeQueryable(QueryProvider queryProvider, SchemaPlus schema,
+ GeodeTable table, String tableName) {
+ super(queryProvider, schema, table, tableName);
+ }
+
+ // tzolov: this should never be called for queryable tables???
+ public Enumerator<T> enumerator() {
+ throw new UnsupportedOperationException("Enumerator on Queryable should never be called");
+ }
+
+ private GeodeTable getTable() {
+ return (GeodeTable) table;
+ }
+
+ private ClientCache getClientCache() {
+ return schema.unwrap(GeodeSchema.class).clientCache;
+ }
+
+ /**
+ * Called via code-generation.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public Enumerable<Object> query(
+ List<Map.Entry<String, Class>> fields,
+ List<Map.Entry<String, String>> selectFields,
+ List<Map.Entry<String, String>> aggregateFunctions,
+ List<String> groupByFields,
+ List<String> predicates,
+ List<String> order,
+ String limit) {
+ return getTable().query(getClientCache(), fields, selectFields,
+ aggregateFunctions, groupByFields, predicates, order, limit);
+ }
+ }
+}
+
+// End GeodeTable.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeTableScan.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeTableScan.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeTableScan.java
new file mode 100644
index 0000000..b83838f
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeTableScan.java
@@ -0,0 +1,80 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rel.type.RelDataType;
+
+import java.util.List;
+
+/**
+ * Relational expression representing a scan of a Geode collection.
+ */
+public class GeodeTableScan extends TableScan implements GeodeRel {
+
+ final GeodeTable geodeTable;
+ final RelDataType projectRowType;
+
+ /**
+ * Creates a GeodeTableScan.
+ *
+ * @param cluster Cluster
+ * @param traitSet Traits
+ * @param table Table
+ * @param geodeTable Geode table
+ * @param projectRowType Fields and types to project; null to project raw row
+ */
+ protected GeodeTableScan(RelOptCluster cluster, RelTraitSet traitSet,
+ RelOptTable table, GeodeTable geodeTable, RelDataType projectRowType) {
+ super(cluster, traitSet, table);
+ this.geodeTable = geodeTable;
+ this.projectRowType = projectRowType;
+
+ assert geodeTable != null;
+ assert getConvention() == GeodeRel.CONVENTION;
+ }
+
+ @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ assert inputs.isEmpty();
+ return this;
+ }
+
+ @Override public RelDataType deriveRowType() {
+ return projectRowType != null ? projectRowType : super.deriveRowType();
+ }
+
+ @Override public void register(RelOptPlanner planner) {
+ planner.addRule(GeodeToEnumerableConverterRule.INSTANCE);
+ for (RelOptRule rule : GeodeRules.RULES) {
+ planner.addRule(rule);
+ }
+ }
+
+ @Override public void implement(GeodeImplementContext geodeImplementContext) {
+ // Note: Scan is the leaf and we do NOT visit its inputs
+ geodeImplementContext.geodeTable = geodeTable;
+ geodeImplementContext.table = table;
+ }
+}
+
+// End GeodeTableScan.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeToEnumerableConverter.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeToEnumerableConverter.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeToEnumerableConverter.java
new file mode 100644
index 0000000..5f85907
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeToEnumerableConverter.java
@@ -0,0 +1,164 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.adapter.enumerable.EnumerableRel;
+import org.apache.calcite.adapter.enumerable.EnumerableRelImplementor;
+import org.apache.calcite.adapter.enumerable.JavaRowFormat;
+import org.apache.calcite.adapter.enumerable.PhysType;
+import org.apache.calcite.adapter.enumerable.PhysTypeImpl;
+import org.apache.calcite.adapter.geode.rel.GeodeRel.GeodeImplementContext;
+import org.apache.calcite.linq4j.tree.BlockBuilder;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.linq4j.tree.Expressions;
+import org.apache.calcite.linq4j.tree.MethodCallExpression;
+import org.apache.calcite.linq4j.tree.Types;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.ConverterImpl;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.runtime.Hook;
+import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.Pair;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
+import java.lang.reflect.Method;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.calcite.adapter.geode.rel.GeodeRules.geodeFieldNames;
+
+/**
+ * Relational expression representing a scan of a table in a Geode data source.
+ */
+public class GeodeToEnumerableConverter extends ConverterImpl implements EnumerableRel {
+
+ protected GeodeToEnumerableConverter(RelOptCluster cluster,
+ RelTraitSet traitSet, RelNode input) {
+ super(cluster, ConventionTraitDef.INSTANCE, traitSet, input);
+ }
+
+ @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ return new GeodeToEnumerableConverter(
+ getCluster(), traitSet, sole(inputs));
+ }
+
+ @Override public RelOptCost computeSelfCost(RelOptPlanner planner,
+ RelMetadataQuery mq) {
+ return super.computeSelfCost(planner, mq).multiplyBy(.1);
+ }
+
+ /**
+ * Reference to the method {@link GeodeTable.GeodeQueryable#query},
+ * used in the {@link Expression}.
+ */
+ private static final Method GEODE_QUERY_METHOD =
+ Types.lookupMethod(GeodeTable.GeodeQueryable.class, "query", List.class,
+ List.class, List.class, List.class, List.class, List.class,
+ String.class);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param implementor GeodeImplementContext
+ */
+ @Override public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
+
+ // travers all relations form this to the scan leaf
+ final GeodeImplementContext geodeImplementContext = new GeodeImplementContext();
+ ((GeodeRel) getInput()).implement(geodeImplementContext);
+
+ // PhysType is Enumerable Adapter class that maps SQL types (getRowType)
+ // with physical Java types (getJavaTypes())
+ final PhysType physType = PhysTypeImpl.of(
+ implementor.getTypeFactory(),
+ rowType,
+ pref.prefer(JavaRowFormat.ARRAY));
+
+ final List<Class> physFieldClasses = new AbstractList<Class>() {
+ public Class get(int index) {
+ return physType.fieldClass(index);
+ }
+
+ public int size() {
+ return rowType.getFieldCount();
+ }
+ };
+
+ // Expression meta-program for calling the GeodeTable.GeodeQueryable#query
+ // method form the generated code
+ final BlockBuilder blockBuilder = new BlockBuilder().append(
+ Expressions.call(
+ geodeImplementContext.table.getExpression(GeodeTable.GeodeQueryable.class),
+ GEODE_QUERY_METHOD,
+ constantArrayList(Pair.zip(geodeFieldNames(rowType), physFieldClasses), Pair.class),
+ // physical fields
+ constantArrayList(toListMapPairs(geodeImplementContext.selectFields), Pair.class),
+ // selected fields
+ constantArrayList(
+ toListMapPairs(geodeImplementContext.oqlAggregateFunctions), Pair.class),
+ constantArrayList(geodeImplementContext.groupByFields, String.class),
+ constantArrayList(geodeImplementContext.whereClause, String.class),
+ constantArrayList(geodeImplementContext.orderByFields, String.class),
+ Expressions.constant(geodeImplementContext.limitValue)));
+
+ Hook.QUERY_PLAN.run(geodeImplementContext);
+
+ return implementor.result(physType, blockBuilder.toBlock());
+ }
+
+ private static List<Map.Entry<String, String>> toListMapPairs(Map<String, String> map) {
+ List<Map.Entry<String, String>> selectList = new ArrayList<>();
+ for (Map.Entry<String, String> entry : Pair.zip(map.keySet(), map.values())) {
+ selectList.add(entry);
+ }
+ return selectList;
+ }
+
+ /**
+ * E.g. {@code constantArrayList("x", "y")} returns
+ * "Arrays.asList('x', 'y')".
+ */
+ private static <T> MethodCallExpression constantArrayList(List<T> values,
+ Class clazz) {
+ return Expressions.call(BuiltInMethod.ARRAYS_AS_LIST.method,
+ Expressions.newArrayInit(clazz, constantList(values)));
+ }
+
+ /**
+ * E.g. {@code constantList("x", "y")} returns
+ * {@code {ConstantExpression("x"), ConstantExpression("y")}}.
+ */
+ private static <T> List<Expression> constantList(List<T> values) {
+ return Lists.transform(values,
+ new Function<T, Expression>() {
+ public Expression apply(T a0) {
+ return Expressions.constant(a0);
+ }
+ });
+ }
+}
+
+// End GeodeToEnumerableConverter.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeToEnumerableConverterRule.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeToEnumerableConverterRule.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeToEnumerableConverterRule.java
new file mode 100644
index 0000000..c36b720
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/GeodeToEnumerableConverterRule.java
@@ -0,0 +1,43 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.adapter.enumerable.EnumerableConvention;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.ConverterRule;
+
+/**
+ * Rule to convert a relational expression from
+ * {@link GeodeRel#CONVENTION} to {@link EnumerableConvention}.
+ */
+public class GeodeToEnumerableConverterRule extends ConverterRule {
+
+ public static final ConverterRule INSTANCE = new GeodeToEnumerableConverterRule();
+
+ private GeodeToEnumerableConverterRule() {
+ super(RelNode.class, GeodeRel.CONVENTION, EnumerableConvention.INSTANCE,
+ "GeodeToEnumerableConverterRule");
+ }
+
+ @Override public RelNode convert(RelNode rel) {
+ RelTraitSet newTraitSet = rel.getTraitSet().replace(getOutConvention());
+ return new GeodeToEnumerableConverter(rel.getCluster(), newTraitSet, rel);
+ }
+}
+
+// End GeodeToEnumerableConverterRule.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/rel/package-info.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/rel/package-info.java b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/package-info.java
new file mode 100644
index 0000000..468b28e
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/rel/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Query provider based on Apache Geode (Gemfire) In Memory Data Grid
+ */
+@PackageMarker
+package org.apache.calcite.adapter.geode.rel;
+
+import org.apache.calcite.avatica.util.PackageMarker;
+
+// End package-info.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleEnumerator.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleEnumerator.java b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleEnumerator.java
new file mode 100644
index 0000000..af799b4
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleEnumerator.java
@@ -0,0 +1,76 @@
+/*
+ * 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.adapter.geode.simple;
+
+import org.apache.calcite.linq4j.Enumerator;
+
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.query.QueryService;
+import org.apache.geode.cache.query.SelectResults;
+
+import java.util.Iterator;
+
+/**
+ * Geode Simple Enumerator.
+ *
+ * @param <E> Element type
+ */
+public abstract class GeodeSimpleEnumerator<E> implements Enumerator<E> {
+
+ private Iterator results;
+
+ private E current;
+ private ClientCache clientCache;
+
+ public GeodeSimpleEnumerator(ClientCache clientCache, String regionName) {
+ this.clientCache = clientCache;
+ QueryService queryService = clientCache.getQueryService();
+ String oql = "select * from /" + regionName.trim();
+ try {
+ results = ((SelectResults) queryService.newQuery(oql).execute()).iterator();
+ } catch (Exception e) {
+ e.printStackTrace();
+ results = null;
+ }
+ }
+
+ @Override public E current() {
+ return current;
+ }
+
+ @Override public boolean moveNext() {
+
+ if (results.hasNext()) {
+ current = convert(results.next());
+ return true;
+ }
+ current = null;
+ return false;
+ }
+
+ @Override public void reset() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void close() {
+ /*clientCache.close(); */
+ }
+
+ public abstract E convert(Object obj);
+}
+
+// End GeodeSimpleEnumerator.java
[4/7] calcite git commit: [CALCITE-2180] Invalid code generated for
negative of byte and short values
Posted by jh...@apache.org.
[CALCITE-2180] Invalid code generated for negative of byte and short values
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/3c67a605
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/3c67a605
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/3c67a605
Branch: refs/heads/master
Commit: 3c67a605cb6d6613ea1696288254a90f621a2834
Parents: becb6df
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Feb 15 12:25:14 2018 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Feb 16 10:18:02 2018 -0800
----------------------------------------------------------------------
.../calcite/adapter/enumerable/RexImpTable.java | 12 +++++--
core/src/test/resources/sql/misc.iq | 36 ++++++++++++++++++++
.../apache/calcite/linq4j/tree/Expressions.java | 10 ++++--
.../calcite/linq4j/test/ExpressionTest.java | 14 ++++++++
4 files changed, 67 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/3c67a605/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 20d340e..a1a88ad 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -31,6 +31,7 @@ import org.apache.calcite.linq4j.tree.OptimizeShuttle;
import org.apache.calcite.linq4j.tree.ParameterExpression;
import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.linq4j.tree.Types;
+import org.apache.calcite.linq4j.tree.UnaryExpression;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.prepare.Prepare;
import org.apache.calcite.rel.type.RelDataType;
@@ -1901,9 +1902,14 @@ public class RexImpTable {
RexToLixTranslator translator,
RexCall call,
List<Expression> translatedOperands) {
- return Expressions.makeUnary(
- expressionType,
- translatedOperands.get(0));
+ final Expression operand = translatedOperands.get(0);
+ final UnaryExpression e = Expressions.makeUnary(expressionType, operand);
+ if (e.type.equals(operand.type)) {
+ return e;
+ }
+ // Certain unary operators do not preserve type. For example, the "-"
+ // operator applied to a "byte" expression returns an "int".
+ return Expressions.convert_(e, operand.type);
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/3c67a605/core/src/test/resources/sql/misc.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.iq b/core/src/test/resources/sql/misc.iq
index b9d64cd..ba2ebd6 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -1030,6 +1030,42 @@ Expression 'DEPTNO' is not being grouped
!use scott
+# ORDER BY expression with SELECT DISTINCT
+select distinct deptno, job
+from "scott".emp
+order by substring(job from 2 for 1), -deptno;
++--------+-----------+
+| DEPTNO | JOB |
++--------+-----------+
+| 30 | SALESMAN |
+| 30 | MANAGER |
+| 20 | MANAGER |
+| 10 | MANAGER |
+| 30 | CLERK |
+| 20 | CLERK |
+| 10 | CLERK |
+| 20 | ANALYST |
+| 10 | PRESIDENT |
++--------+-----------+
+(9 rows)
+
+!ok
+
+# [CALCITE-2180] Invalid code generated for negative of byte and short values
+select -deptno as d
+from "scott".dept;
++-----+
+| D |
++-----+
+| -40 |
+| -30 |
+| -20 |
+| -10 |
++-----+
+(4 rows)
+
+!ok
+
# [CALCITE-2099] Incorrect code generated for UNION
select count(*) as c from "scott".emp group by deptno
union
http://git-wip-us.apache.org/repos/asf/calcite/blob/3c67a605/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
index 6902cc4..5d7f83d 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
@@ -1605,8 +1605,14 @@ public abstract class Expressions {
*/
public static UnaryExpression makeUnary(ExpressionType expressionType,
Expression expression) {
- return new UnaryExpression(expressionType, expression.getType(),
- expression);
+ Type type = expression.getType();
+ switch (expressionType) {
+ case Negate:
+ if (type == byte.class || type == short.class) {
+ type = int.class;
+ }
+ }
+ return new UnaryExpression(expressionType, type, expression);
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/3c67a605/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
----------------------------------------------------------------------
diff --git a/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java b/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
index 9d094b3..8f1756d 100644
--- a/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
+++ b/linq4j/src/test/java/org/apache/calcite/linq4j/test/ExpressionTest.java
@@ -835,6 +835,20 @@ public class ExpressionTest {
Expressions.constant(true),
Expressions.constant(0),
Expressions.constant(null)).getType());
+
+ // In Java, "-" applied to short and byte yield int.
+ assertEquals(double.class,
+ Expressions.negate(Expressions.constant((double) 1)).getType());
+ assertEquals(float.class,
+ Expressions.negate(Expressions.constant((float) 1)).getType());
+ assertEquals(long.class,
+ Expressions.negate(Expressions.constant((long) 1)).getType());
+ assertEquals(int.class,
+ Expressions.negate(Expressions.constant(1)).getType());
+ assertEquals(int.class,
+ Expressions.negate(Expressions.constant((short) 1)).getType());
+ assertEquals(int.class,
+ Expressions.negate(Expressions.constant((byte) 1)).getType());
}
@Test public void testCompile() throws NoSuchMethodException {
[5/7] calcite git commit: [CALCITE-2059] Apache Geode Adapter
(Christian Tzolov)
Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/site/_docs/adapter.md
----------------------------------------------------------------------
diff --git a/site/_docs/adapter.md b/site/_docs/adapter.md
index 35001ed..4b1a521 100644
--- a/site/_docs/adapter.md
+++ b/site/_docs/adapter.md
@@ -35,6 +35,7 @@ presenting the data as tables within a schema.
and
<a href="{{ site.apiRoot }}/org/apache/calcite/adapter/elasticsearch5/package-summary.html">calcite-elasticsearch5</a>)
* [File adapter](file_adapter.html) (<a href="{{ site.apiRoot }}/org/apache/calcite/adapter/file/package-summary.html">calcite-file</a>)
+* [Geode adapter](geode_adapter.html) (<a href="{{ site.apiRoot }}/org/apache/calcite/adapter/geode/package-summary.html">calcite-geode</a>)
* JDBC adapter (part of <a href="{{ site.apiRoot }}/org/apache/calcite/adapter/jdbc/package-summary.html">calcite-core</a>)
* MongoDB adapter (<a href="{{ site.apiRoot }}/org/apache/calcite/adapter/mongodb/package-summary.html">calcite-mongodb</a>)
* [OS adapter](os_adapter.html) (<a href="{{ site.apiRoot }}/org/apache/calcite/adapter/os/package-summary.html">calcite-os</a>)
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/site/_docs/geode_adapter.md
----------------------------------------------------------------------
diff --git a/site/_docs/geode_adapter.md b/site/_docs/geode_adapter.md
new file mode 100644
index 0000000..f6678ee
--- /dev/null
+++ b/site/_docs/geode_adapter.md
@@ -0,0 +1,180 @@
+---
+layout: docs
+title: Apache Geode adapter
+permalink: /docs/geode_adapter.html
+---
+<!--
+{% comment %}
+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.
+{% endcomment %}
+-->
+
+For instructions on downloading and building Calcite, start with the
+[tutorial]({{ site.baseurl }}/docs/tutorial.html).
+
+> Optionally: add `-Puberjdbc` to your maven build to create a single self-contained Geode JDBC adapter jar.
+
+
+Once you've managed to compile the project, you can return here to
+start querying Apache Geode with Calcite. First, we need a
+[model definition]({{ site.baseurl }}/docs/model.html).
+The model gives Calcite the necessary parameters to create an instance
+of the Geode adapter. The models can contain definitions of
+[materializations]({{ site.baseurl }}/docs/model.html#materialization).
+The name of the tables defined in the model definition corresponds to
+[Regions](https://geode.apache.org/docs/guide/12/developing/region_options/chapter_overview.html)
+in Geode.
+
+A basic example of a model file is given below:
+
+{% highlight json %}
+{
+ "version": "1.0",
+ "defaultSchema": "geode",
+ "schemas": [
+ {
+ "name": "geode_raw",
+ "type": "custom",
+ "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory",
+ "operand": {
+ "locatorHost": "localhost",
+ "locatorPort": "10334",
+ "regions": "Zips",
+ "pdxSerializablePackagePath": ".*"
+ }
+ }
+ ]
+}
+{% endhighlight %}
+
+This adapter is targeted for Geode 1.3.x. The `regions` field allows to list (comma separated)
+all Geode regions to be appear as relational tables.
+
+Assuming this file is stored as `model.json`, you can connect to
+Geode via [`sqlline`](https://github.com/julianhyde/sqlline) as
+follows:
+
+{% highlight bash %}
+$ ./sqlline
+sqlline> !connect jdbc:calcite:model=model.json admin admin
+{% endhighlight %}
+
+`sqlline` will now accept SQL queries which access your Regions using OQL.
+However, you're not restricted to issuing queries supported by
+[OQL](https://geode.apache.org/docs/guide/latest/developing/querying_basics/chapter_overview.html).
+Calcite allows you to perform complex operations such as aggregations
+or joins. The adapter will attempt to compile the query into the most
+efficient OQL possible by exploiting filtering, sorting and aggregation directly
+in Geode where possible.
+
+For example, in the example Bookshop dataset there is a Regions `BookMaster`.
+
+We can issue a SQL query to fetch the annual retail cost ordered by the cost:
+
+{% highlight sql %}
+sqlline> SELECT
+ "yearPublished",
+ SUM("retailCost") AS "totalCost"
+ FROM "TEST"."BookMaster"
+ GROUP BY "yearPublished"
+ ORDER BY "totalCost";
++---------------+--------------------+
+| yearPublished | totalCost |
++---------------+--------------------+
+| 1971 | 11.989999771118164 |
+| 2011 | 94.9800033569336 |
++---------------+--------------------+
+{% endhighlight %}
+
+While executing this query, the Geode adapter is able to recognize
+that the projection, grouping and ordering can be performed natively by Geode.
+
+The final OQL query given to Geode is below:
+
+{% highlight sql %}
+SELECT yearPublished AS yearPublished, SUM(retailCost) AS totalCost
+FROM /BookMaster
+GROUP BY yearPublished
+ORDER BY totalCost ASC
+{% endhighlight %}
+
+Operations that are not supported in Geode are handled by Calcite itself.
+For example the following JOIN query on the same Bookshop dataset
+
+{% highlight sql %}
+sqlline> SELECT
+ "i"."itemNumber",
+ "m"."author",
+ "m"."retailCost"
+ FROM "TEST"."BookInventory" "i"
+ JOIN "TEST"."BookMaster" "m" ON "i"."itemNumber" = "m"."itemNumber"
+ WHERE "m"."retailCost" > 20;
++------------+----------------+------------+
+| itemNumber | author | retailCost |
++------------+----------------+------------+
+| 123 | Daisy Mae West | 34.99 |
++------------+----------------+------------+
+{% endhighlight %}
+
+Will result into two separate OQL queries:
+
+{% highlight sql %}
+SELECT itemNumber AS itemNumber, retailCost AS retailCost, author AS author
+FROM /BookMaster
+WHERE retailCost > 20
+{% endhighlight %}
+
+{% highlight sql %}
+SELECT itemNumber AS itemNumber
+FROM /BookInventory
+{% endhighlight %}
+
+And the result will be joined in Calcite.
+
+To select a particular item in Geode array field use the `fieldName[index]`
+syntax:
+{% highlight sql %}
+sqlline> SELECT
+ "loc" [0] AS "lon",
+ "loc" [1] AS "lat"
+ FROM "geode".ZIPS
+{% endhighlight %}
+
+To select a nested fields use the map `fieldName[nestedFiledName]`
+syntax:
+{% highlight sql %}
+sqlline> SELECT "primaryAddress" ['postalCode'] AS "postalCode"
+ FROM "TEST"."BookCustomer"
+ WHERE "primaryAddress" ['postalCode'] > '0';
+{% endhighlight %}
+This will project `BookCustomer.primaryAddress.postalCode` value field.
+
+The following presentations and video tutorials provide further dails
+about Geode adapter:
+
+* [Enable SQL/JDBC Access to Apache Geode/GemFire Using Apache Calcite](https://www.slideshare.net/slideshow/embed_code/key/2Mil7I0ZPMLuJU)
+ (GeodeSummit/SpringOne 2017)
+* [Access Apache Geode / GemFire over SQL/JDBC](https://www.linkedin.com/pulse/access-apache-geode-gemfire-over-sqljdbc-christian-tzolov)
+* [Explore Geode & GemFire Data with IntelliJ SQL/Database tool](https://www.linkedin.com/pulse/explore-your-geode-gemfire-data-from-within-intellij-tool-tzolov)
+* [Advanced Apache Geode Data Analytics with Apache Zeppelin over SQL/JDBC](https://www.linkedin.com/pulse/advanced-apache-geode-data-analytics-zeppelin-over-sqljdbc-tzolov)
+* [Unified Access to {Geode|Greenplum|...}](https://www.linkedin.com/pulse/unified-access-geodegreenplum-christian-tzolov)
+* [Apache Calcite for Enabling SQL Access to NoSQL Data Systems such as Apache Geode](https://schd.ws/hosted_files/apachebigdataeu2016/b6/ApacheCon2016ChristianTzolov.v3.pdf)
+ (ApacheCon Big Data, 2016)
+
+There is still significant work to do in improving the flexibility and
+performance of the adapter, but if you're looking for a quick way to
+gain additional insights into data stored in Geode, Calcite should
+prove useful.
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/sqlline
----------------------------------------------------------------------
diff --git a/sqlline b/sqlline
index b23dcd9..c26f001 100755
--- a/sqlline
+++ b/sqlline
@@ -37,7 +37,7 @@ if [ ! -f target/fullclasspath.txt ]; then
fi
CP=
-for module in core cassandra druid elasticsearch2 elasticsearch5 file mongodb server spark splunk example/csv example/function; do
+for module in core cassandra druid elasticsearch2 elasticsearch5 file mongodb server spark splunk geode example/csv example/function; do
CP=${CP}${module}/target/classes:
CP=${CP}${module}/target/test-classes:
done
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/sqlline.bat
----------------------------------------------------------------------
diff --git a/sqlline.bat b/sqlline.bat
index f7165c0..b163e6f 100644
--- a/sqlline.bat
+++ b/sqlline.bat
@@ -23,6 +23,6 @@
:: Copy dependency jars on first call. (To force jar refresh, remove target\dependencies)
if not exist target\dependencies (call mvn -B dependency:copy-dependencies -DoverWriteReleases=false -DoverWriteSnapshots=false -DoverWriteIfNewer=true -DoutputDirectory=target\dependencies)
-java -Xmx1G -cp ".\target\dependencies\*;core\target\dependencies\*;cassandra\target\dependencies\*;druid\target\dependencies\*;elasticsearch2\target\dependencies\*;elasticsearch5\target\dependencies\*;file\target\dependencies\*;mongodb\target\dependencies\*;server\target\dependencies\*;spark\target\dependencies\*;splunk\target\dependencies\*" sqlline.SqlLine --verbose=true %*
+java -Xmx1G -cp ".\target\dependencies\*;core\target\dependencies\*;cassandra\target\dependencies\*;druid\target\dependencies\*;elasticsearch2\target\dependencies\*;elasticsearch5\target\dependencies\*;geode\target\dependencies\*;file\target\dependencies\*;mongodb\target\dependencies\*;server\target\dependencies\*;spark\target\dependencies\*;splunk\target\dependencies\*" sqlline.SqlLine --verbose=true %*
:: End sqlline.bat
[6/7] calcite git commit: [CALCITE-2059] Apache Geode Adapter
(Christian Tzolov)
Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleScannableTable.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleScannableTable.java b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleScannableTable.java
new file mode 100644
index 0000000..add3dac
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleScannableTable.java
@@ -0,0 +1,75 @@
+/*
+ * 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.adapter.geode.simple;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.linq4j.AbstractEnumerable;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.schema.ScannableTable;
+import org.apache.calcite.schema.impl.AbstractTable;
+
+import org.apache.geode.cache.client.ClientCache;
+
+import static org.apache.calcite.adapter.geode.util.GeodeUtils.convertToRowValues;
+
+/**
+ * Geode Simple Scannable Table Abstraction
+ */
+public class GeodeSimpleScannableTable extends AbstractTable implements ScannableTable {
+
+ private final RelDataType relDataType;
+ private String regionName;
+ private ClientCache clientCache;
+
+ public GeodeSimpleScannableTable(String regionName, RelDataType relDataType,
+ ClientCache clientCache) {
+ super();
+
+ this.regionName = regionName;
+ this.clientCache = clientCache;
+ this.relDataType = relDataType;
+ }
+
+ @Override public String toString() {
+ return "GeodeSimpleScannableTable";
+ }
+
+ @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+ return relDataType;
+ }
+
+ @Override public Enumerable<Object[]> scan(DataContext root) {
+ return new AbstractEnumerable<Object[]>() {
+ public Enumerator<Object[]> enumerator() {
+ return new GeodeSimpleEnumerator<Object[]>(clientCache, regionName) {
+ @Override public Object[] convert(Object obj) {
+ Object values = convertToRowValues(relDataType.getFieldList(), obj);
+ if (values instanceof Object[]) {
+ return (Object[]) values;
+ }
+ return new Object[]{values};
+ }
+ };
+ }
+ };
+ }
+}
+
+// End GeodeSimpleScannableTable.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleSchema.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleSchema.java b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleSchema.java
new file mode 100644
index 0000000..bb98e60
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleSchema.java
@@ -0,0 +1,84 @@
+/*
+ * 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.adapter.geode.simple;
+
+import org.apache.calcite.adapter.geode.util.GeodeUtils;
+import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.impl.AbstractSchema;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Map;
+
+import static org.apache.calcite.adapter.geode.util.GeodeUtils.createRelDataType;
+
+/**
+ * Geode Simple Schema.
+ */
+public class GeodeSimpleSchema extends AbstractSchema {
+
+ private String locatorHost;
+ private int locatorPort;
+ private String[] regionNames;
+ private String pdxAutoSerializerPackageExp;
+ private ClientCache clientCache;
+ private ImmutableMap<String, Table> tableMap;
+
+ public GeodeSimpleSchema(
+ String locatorHost, int locatorPort,
+ String[] regionNames, String pdxAutoSerializerPackageExp) {
+ super();
+ this.locatorHost = locatorHost;
+ this.locatorPort = locatorPort;
+ this.regionNames = regionNames;
+ this.pdxAutoSerializerPackageExp = pdxAutoSerializerPackageExp;
+
+ this.clientCache = GeodeUtils.createClientCache(
+ locatorHost,
+ locatorPort,
+ pdxAutoSerializerPackageExp,
+ true);
+ }
+
+ @Override protected Map<String, Table> getTableMap() {
+
+ if (tableMap == null) {
+ final ImmutableMap.Builder<String, Table> builder = ImmutableMap.builder();
+
+ for (String regionName : regionNames) {
+
+ Region region = GeodeUtils.createRegionProxy(clientCache, regionName);
+
+ // TODO: What if the region is empty
+ Object regionEntry = region.get(region.keySetOnServer().iterator().next());
+
+ Table table = new GeodeSimpleScannableTable(regionName, createRelDataType(regionEntry),
+ clientCache);
+
+ builder.put(regionName, table);
+ }
+
+ tableMap = builder.build();
+ }
+ return tableMap;
+ }
+}
+
+// End GeodeSimpleSchema.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleSchemaFactory.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleSchemaFactory.java b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleSchemaFactory.java
new file mode 100644
index 0000000..a7b3a26
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleSchemaFactory.java
@@ -0,0 +1,53 @@
+/*
+ * 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.adapter.geode.simple;
+
+import org.apache.calcite.schema.Schema;
+import org.apache.calcite.schema.SchemaFactory;
+import org.apache.calcite.schema.SchemaPlus;
+
+import java.util.Map;
+
+/**
+ * Geode Simple Table Schema Factory.
+ */
+public class GeodeSimpleSchemaFactory implements SchemaFactory {
+
+ public static final String LOCATOR_HOST = "locatorHost";
+ public static final String LOCATOR_PORT = "locatorPort";
+ public static final String REGIONS = "regions";
+ public static final String PDX_SERIALIZABLE_PACKAGE_PATH = "pdxSerializablePackagePath";
+ public static final String COMMA_DELIMITER = ",";
+
+ public GeodeSimpleSchemaFactory() {
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override public Schema create(SchemaPlus parentSchema,
+ String name, Map<String, Object> operand) {
+ Map map = (Map) operand;
+
+ String locatorHost = (String) map.get(LOCATOR_HOST);
+ int locatorPort = Integer.valueOf((String) map.get(LOCATOR_PORT));
+ String[] regionNames = ((String) map.get(REGIONS)).split(COMMA_DELIMITER);
+ String pdxSerializablePackagePath = (String) map.get(PDX_SERIALIZABLE_PACKAGE_PATH);
+
+ return new GeodeSimpleSchema(locatorHost, locatorPort, regionNames, pdxSerializablePackagePath);
+ }
+}
+
+// End GeodeSimpleSchemaFactory.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/simple/package-info.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/simple/package-info.java b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/package-info.java
new file mode 100644
index 0000000..7f15530
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Query provider based on Apache Geode (Gemfire) In Memory Data Grid
+ */
+@PackageMarker
+package org.apache.calcite.adapter.geode.simple;
+
+import org.apache.calcite.avatica.util.PackageMarker;
+
+// End package-info.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/util/GeodeUtils.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/util/GeodeUtils.java b/geode/src/main/java/org/apache/calcite/adapter/geode/util/GeodeUtils.java
new file mode 100644
index 0000000..fb1c095
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/util/GeodeUtils.java
@@ -0,0 +1,278 @@
+/*
+ * 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.adapter.geode.util;
+
+import org.apache.calcite.avatica.util.DateTimeUtils;
+import org.apache.calcite.linq4j.tree.Primitive;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.util.Util;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.apache.geode.cache.CacheClosedException;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.client.ClientCacheFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+import org.apache.geode.cache.query.Struct;
+import org.apache.geode.pdx.PdxInstance;
+import org.apache.geode.pdx.ReflectionBasedAutoSerializer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Utilities for the Geode adapter.
+ */
+public class GeodeUtils {
+
+ protected static final Logger LOGGER = LoggerFactory.getLogger(GeodeUtils.class.getName());
+
+ /**
+ * Cache for the client proxy regions created in the current ClientCache.
+ */
+ private static final Map<String, Region> REGION_MAP = new ConcurrentHashMap<>();
+
+ private static String currentLocatorHost = "";
+ private static int currentLocatorPort = -1;
+
+ private static final JavaTypeFactoryExtImpl JAVA_TYPE_FACTORY = new JavaTypeFactoryExtImpl();
+
+ private GeodeUtils() {
+ }
+
+ /**
+ * Creates a Geode client instance connected to locator and configured to
+ * support PDX instances.
+ *
+ * <p>If an old instance exists, it will be destroyed and re-created.
+ *
+ * @param locatorHost Locator's host address
+ * @param locatorPort Locator's port
+ * @param autoSerializerPackagePath package name of the Domain classes loaded in the regions
+ * @return Returns a Geode {@link ClientCache} instance connected to Geode cluster
+ */
+ public static synchronized ClientCache createClientCache(String locatorHost,
+ int locatorPort, String autoSerializerPackagePath,
+ boolean readSerialized) {
+ if (locatorPort != currentLocatorPort
+ || !StringUtils.equalsIgnoreCase(currentLocatorHost, locatorHost)) {
+ LOGGER.info("Close existing ClientCache ["
+ + currentLocatorHost + ":" + currentLocatorPort + "] for new Locator connection at: ["
+ + locatorHost + ":" + locatorPort + "]");
+ currentLocatorHost = locatorHost;
+ currentLocatorPort = locatorPort;
+ closeClientCache();
+ }
+
+ try {
+ // If exists returns the existing client cache. This requires that the pre-created
+ // client proxy regions can also be resolved from the regionMap
+ return ClientCacheFactory.getAnyInstance();
+ } catch (CacheClosedException cce) {
+ // Do nothing if there is no existing instance
+ }
+
+ return new ClientCacheFactory()
+ .addPoolLocator(locatorHost, locatorPort)
+ .setPdxSerializer(new ReflectionBasedAutoSerializer(autoSerializerPackagePath))
+ .setPdxReadSerialized(readSerialized)
+ .setPdxPersistent(false)
+ .create();
+ }
+
+ public static synchronized void closeClientCache() {
+ try {
+ ClientCacheFactory.getAnyInstance().close();
+ } catch (CacheClosedException cce) {
+ // Do nothing if there is no existing instance
+ }
+ REGION_MAP.clear();
+ }
+
+ /**
+ * Obtains a proxy pointing to an existing Region on the server
+ *
+ * @param clientCache {@link ClientCache} instance to interact with the Geode server
+ * @param regionName Name of the region to create proxy for.
+ * @return Returns a Region proxy to a remote (on the Server) regions.
+ */
+ public static synchronized Region createRegionProxy(ClientCache clientCache,
+ String regionName) {
+ Region region = REGION_MAP.get(regionName);
+ if (region == null) {
+ region = clientCache
+ .createClientRegionFactory(ClientRegionShortcut.PROXY)
+ .create(regionName);
+ REGION_MAP.put(regionName, region);
+ }
+ return region;
+ }
+
+ /**
+ * Converts a Geode object into a Row tuple.
+ *
+ * @param relDataTypeFields Table relation types
+ * @param geodeResultObject Object value returned by Geode query
+ * @return List of objects values corresponding to the relDataTypeFields
+ */
+ public static Object convertToRowValues(
+ List<RelDataTypeField> relDataTypeFields, Object geodeResultObject) {
+
+ Object values;
+
+ if (geodeResultObject instanceof Struct) {
+ values = handleStructEntry(relDataTypeFields, geodeResultObject);
+ } else if (geodeResultObject instanceof PdxInstance) {
+ values = handlePdxInstanceEntry(relDataTypeFields, geodeResultObject);
+ } else {
+ values = handleJavaObjectEntry(relDataTypeFields, geodeResultObject);
+ }
+
+ return values;
+ }
+
+ private static Object handleStructEntry(
+ List<RelDataTypeField> relDataTypeFields, Object obj) {
+
+ Struct struct = (Struct) obj;
+
+ Object[] values = new Object[relDataTypeFields.size()];
+
+ int index = 0;
+ for (RelDataTypeField relDataTypeField : relDataTypeFields) {
+ Type javaType = JAVA_TYPE_FACTORY.getJavaClass(relDataTypeField.getType());
+ Object rawValue;
+ try {
+ rawValue = struct.get(relDataTypeField.getName());
+ } catch (IllegalArgumentException e) {
+ rawValue = "<error>";
+ System.err.println("Could find field : " + relDataTypeField.getName());
+ e.printStackTrace();
+ }
+ values[index++] = convert(rawValue, (Class) javaType);
+ }
+
+ if (values.length == 1) {
+ return values[0];
+ }
+
+ return values;
+ }
+
+ private static Object handlePdxInstanceEntry(
+ List<RelDataTypeField> relDataTypeFields, Object obj) {
+
+ PdxInstance pdxEntry = (PdxInstance) obj;
+
+ Object[] values = new Object[relDataTypeFields.size()];
+
+ int index = 0;
+ for (RelDataTypeField relDataTypeField : relDataTypeFields) {
+ Type javaType = JAVA_TYPE_FACTORY.getJavaClass(relDataTypeField.getType());
+ Object rawValue = pdxEntry.getField(relDataTypeField.getName());
+ values[index++] = convert(rawValue, (Class) javaType);
+ }
+
+ if (values.length == 1) {
+ return values[0];
+ }
+
+ return values;
+ }
+
+ private static Object handleJavaObjectEntry(
+ List<RelDataTypeField> relDataTypeFields, Object obj) {
+
+ Class<?> clazz = obj.getClass();
+ if (relDataTypeFields.size() == 1) {
+ try {
+ Field javaField = clazz.getDeclaredField(relDataTypeFields.get(0).getName());
+ javaField.setAccessible(true);
+ return javaField.get(obj);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ Object[] values = new Object[relDataTypeFields.size()];
+
+ int index = 0;
+ for (RelDataTypeField relDataTypeField : relDataTypeFields) {
+ try {
+ Field javaField = clazz.getDeclaredField(relDataTypeField.getName());
+ javaField.setAccessible(true);
+ values[index++] = javaField.get(obj);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return values;
+ }
+
+ private static Object convert(Object o, Class clazz) {
+ if (o == null) {
+ return null;
+ }
+ Primitive primitive = Primitive.of(clazz);
+ if (primitive != null) {
+ clazz = primitive.boxClass;
+ } else {
+ primitive = Primitive.ofBox(clazz);
+ }
+ if (clazz == null) {
+ // This is in case of nested Objects!
+ if (o instanceof PdxInstance) {
+ return Util.toString(
+ ((PdxInstance) o).getFieldNames(), "PDX[", ",", "]");
+ }
+ return o.toString();
+ }
+ if (clazz.isInstance(o)) {
+ return o;
+ }
+ if (o instanceof Date && primitive != null) {
+ o = ((Date) o).getTime() / DateTimeUtils.MILLIS_PER_DAY;
+ }
+ if (o instanceof Number && primitive != null) {
+ return primitive.number((Number) o);
+ }
+ return o;
+ }
+
+ // Create Relational Type by inferring a Geode entry or response instance.
+ public static RelDataType createRelDataType(Object regionEntry) {
+ JavaTypeFactoryExtImpl typeFactory = new JavaTypeFactoryExtImpl();
+ if (regionEntry instanceof PdxInstance) {
+ return typeFactory.createPdxType((PdxInstance) regionEntry);
+ } else {
+ return typeFactory.createStructType(regionEntry.getClass());
+ }
+ }
+
+}
+
+// End GeodeUtils.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/util/JavaTypeFactoryExtImpl.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/util/JavaTypeFactoryExtImpl.java b/geode/src/main/java/org/apache/calcite/adapter/geode/util/JavaTypeFactoryExtImpl.java
new file mode 100644
index 0000000..ca17342
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/util/JavaTypeFactoryExtImpl.java
@@ -0,0 +1,123 @@
+/*
+ * 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.adapter.geode.util;
+
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.jdbc.JavaRecordType;
+import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
+import org.apache.calcite.rel.type.RelRecordType;
+
+import org.apache.geode.pdx.PdxInstance;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Implementation of {@link JavaTypeFactory}.
+ *
+ * <p><strong>NOTE: This class is experimental and subject to
+ * change/removal without notice</strong>.</p>
+ */
+public class JavaTypeFactoryExtImpl
+ extends JavaTypeFactoryImpl {
+
+ /**
+ * See <a href="http://stackoverflow.com/questions/16966629/what-is-the-difference-between-getfields-and-getdeclaredfields-in-java-reflectio">
+ * the difference between fields and declared fields</a>.
+ */
+ @Override public RelDataType createStructType(Class type) {
+
+ final List<RelDataTypeField> list = new ArrayList<>();
+ for (Field field : type.getDeclaredFields()) {
+ if (!Modifier.isStatic(field.getModifiers())) {
+ // FIXME: watch out for recursion
+ final Type fieldType = field.getType();
+ list.add(
+ new RelDataTypeFieldImpl(
+ field.getName(),
+ list.size(),
+ createType(fieldType)));
+ }
+ }
+ return canonize(new JavaRecordType(list, type));
+ }
+
+ public RelDataType createPdxType(PdxInstance pdxInstance) {
+ final List<RelDataTypeField> list = new ArrayList<>();
+ for (String fieldName : pdxInstance.getFieldNames()) {
+ Object field = pdxInstance.getField(fieldName);
+
+ Type fieldType;
+
+ if (field == null) {
+ fieldType = String.class;
+ } else if (field instanceof PdxInstance) {
+ // Map Nested PDX structures as String. This relates with
+ // GeodeUtils.convert case when clazz is Null.
+ fieldType = Map.class;
+ // RelDataType boza = createPdxType((PdxInstance) field);
+ } else {
+ fieldType = field.getClass();
+ }
+
+ list.add(
+ new RelDataTypeFieldImpl(
+ fieldName,
+ list.size(),
+ createType(fieldType)));
+ }
+
+ return canonize(new RelRecordType(list));
+ }
+
+ // Experimental flattering the nested structures.
+ public RelDataType createPdxType2(PdxInstance pdxInstance) {
+ final List<RelDataTypeField> list = new ArrayList<>();
+ recursiveCreatePdxType(pdxInstance, list, "");
+ return canonize(new RelRecordType(list));
+ }
+
+ private void recursiveCreatePdxType(PdxInstance pdxInstance,
+ List<RelDataTypeField> list, String fieldNamePrefix) {
+
+ for (String fieldName : pdxInstance.getFieldNames()) {
+ Object field = pdxInstance.getField(fieldName);
+ final Type fieldType = field.getClass();
+ if (fieldType instanceof PdxInstance) {
+ recursiveCreatePdxType(
+ (PdxInstance) field, list, fieldNamePrefix + fieldName + ".");
+ } else {
+ list.add(
+ new RelDataTypeFieldImpl(
+ fieldNamePrefix + fieldName,
+ list.size(),
+ createType(fieldType)));
+ }
+ }
+ }
+
+}
+
+// End JavaTypeFactoryExtImpl.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/main/java/org/apache/calcite/adapter/geode/util/package-info.java
----------------------------------------------------------------------
diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/util/package-info.java b/geode/src/main/java/org/apache/calcite/adapter/geode/util/package-info.java
new file mode 100644
index 0000000..b876717
--- /dev/null
+++ b/geode/src/main/java/org/apache/calcite/adapter/geode/util/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Query provider based on Apache Geode (Gemfire) In Memory Data Grid
+ */
+@PackageMarker
+package org.apache.calcite.adapter.geode.util;
+
+import org.apache.calcite.avatica.util.PackageMarker;
+
+// End package-info.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/java/org/apache/calcite/adapter/geode/rel/BaseGeodeAdapterIT.java
----------------------------------------------------------------------
diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/BaseGeodeAdapterIT.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/BaseGeodeAdapterIT.java
new file mode 100644
index 0000000..cdec337
--- /dev/null
+++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/BaseGeodeAdapterIT.java
@@ -0,0 +1,168 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.linq4j.function.Function1;
+
+import org.junit.Assert;
+
+import java.io.PrintStream;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Geode Adapter IT Test
+ */
+public class BaseGeodeAdapterIT {
+
+ /**
+ * Returns a function that checks the contents of a result set against an
+ * expected string.
+ */
+ private static Function1<ResultSet, Void> expect(final String... expected) {
+ return new Function1<ResultSet, Void>() {
+ public Void apply(ResultSet resultSet) {
+ try {
+ final List<String> lines = new ArrayList<>();
+ BaseGeodeAdapterIT.collect(lines, resultSet);
+ Assert.assertEquals(Arrays.asList(expected), lines);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+ };
+ }
+
+ private static void collect(List<String> result, ResultSet resultSet)
+ throws SQLException {
+ final StringBuilder buf = new StringBuilder();
+ while (resultSet.next()) {
+ buf.setLength(0);
+ int n = resultSet.getMetaData().getColumnCount();
+ String sep = "";
+ for (int i = 1; i <= n; i++) {
+ buf.append(sep)
+ .append(resultSet.getMetaData().getColumnLabel(i))
+ .append("=")
+ .append(resultSet.getString(i));
+ sep = "; ";
+ }
+ result.add(toLinux(buf.toString()));
+ }
+ }
+
+ public static String toLinux(String s) {
+ return s.replaceAll("\r\n", "\n");
+ }
+
+ protected void checkSql(String model, String sql) throws SQLException {
+ checkSql(sql, model, output());
+ }
+
+ protected Function1<ResultSet, Void> output() {
+ return new Function1<ResultSet, Void>() {
+ public Void apply(ResultSet resultSet) {
+ try {
+ output(resultSet, System.out);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+ };
+ }
+
+ protected void checkSql(String model, String sql, final String... expected)
+ throws SQLException {
+ checkSql(sql, model, expect(expected));
+ }
+
+ protected void checkSql(String sql, String model, Function1<ResultSet, Void> fn)
+ throws SQLException {
+ Connection connection = null;
+ Statement statement = null;
+ try {
+ Properties info = new Properties();
+ info.put("model", jsonPath(model));
+ connection = DriverManager.getConnection("jdbc:calcite:", info);
+ statement = connection.createStatement();
+ final ResultSet resultSet = statement.executeQuery(sql);
+ fn.apply(resultSet);
+ } finally {
+ close(connection, statement);
+ }
+ }
+
+ private String jsonPath(String model) {
+ return resourcePath(model + ".json");
+ }
+
+ private String resourcePath(String path) {
+ final URL url = GeodeAdapterIT.class.getResource("/" + path);
+ String s = url.toString();
+ if (s.startsWith("file:")) {
+ s = s.substring("file:".length());
+ }
+ return s;
+ }
+
+ private void output(ResultSet resultSet, PrintStream out)
+ throws SQLException {
+ final ResultSetMetaData metaData = resultSet.getMetaData();
+ final int columnCount = metaData.getColumnCount();
+ while (resultSet.next()) {
+ for (int i = 1; true; i++) {
+ out.print(resultSet.getString(i));
+ if (i < columnCount) {
+ out.print(", ");
+ } else {
+ out.println();
+ break;
+ }
+ }
+ }
+ }
+
+ private void close(Connection connection, Statement statement) {
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (SQLException e) {
+ // ignore
+ }
+ }
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ // ignore
+ }
+ }
+ }
+}
+
+// End BaseGeodeAdapterIT.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeAdapterBookshopIT.java
----------------------------------------------------------------------
diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeAdapterBookshopIT.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeAdapterBookshopIT.java
new file mode 100644
index 0000000..ba5db45
--- /dev/null
+++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeAdapterBookshopIT.java
@@ -0,0 +1,468 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.test.CalciteAssert;
+import org.apache.calcite.util.Util;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.junit.Test;
+
+/**
+ * Tests for the {@code org.apache.calcite.adapter.geode} package.
+ *
+ * <p>Before calling this rel, you need to populate Geode, as follows:
+ *
+ * <blockquote><code>
+ * git clone https://github.com/vlsi/calcite-test-dataset<br>
+ * cd calcite-rel-dataset<br>
+ * mvn install
+ * </code></blockquote>
+ *
+ * <p>This will create a virtual machine with Geode and the "bookshop"
+ * and "zips" rel dataset.
+ */
+public class GeodeAdapterBookshopIT {
+ /**
+ * Connection factory based on the "geode relational " model.
+ */
+ public static final ImmutableMap<String, String> GEODE =
+ ImmutableMap.of("model",
+ GeodeAdapterBookshopIT.class.getResource("/model-bookshop.json")
+ .getPath());
+
+
+ /**
+ * Whether to run Geode tests. Enabled by default, however rel is only
+ * included if "it" profile is activated ({@code -Pit}). To disable,
+ * specify {@code -Dcalcite.rel.geode=false} on the Java command line.
+ */
+ public static final boolean ENABLED = Util.getBooleanProperty("calcite.rel.geode", true);
+
+ /**
+ * Whether to run this rel.
+ */
+ protected boolean enabled() {
+ return ENABLED;
+ }
+
+ @Test
+ public void testSelect() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select * from \"BookMaster\"")
+ .returnsCount(3);
+ }
+
+ @Test
+ public void testWhereEqual() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select * from \"BookMaster\" WHERE \"itemNumber\" = 123")
+ .returnsCount(1)
+ .returns("itemNumber=123; description=Run on sentences and drivel on all things mundane;"
+ + " retailCost=34.99; yearPublished=2011; author=Daisy Mae West; title=A Treatise of "
+ + "Treatises\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeFilterRel(condition=[=(CAST($0):INTEGER, 123)])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])");
+ }
+
+ @Test
+ public void testWhereWithAnd() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select * from \"BookMaster\" WHERE \"itemNumber\" > 122 "
+ + "AND \"itemNumber\" <= 123")
+ .returnsCount(1)
+ .returns("itemNumber=123; description=Run on sentences and drivel on all things mundane; "
+ + "retailCost=34.99; yearPublished=2011; author=Daisy Mae West; title=A Treatise of "
+ + "Treatises\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeFilterRel(condition=[AND(>($0, 122), <=($0, 123))])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])");
+ }
+
+ @Test
+ public void testWhereWithOr() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"author\" from \"BookMaster\" "
+ + "WHERE \"itemNumber\" = 123 OR \"itemNumber\" = 789")
+ .returnsCount(2)
+ .returnsUnordered("author=Jim Heavisides", "author=Daisy Mae West")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(author=[$4])\n"
+ + " GeodeFilterRel(condition=[OR(=(CAST($0):INTEGER, 123), "
+ + "=(CAST($0):INTEGER, 789))])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testWhereWithAndOr() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("SELECT \"author\" from \"BookMaster\" "
+ + "WHERE (\"itemNumber\" > 123 AND \"itemNumber\" = 789) "
+ + "OR \"author\"='Daisy Mae West'")
+ .returnsCount(2)
+ .returnsUnordered("author=Jim Heavisides", "author=Daisy Mae West")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(author=[$4])\n"
+ + " GeodeFilterRel(condition=[OR(AND(>($0, 123), =(CAST($0):INTEGER, 789)), "
+ + "=(CAST($4):VARCHAR CHARACTER SET \"ISO-8859-1\" "
+ + "COLLATE \"ISO-8859-1$en_US$primary\", 'Daisy Mae West'))])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n"
+ + "\n");
+ }
+
+ // TODO: Not supported YET
+ @Test
+ public void testWhereWithOrAnd() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("SELECT \"author\" from \"BookMaster\" "
+ + "WHERE (\"itemNumber\" > 100 OR \"itemNumber\" = 789) "
+ + "AND \"author\"='Daisy Mae West'")
+ .returnsCount(1)
+ .returnsUnordered("author=Daisy Mae West")
+ .explainContains("");
+ }
+
+ @Test
+ public void testProjectionsAndWhereGreatThan() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"author\" from \"BookMaster\" WHERE \"itemNumber\" > 123")
+ .returnsCount(2)
+ .returns("author=Clarence Meeks\n"
+ + "author=Jim Heavisides\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(author=[$4])\n"
+ + " GeodeFilterRel(condition=[>($0, 123)])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])");
+ }
+
+ @Test
+ public void testLimit() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select * from \"BookMaster\" LIMIT 1")
+ .returnsCount(1)
+ .returns("itemNumber=123; description=Run on sentences and drivel on all things mundane; "
+ + "retailCost=34.99; yearPublished=2011; author=Daisy Mae West; title=A Treatise of "
+ + "Treatises\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeSortRel(fetch=[1])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])");
+ }
+
+ @Test
+ public void testSortWithProjection() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\" from \"BookMaster\" ORDER BY \"yearPublished\" ASC")
+ .returnsCount(3)
+ .returns("yearPublished=1971\n"
+ + "yearPublished=2011\n"
+ + "yearPublished=2011\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeSortRel(sort0=[$0], dir0=[ASC])\n"
+ + " GeodeProjectRel(yearPublished=[$3])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testSortWithProjectionAndLimit() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\" from \"BookMaster\" ORDER BY \"yearPublished\" "
+ + "LIMIT 2")
+ .returnsCount(2)
+ .returns("yearPublished=1971\n"
+ + "yearPublished=2011\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(yearPublished=[$3])\n"
+ + " GeodeSortRel(sort0=[$3], dir0=[ASC], fetch=[2])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testSortBy2Columns() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\", \"itemNumber\" from \"BookMaster\" ORDER BY "
+ + "\"yearPublished\" ASC, \"itemNumber\" DESC")
+ .returnsCount(3)
+ .returns("yearPublished=1971; itemNumber=456\n"
+ + "yearPublished=2011; itemNumber=789\n"
+ + "yearPublished=2011; itemNumber=123\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(yearPublished=[$3], itemNumber=[$0])\n"
+ + " GeodeSortRel(sort0=[$3], sort1=[$0], dir0=[ASC], dir1=[DESC])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ //
+ // TEST Group By and Aggregation Function Support
+ //
+
+ /**
+ * OQL Error: Query contains group by columns not present in projected fields
+ * Solution: Automatically expand the projections to include all missing GROUP By columns.
+ */
+ @Test
+ public void testAddMissingGroupByColumnToProjectedFields() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\" from \"BookMaster\" GROUP BY \"yearPublished\", "
+ + "\"author\"")
+ .returnsCount(3)
+ .returns("yearPublished=1971\n"
+ + "yearPublished=2011\n"
+ + "yearPublished=2011\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(yearPublished=[$0])\n"
+ + " GeodeAggregateRel(group=[{3, 4}])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])");
+ }
+
+ /**
+ * When the group by columns match the projected fields, the optimizers removes the projected
+ * relation.
+ */
+ @Test
+ public void testMissingProjectRelationOnGroupByColumnMatchingProjectedFields() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\" from \"BookMaster\" GROUP BY \"yearPublished\"")
+ .returnsCount(2)
+ .returns("yearPublished=1971\n"
+ + "yearPublished=2011\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{3}])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])");
+ }
+
+ /**
+ * When the group by columns match the projected fields, the optimizers removes the projected
+ * relation.
+ */
+ @Test
+ public void testMissingProjectRelationOnGroupByColumnMatchingProjectedFields2() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\", MAX(\"retailCost\") from \"BookMaster\" GROUP BY "
+ + "\"yearPublished\"")
+ .returnsCount(2)
+ .returns("yearPublished=1971; EXPR$1=11.99\n"
+ + "yearPublished=2011; EXPR$1=59.99\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{3}], EXPR$1=[MAX($2)])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])");
+ }
+
+ @Test
+ public void testCount() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select COUNT(\"retailCost\") from \"BookMaster\"")
+ .returnsCount(1)
+ .returns("EXPR$0=3\n")
+ .returnsValue("3")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{}], EXPR$0=[COUNT($2)])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testCountStar() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select COUNT(*) from \"BookMaster\"")
+ .returnsCount(1)
+ .returns("EXPR$0=3\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{}], EXPR$0=[COUNT()])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testCountInGroupBy() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\", COUNT(\"retailCost\") from \"BookMaster\" GROUP BY "
+ + "\"yearPublished\"")
+ .returnsCount(2)
+ .returns("yearPublished=1971; EXPR$1=1\n"
+ + "yearPublished=2011; EXPR$1=2\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{3}], EXPR$1=[COUNT($2)])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testMaxMinSumAvg() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select MAX(\"retailCost\"), MIN(\"retailCost\"), SUM(\"retailCost\"), AVG"
+ + "(\"retailCost\") from \"BookMaster\"")
+ .returnsCount(1)
+ .returns("EXPR$0=59.99; EXPR$1=11.99; EXPR$2=106.97000122070312; "
+ + "EXPR$3=35.65666580200195\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{}], EXPR$0=[MAX($2)], EXPR$1=[MIN($2)], EXPR$2=[SUM($2)"
+ + "], EXPR$3=[AVG($2)])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testMaxMinSumAvgInGroupBy() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\", MAX(\"retailCost\"), MIN(\"retailCost\"), SUM"
+ + "(\"retailCost\"), AVG(\"retailCost\") from \"BookMaster\" "
+ + "GROUP BY \"yearPublished\"")
+ .returnsCount(2)
+ .returns("yearPublished=2011; EXPR$1=59.99; EXPR$2=34.99; EXPR$3=94.9800033569336; "
+ + "EXPR$4=47.4900016784668\n"
+ + "yearPublished=1971; EXPR$1=11.99; EXPR$2=11.99; EXPR$3=11.989999771118164; "
+ + "EXPR$4=11.989999771118164\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{3}], EXPR$1=[MAX($2)], EXPR$2=[MIN($2)], EXPR$3=[SUM($2)"
+ + "], EXPR$4=[AVG($2)])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testGroupBy() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"yearPublished\", MAX(\"retailCost\") AS MAXCOST, \"author\" from "
+ + "\"BookMaster\" GROUP BY \"yearPublished\", \"author\"")
+ .returnsCount(3)
+ .returns("yearPublished=2011; MAXCOST=59.99; author=Jim Heavisides\n"
+ + "yearPublished=1971; MAXCOST=11.99; author=Clarence Meeks\n"
+ + "yearPublished=2011; MAXCOST=34.99; author=Daisy Mae West\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(yearPublished=[$0], MAXCOST=[$2], author=[$1])\n"
+ + " GeodeAggregateRel(group=[{3, 4}], MAXCOST=[MAX($2)])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookMaster]])\n");
+ }
+
+ @Test
+ public void testSelectWithNestedPdx() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select * from \"BookCustomer\" limit 2")
+ .returnsCount(2)
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeSortRel(fetch=[2])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookCustomer]])\n");
+ }
+
+ @Test
+ public void testSelectWithNestedPdx2() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"primaryAddress\" from \"BookCustomer\" limit 2")
+ .returnsCount(2)
+ .returns("primaryAddress=PDX[addressLine1,addressLine2,addressLine3,city,state,"
+ + "postalCode,country,phoneNumber,addressTag]\n"
+ + "primaryAddress=PDX[addressLine1,addressLine2,addressLine3,city,state,postalCode,"
+ + "country,phoneNumber,addressTag]\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(primaryAddress=[$3])\n"
+ + " GeodeSortRel(fetch=[2])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookCustomer]])\n");
+ }
+
+ @Test
+ public void testSelectWithNestedPdxFieldAccess() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"primaryAddress\"['city'] as \"city\" from \"BookCustomer\" limit 2")
+ .returnsCount(2)
+ .returns("city=Topeka\n"
+ + "city=San Francisco\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(city=[ITEM($3, 'city')])\n"
+ + " GeodeSortRel(fetch=[2])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookCustomer]])\n");
+ }
+
+ @Test
+ public void testSelectWithNullFieldValue() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("select \"primaryAddress\"['addressLine2'] from \"BookCustomer\" limit"
+ + " 2")
+ .returnsCount(2)
+ .returns("EXPR$0=null\n"
+ + "EXPR$0=null\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(EXPR$0=[ITEM($3, 'addressLine2')])\n"
+ + " GeodeSortRel(fetch=[2])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookCustomer]])\n");
+ }
+
+ @Test
+ public void testFilterWithNestedField() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE)
+ .query("SELECT \"primaryAddress\"['postalCode'] AS \"postalCode\"\n"
+ + "FROM \"TEST\".\"BookCustomer\"\n"
+ + "WHERE \"primaryAddress\"['postalCode'] > '0'\n")
+ .returnsCount(3)
+ .returns("postalCode=50505\n"
+ + "postalCode=50505\n"
+ + "postalCode=50505\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(postalCode=[ITEM($3, 'postalCode')])\n"
+ + " GeodeFilterRel(condition=[>(ITEM($3, 'postalCode'), '0')])\n"
+ + " GeodeTableScanRel(table=[[TEST, BookCustomer]])\n");
+ }
+
+}
+
+// End GeodeAdapterBookshopIT.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeAdapterIT.java
----------------------------------------------------------------------
diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeAdapterIT.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeAdapterIT.java
new file mode 100644
index 0000000..f416d5e
--- /dev/null
+++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeAdapterIT.java
@@ -0,0 +1,99 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.junit.Test;
+
+import java.sql.SQLException;
+
+/**
+ * Tests for the {@code org.apache.calcite.adapter.geode} package.
+ *
+ * <p>Before calling this rel, you need to populate Geode, as follows:
+ *
+ * <blockquote><code>
+ * git clone https://github.com/vlsi/calcite-test-dataset<br>
+ * cd calcite-rel-dataset<br>
+ * mvn install
+ * </code></blockquote>
+ *
+ * <p>This will create a virtual machine with Geode and the "bookshop" and "zips" rel dataset.
+ */
+public class GeodeAdapterIT extends BaseGeodeAdapterIT {
+
+ @Test
+ public void testSqlSimple() throws SQLException {
+ checkSql("model-bookshop", "SELECT \"itemNumber\" "
+ + "FROM \"BookMaster\" WHERE \"itemNumber\" > 123");
+ }
+
+ @Test
+ public void testSqlSingleNumberWhereFilter() throws SQLException {
+ checkSql("model-bookshop", "SELECT * FROM \"BookMaster\" "
+ + "WHERE \"itemNumber\" = 123");
+ }
+
+ @Test
+ public void testSqlDistinctSort() throws SQLException {
+ checkSql("model-bookshop", "SELECT DISTINCT \"itemNumber\", \"author\" "
+ + "FROM \"BookMaster\" ORDER BY \"itemNumber\", \"author\"");
+ }
+
+ @Test
+ public void testSqlDistinctSort2() throws SQLException {
+ checkSql("model-bookshop", "SELECT \"itemNumber\", \"author\" "
+ + "FROM \"BookMaster\" GROUP BY \"itemNumber\", \"author\" ORDER BY \"itemNumber\", "
+ + "\"author\"");
+ }
+
+ @Test
+ public void testSqlDistinctSort3() throws SQLException {
+ checkSql("model-bookshop", "SELECT DISTINCT * FROM \"BookMaster\"");
+ }
+
+
+ @Test
+ public void testSqlLimit2() throws SQLException {
+ checkSql("model-bookshop", "SELECT DISTINCT * FROM \"BookMaster\" LIMIT 2");
+ }
+
+
+ @Test
+ public void testSqlDisjunciton() throws SQLException {
+ checkSql("model-bookshop", "SELECT \"author\" FROM \"BookMaster\" "
+ + "WHERE \"itemNumber\" = 789 OR \"itemNumber\" = 123");
+ }
+
+ @Test
+ public void testSqlConjunciton() throws SQLException {
+ checkSql("model-bookshop", "SELECT \"author\" FROM \"BookMaster\" "
+ + "WHERE \"itemNumber\" = 789 AND \"author\" = 'Jim Heavisides'");
+ }
+
+ @Test
+ public void testSqlBookMasterWhere() throws SQLException {
+ checkSql("model-bookshop", "select \"author\", \"title\" from \"BookMaster\" "
+ + "WHERE \"author\" = \'Jim Heavisides\' LIMIT 2");
+ }
+
+ @Test
+ public void testSqlBookMasterCount() throws SQLException {
+ checkSql("model-bookshop", "select count(*) from \"BookMaster\"");
+ }
+}
+
+// End GeodeAdapterIT.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsIT.java
----------------------------------------------------------------------
diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsIT.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsIT.java
new file mode 100644
index 0000000..e465393
--- /dev/null
+++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsIT.java
@@ -0,0 +1,199 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.apache.calcite.test.CalciteAssert;
+import org.apache.calcite.util.Util;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.junit.Test;
+
+/**
+ * Tests for the {@code org.apache.calcite.adapter.geode} package.
+ *
+ * <p>Before calling this rel, you need to populate Geode, as follows:
+ *
+ * <blockquote><code>
+ * git clone https://github.com/vlsi/calcite-test-dataset<br>
+ * cd calcite-rel-dataset<br>
+ * mvn install
+ * </code></blockquote>
+ *
+ * <p>This will create a virtual machine with Geode and the "bookshop" and "zips" rel dataset.
+ */
+public class GeodeZipsIT {
+ /**
+ * Connection factory based on the "geode relational " model.
+ */
+ public static final ImmutableMap<String, String> GEODE_ZIPS =
+ ImmutableMap.of("CONFORMANCE", "LENIENT", "model",
+ GeodeZipsIT.class.getResource("/model-zips.json")
+ .getPath());
+
+
+ /**
+ * Whether to run Geode tests. Enabled by default, however rel is only
+ * included if "it" profile is activated ({@code -Pit}). To disable,
+ * specify {@code -Dcalcite.rel.geode=false} on the Java command line.
+ */
+ public static final boolean ENABLED = Util.getBooleanProperty("calcite.rel.geode", true);
+
+ /**
+ * Whether to run this rel.
+ */
+ protected boolean enabled() {
+ return ENABLED;
+ }
+
+
+ @Test
+ public void testGroupByView() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT \"state\", SUM(\"pop\") FROM \"geode\".\"ZIPS\" GROUP BY \"state\"")
+ .returnsCount(51)
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{1}], EXPR$1=[SUM($0)])\n"
+ + " GeodeProjectRel(pop=[CAST($3):INTEGER], state=[CAST($4):VARCHAR(2) CHARACTER SET"
+ + " \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+ }
+
+ @Test
+ public void testGroupByViewWithAliases() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT \"state\" as \"st\", SUM(\"pop\") \"po\" "
+ + "FROM \"geode\".\"ZIPS\" GROUP BY "
+ + "\"state\"")
+ .returnsCount(51)
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{1}], po=[SUM($0)])\n"
+ + " GeodeProjectRel(pop=[CAST($3):INTEGER], state=[CAST($4):VARCHAR(2) CHARACTER SET"
+ + " \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+ }
+
+ @Test
+ public void testGroupByRaw() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT \"state\" as \"st\", SUM(\"pop\") \"po\" "
+ + "FROM \"geode_raw\".\"Zips\" GROUP"
+ + " BY \"state\"")
+ .returnsCount(51)
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{4}], po=[SUM($3)])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+ }
+
+ @Test
+ public void testGroupByRawWithAliases() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT \"state\" AS \"st\", SUM(\"pop\") AS \"po\" "
+ + "FROM \"geode_raw\".\"Zips\" "
+ + "GROUP BY \"state\"")
+ .returnsCount(51)
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{4}], po=[SUM($3)])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+ }
+
+ @Test
+ public void testMaxRaw() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT MAX(\"pop\") FROM \"geode_raw\".\"Zips\"")
+ .returnsCount(1)
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeAggregateRel(group=[{}], EXPR$0=[MAX($3)])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+ }
+
+ @Test
+ public void testJoin() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT \"r\".\"_id\" FROM \"geode_raw\".\"Zips\" AS \"v\" JOIN \"geode_raw\""
+ + ".\"Zips\" AS \"r\" ON \"v\".\"_id\" = \"r\".\"_id\" LIMIT 1")
+ .returnsCount(1)
+ .explainContains("PLAN=EnumerableCalc(expr#0..2=[{inputs}], _id1=[$t0])\n"
+ + " EnumerableLimit(fetch=[1])\n"
+ + " EnumerableJoin(condition=[=($1, $2)], joinType=[inner])\n"
+ + " GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(_id=[$0], _id0=[CAST($0):VARCHAR CHARACTER SET "
+ + "\"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n"
+ + " GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(_id0=[CAST($0):VARCHAR CHARACTER SET \"ISO-8859-1\" COLLATE "
+ + "\"ISO-8859-1$en_US$primary\"])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+ }
+
+ @Test
+ public void testSelectLocItem() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT \"loc\"[0] as \"lat\", \"loc\"[1] as \"lon\" "
+ + "FROM \"geode_raw\".\"Zips\" LIMIT 1")
+ .returnsCount(1)
+ .returns("lat=-74.700748; lon=41.65158\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n"
+ + " GeodeSortRel(fetch=[1])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+ }
+
+ @Test
+ public void testItemPredicate() {
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT \"loc\"[0] as \"lat\", \"loc\"[1] as \"lon\" "
+ + "FROM \"geode_raw\".\"Zips\" WHERE \"loc\"[0] < 0 LIMIT 1")
+ .returnsCount(1)
+ .returns("lat=-74.700748; lon=41.65158\n")
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n"
+ + " GeodeSortRel(fetch=[1])\n"
+ + " GeodeFilterRel(condition=[<(ITEM($2, 0), 0)])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+
+ CalciteAssert.that()
+ .enable(enabled())
+ .with(GEODE_ZIPS)
+ .query("SELECT \"loc\"[0] as \"lat\", \"loc\"[1] as \"lon\" "
+ + "FROM \"geode_raw\".\"Zips\" WHERE \"loc\"[0] > 0 LIMIT 1")
+ .returnsCount(0)
+ .explainContains("PLAN=GeodeToEnumerableConverterRel\n"
+ + " GeodeProjectRel(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n"
+ + " GeodeSortRel(fetch=[1])\n"
+ + " GeodeFilterRel(condition=[>(ITEM($2, 0), 0)])\n"
+ + " GeodeTableScanRel(table=[[geode_raw, Zips]])\n");
+ }
+}
+
+// End GeodeZipsIT.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/java/org/apache/calcite/adapter/geode/rel/RelationalJdbcExample.java
----------------------------------------------------------------------
diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/RelationalJdbcExample.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/RelationalJdbcExample.java
new file mode 100644
index 0000000..5afda9b
--- /dev/null
+++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/RelationalJdbcExample.java
@@ -0,0 +1,103 @@
+/*
+ * 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.adapter.geode.rel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Statement;
+import java.util.Properties;
+
+/**
+ * Example of using Geode via JDBC.
+ *
+ * <p>Before using this example, you need to populate Geode, as follows:
+ *
+ * <blockquote><code>
+ * git clone https://github.com/vlsi/calcite-test-dataset<br>
+ * cd calcite-test-dataset<br>
+ * mvn install
+ * </code></blockquote>
+ *
+ * <p>This will create a virtual machine with Geode and the "bookshop" and "zips"
+ * test data sets.
+ */
+public class RelationalJdbcExample {
+
+ protected static final Logger LOGGER = LoggerFactory.getLogger(
+ RelationalJdbcExample.class.getName());
+
+ private RelationalJdbcExample() {
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ final String geodeModelJson =
+ "inline:"
+ + "{\n"
+ + " version: '1.0',\n"
+ + " schemas: [\n"
+ + " {\n"
+ + " type: 'custom',\n"
+ + " name: 'TEST',\n"
+ + " factory: 'org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory',\n"
+ + " operand: {\n"
+ + " locatorHost: 'localhost', \n"
+ + " locatorPort: '10334', \n"
+ + " regions: 'BookMaster,BookCustomer,BookInventory,BookOrder', \n"
+ + " pdxSerializablePackagePath: 'org.apache.calcite.adapter.geode.domain.*' \n"
+ + " }\n"
+ + " }\n"
+ + " ]\n"
+ + "}";
+
+ Class.forName("org.apache.calcite.jdbc.Driver");
+
+ Properties info = new Properties();
+ info.put("model", geodeModelJson);
+
+ Connection connection = DriverManager.getConnection("jdbc:calcite:", info);
+
+ Statement statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery(
+ "SELECT \"b\".\"author\", \"b\".\"retailCost\", \"i\".\"quantityInStock\"\n"
+ + "FROM \"TEST\".\"BookMaster\" AS \"b\" "
+ + " INNER JOIN \"TEST\".\"BookInventory\" AS \"i\""
+ + " ON \"b\".\"itemNumber\" = \"i\".\"itemNumber\"\n "
+ + "WHERE \"b\".\"retailCost\" > 0");
+
+ final StringBuilder buf = new StringBuilder();
+ while (resultSet.next()) {
+ ResultSetMetaData metaData = resultSet.getMetaData();
+ for (int i = 1; i <= metaData.getColumnCount(); i++) {
+ buf.append(i > 1 ? "; " : "")
+ .append(metaData.getColumnLabel(i)).append("=").append(resultSet.getObject(i));
+ }
+ LOGGER.info("Result entry: " + buf.toString());
+ buf.setLength(0);
+ }
+ resultSet.close();
+ statement.close();
+ connection.close();
+ }
+}
+
+// End RelationalJdbcExample.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/java/org/apache/calcite/adapter/geode/simple/BookMasterRegionTest.java
----------------------------------------------------------------------
diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/simple/BookMasterRegionTest.java b/geode/src/test/java/org/apache/calcite/adapter/geode/simple/BookMasterRegionTest.java
new file mode 100644
index 0000000..8bff14f
--- /dev/null
+++ b/geode/src/test/java/org/apache/calcite/adapter/geode/simple/BookMasterRegionTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.adapter.geode.simple;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.client.ClientCacheFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+import org.apache.geode.cache.query.QueryService;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.pdx.ReflectionBasedAutoSerializer;
+
+/**
+ *
+ */
+public class BookMasterRegionTest {
+
+ private BookMasterRegionTest() {
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ ClientCache clientCache = new ClientCacheFactory()
+ .addPoolLocator("localhost", 10334)
+ .setPdxSerializer(new ReflectionBasedAutoSerializer("org.apache.calcite.adapter.geode.*"))
+ .create();
+
+ // Using Key/Value
+ Region bookMaster = clientCache
+ .createClientRegionFactory(ClientRegionShortcut.PROXY)
+ .create("BookMaster");
+
+ System.out.println("BookMaster = " + bookMaster.get(789));
+
+ // Using OQL
+ QueryService queryService = clientCache.getQueryService();
+ String oql = "select itemNumber, description, retailCost from /BookMaster";
+ SelectResults result = (SelectResults) queryService.newQuery(oql).execute();
+ System.out.println(result.asList());
+ }
+}
+
+// End BookMasterRegionTest.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/java/org/apache/calcite/adapter/geode/simple/SimpleJdbcExample.java
----------------------------------------------------------------------
diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/simple/SimpleJdbcExample.java b/geode/src/test/java/org/apache/calcite/adapter/geode/simple/SimpleJdbcExample.java
new file mode 100644
index 0000000..795a531
--- /dev/null
+++ b/geode/src/test/java/org/apache/calcite/adapter/geode/simple/SimpleJdbcExample.java
@@ -0,0 +1,95 @@
+/*
+ * 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.adapter.geode.simple;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Properties;
+
+/**
+ * Example of using Geode via JDBC.
+ */
+public class SimpleJdbcExample {
+
+ protected static final Logger LOGGER =
+ LoggerFactory.getLogger(SimpleJdbcExample.class.getName());
+
+ private SimpleJdbcExample() {
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ Properties info = new Properties();
+ final String model = "inline:"
+ + "{\n"
+ + " version: '1.0',\n"
+ + " schemas: [\n"
+ + " {\n"
+ + " type: 'custom',\n"
+ + " name: 'TEST',\n"
+ + " factory: 'org.apache.calcite.adapter.geode.simple"
+ + ".GeodeSimpleSchemaFactory',\n"
+ + " operand: {\n"
+ + " locatorHost: 'localhost',\n"
+ + " locatorPort: '10334',\n"
+ + " regions: 'BookMaster',\n"
+ + " pdxSerializablePackagePath: 'org.apache.calcite.adapter.geode.domain.*'\n"
+ + " }\n"
+ + " }\n"
+ + " ]\n"
+ + "}";
+ info.put("model", model);
+
+ Class.forName("org.apache.calcite.jdbc.Driver");
+
+ Connection connection = DriverManager.getConnection("jdbc:calcite:", info);
+
+ Statement statement = connection.createStatement();
+
+ ResultSet resultSet = statement.executeQuery("SELECT * FROM \"TEST\".\"BookMaster\"");
+
+ final StringBuilder buf = new StringBuilder();
+
+ while (resultSet.next()) {
+
+ int columnCount = resultSet.getMetaData().getColumnCount();
+
+ for (int i = 1; i <= columnCount; i++) {
+
+ buf.append(i > 1 ? "; " : "")
+ .append(resultSet.getMetaData().getColumnLabel(i))
+ .append("=")
+ .append(resultSet.getObject(i));
+ }
+
+ LOGGER.info("Entry: " + buf.toString());
+
+ buf.setLength(0);
+ }
+
+ resultSet.close();
+ statement.close();
+ connection.close();
+ }
+}
+
+// End SimpleJdbcExample.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/resources/model-bookshop-all.json
----------------------------------------------------------------------
diff --git a/geode/src/test/resources/model-bookshop-all.json b/geode/src/test/resources/model-bookshop-all.json
new file mode 100644
index 0000000..13ed2e5
--- /dev/null
+++ b/geode/src/test/resources/model-bookshop-all.json
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * A JSON model of a simple Calcite schema.
+ */
+{
+ "version": "1.0",
+ "defaultSchema": "TEST",
+ "schemas": [
+ {
+ "name": "TEST",
+ "type": "custom",
+ "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory",
+ "operand": {
+ "locatorHost": "localhost",
+ "locatorPort": "10334",
+ "regions": "BookMaster,BookCustomer,BookOrder,BookInventory",
+ "pdxSerializablePackagePath": "org.apache.calcite.adapter.geode.domain.bookshop.*"
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/resources/model-bookshop.json
----------------------------------------------------------------------
diff --git a/geode/src/test/resources/model-bookshop.json b/geode/src/test/resources/model-bookshop.json
new file mode 100644
index 0000000..aaab978
--- /dev/null
+++ b/geode/src/test/resources/model-bookshop.json
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * A JSON model of a simple Calcite schema.
+ */
+{
+ "version": "1.0",
+ "defaultSchema": "TEST",
+ "schemas": [
+ {
+ "name": "TEST",
+ "type": "custom",
+ "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory",
+ "operand": {
+ "locatorHost": "localhost",
+ "locatorPort": "10334",
+ "regions": "BookMaster,BookCustomer",
+ "pdxSerializablePackagePath": "org.apache.calcite.adapter.geode.*"
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/resources/model-geode-pg-federation.json
----------------------------------------------------------------------
diff --git a/geode/src/test/resources/model-geode-pg-federation.json b/geode/src/test/resources/model-geode-pg-federation.json
new file mode 100644
index 0000000..586fafa
--- /dev/null
+++ b/geode/src/test/resources/model-geode-pg-federation.json
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ *
+ * A JSON model of a simple Calcite schema.
+ */
+{
+ "version": "1.0",
+ "defaultSchema": "geode",
+ "schemas": [
+ {
+ "type": "custom",
+ "name": "geode_zips",
+ "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory",
+ "operand": {
+ "locatorHost": "localhost",
+ "locatorPort": "10334",
+ "regions": "Zips",
+ "pdxSerializablePackagePath": ".*"
+ }
+ },
+ {
+ "type": "jdbc",
+ "name": "mysql_foodmart",
+ "jdbcUser": "foodmart",
+ "jdbcPassword": "foodmart",
+ "jdbcUrl": "jdbc:mysql://localhost",
+ "jdbcCatalog": "foodmart",
+ "jdbcSchema": null
+ },
+ {
+ "type": "jdbc",
+ "name": "postgresql_foodmart",
+ "jdbcUser": "foodmart",
+ "jdbcPassword": "foodmart",
+ "jdbcDriver": "org.postgresql.Driver",
+ "jdbcUrl": "jdbc:postgresql://localhost/foodmart",
+ "jdbcCatalog": "foodmart",
+ "jdbcSchema": null
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/resources/model-with-classes.json
----------------------------------------------------------------------
diff --git a/geode/src/test/resources/model-with-classes.json b/geode/src/test/resources/model-with-classes.json
new file mode 100644
index 0000000..b776f0e
--- /dev/null
+++ b/geode/src/test/resources/model-with-classes.json
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ * A JSON model of a simple Calcite schema.
+ */
+{
+ "version": "1.0",
+ "defaultSchema": "TEST",
+ "schemas": [
+ {
+ "name": "TEST",
+ "type": "custom",
+ "factory": "org.apache.calcite.adapter.geode.simple.GeodeSchemaFactory",
+ "operand": {
+ "locatorHost": "localhost",
+ "locatorPort": "10334",
+ "regions": "BookMaster,Customer,InventoryItem,BookOrder",
+ "BookMaster": "net.tzolov.geode.bookstore.domain.BookMaster",
+ "Customer": "net.tzolov.geode.bookstore.domain.Customer",
+ "InventoryItem": "net.tzolov.geode.bookstore.domain.InventoryItem",
+ "BookOrder": "net.tzolov.geode.bookstore.domain.BookOrder",
+ "pdxSerializablePackagePath": "net.tzolov.geode.bookstore.domain.*"
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/resources/model-zips.json
----------------------------------------------------------------------
diff --git a/geode/src/test/resources/model-zips.json b/geode/src/test/resources/model-zips.json
new file mode 100644
index 0000000..4077768
--- /dev/null
+++ b/geode/src/test/resources/model-zips.json
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * A JSON model of a simple Calcite schema.
+ */
+{
+ "version": "1.0",
+ "defaultSchema": "geode_raw",
+ "schemas": [
+ {
+ "name": "geode_raw",
+ "type": "custom",
+ "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory",
+ "operand": {
+ "locatorHost": "localhost",
+ "locatorPort": "10334",
+ "regions": "Zips",
+ "pdxSerializablePackagePath": ".*"
+ }
+ },
+ {
+ "name": "geode",
+ "tables": [
+ {
+ "name": "ZIPS",
+ "type": "view",
+ "sql": [
+ "select \"_id\" AS \"id\", \"city\", \"loc\", cast(\"pop\" AS integer) AS \"pop\", cast(\"state\" AS varchar(2)) AS \"state\" from \"geode_raw\".\"Zips\""
+ ]
+ }
+ ]
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/resources/model.json
----------------------------------------------------------------------
diff --git a/geode/src/test/resources/model.json b/geode/src/test/resources/model.json
new file mode 100644
index 0000000..c1a2c86
--- /dev/null
+++ b/geode/src/test/resources/model.json
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * A JSON model of a simple Calcite schema.
+ */
+{
+ "version": "1.0",
+ "defaultSchema": "TEST",
+ "schemas": [
+ {
+ "name": "TEST",
+ "type": "custom",
+ "factory": "org.apache.calcite.adapter.geode.simple.GeodeSchemaFactory",
+ "operand": {
+ "locatorHost": "localhost",
+ "locatorPort": "10334",
+ "regions": "BookMaster",
+ "pdxSerializablePackagePath": "net.tzolov.geode.bookstore.domain.*"
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/geode/src/test/resources/model2.json
----------------------------------------------------------------------
diff --git a/geode/src/test/resources/model2.json b/geode/src/test/resources/model2.json
new file mode 100644
index 0000000..4cbe328
--- /dev/null
+++ b/geode/src/test/resources/model2.json
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * A JSON model of a simple Calcite schema.
+ */
+{
+ "version": "1.0",
+ "defaultSchema": "TEST",
+ "schemas": [
+ {
+ "name": "TEST",
+ "type": "custom",
+ "factory": "org.apache.calcite.adapter.geode.simple.GeodeSchemaFactory",
+ "operand": {
+ "locatorHost": "localhost",
+ "locatorPort": "10334",
+ "regions": "BookMaster,Customer,InventoryItem,BookOrder",
+ "pdxSerializablePackagePath": "net.tzolov.geode.bookstore.domain.*"
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/calcite/blob/707f4de9/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 62d4871..b1c81b8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,6 +75,7 @@ limitations under the License.
<forbiddenapis.version>2.3</forbiddenapis.version>
<freemarker.version>2.3.25-incubating</freemarker.version>
<git-commit-id-plugin.version>2.1.9</git-commit-id-plugin.version>
+ <geode.version>1.3.0</geode.version>
<!-- We support (and test against) Guava versions between
14.0.1 (Hive) and 23.0. Default is 19.0 due to Cassandra adapter.
@@ -152,6 +153,7 @@ limitations under the License.
<module>elasticsearch5</module>
<module>example</module>
<module>file</module>
+ <module>geode</module>
<module>linq4j</module>
<module>mongodb</module>
<module>pig</module>
@@ -340,6 +342,11 @@ limitations under the License.
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.geode</groupId>
+ <artifactId>geode-core</artifactId>
+ <version>${geode.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>${hadoop.version}</version>
[2/7] calcite git commit: In JdbcTest, ensure ResultSet is closed
Posted by jh...@apache.org.
In JdbcTest, ensure ResultSet is closed
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/fd68f251
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/fd68f251
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/fd68f251
Branch: refs/heads/master
Commit: fd68f25135b7f07f724116c715c070cb3990e778
Parents: facd83d
Author: Julian Hyde <jh...@apache.org>
Authored: Sun Dec 24 13:05:59 2017 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Feb 16 10:18:01 2018 -0800
----------------------------------------------------------------------
.../java/org/apache/calcite/test/JdbcTest.java | 103 ++++++++++---------
1 file changed, 54 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/fd68f251/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 b8bffce..ec5118f 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -5365,70 +5365,75 @@ public class JdbcTest {
final DatabaseMetaData metaData = a0.getMetaData();
// all table types
- assertEquals(
- "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=EMPLOYEES; TABLE_TYPE=TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
- + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=MUTABLE_EMPLOYEES; TABLE_TYPE=TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
- + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; TABLE_TYPE=VIEW; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n",
- CalciteAssert.toString(
- metaData.getTables(null, "adhoc", null, null)));
+ try (ResultSet r =
+ metaData.getTables(null, "adhoc", null, null)) {
+ assertEquals(
+ "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=EMPLOYEES; TABLE_TYPE=TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=MUTABLE_EMPLOYEES; TABLE_TYPE=TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; TABLE_TYPE=VIEW; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n",
+ CalciteAssert.toString(r));
+ }
// including system tables; note that table type is "SYSTEM TABLE"
// not "SYSTEM_TABLE"
- assertEquals(
- "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=EMPLOYEES; TABLE_TYPE=TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
- + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=MUTABLE_EMPLOYEES; TABLE_TYPE=TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
- + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; TABLE_TYPE=VIEW; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
- + "TABLE_CAT=null; TABLE_SCHEM=metadata; TABLE_NAME=COLUMNS; TABLE_TYPE=SYSTEM TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
- + "TABLE_CAT=null; TABLE_SCHEM=metadata; TABLE_NAME=TABLES; TABLE_TYPE=SYSTEM TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n",
- CalciteAssert.toString(
- metaData.getTables(null, null, null, null)));
+ try (ResultSet r = metaData.getTables(null, null, null, null)) {
+ assertEquals(
+ "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=EMPLOYEES; TABLE_TYPE=TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=MUTABLE_EMPLOYEES; TABLE_TYPE=TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; TABLE_TYPE=VIEW; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=metadata; TABLE_NAME=COLUMNS; TABLE_TYPE=SYSTEM TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=metadata; TABLE_NAME=TABLES; TABLE_TYPE=SYSTEM TABLE; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n",
+ CalciteAssert.toString(r));
+ }
// views only
- assertEquals(
- "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; TABLE_TYPE=VIEW; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n",
- CalciteAssert.toString(
- metaData.getTables(
- null, "adhoc", null,
- new String[]{
- Schema.TableType.VIEW.jdbcName
- })));
+ try (ResultSet r = metaData.getTables(null, "adhoc", null,
+ new String[]{Schema.TableType.VIEW.jdbcName})) {
+ assertEquals(
+ "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; TABLE_TYPE=VIEW; REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; REF_GENERATION=null\n",
+ CalciteAssert.toString(r));
+ }
// columns
- assertEquals(
- "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=empid; DATA_TYPE=4; TYPE_NAME=JavaType(int) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=1; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n"
- + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=deptno; DATA_TYPE=4; TYPE_NAME=JavaType(int) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=2; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n"
- + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=name; DATA_TYPE=12; TYPE_NAME=JavaType(class java.lang.String); COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=1; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=3; IS_NULLABLE=YES; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n"
- + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=salary; DATA_TYPE=7; TYPE_NAME=JavaType(float) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=4; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n"
- + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=commission; DATA_TYPE=4; TYPE_NAME=JavaType(class java.lang.Integer); COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=1; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=5; IS_NULLABLE=YES; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n",
- CalciteAssert.toString(
- metaData.getColumns(
- null, "adhoc", "V", null)));
+ try (ResultSet r =
+ metaData.getColumns(null, "adhoc", "V", null)) {
+ assertEquals(
+ "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=empid; DATA_TYPE=4; TYPE_NAME=JavaType(int) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=1; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=deptno; DATA_TYPE=4; TYPE_NAME=JavaType(int) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=2; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=name; DATA_TYPE=12; TYPE_NAME=JavaType(class java.lang.String); COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=1; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=3; IS_NULLABLE=YES; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=salary; DATA_TYPE=7; TYPE_NAME=JavaType(float) NOT NULL; COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=0; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=4; IS_NULLABLE=NO; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n"
+ + "TABLE_CAT=null; TABLE_SCHEM=adhoc; TABLE_NAME=V; COLUMN_NAME=commission; DATA_TYPE=4; TYPE_NAME=JavaType(class java.lang.Integer); COLUMN_SIZE=-1; BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; NULLABLE=1; REMARKS=null; COLUMN_DEF=null; SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=5; IS_NULLABLE=YES; SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; IS_GENERATEDCOLUMN=\n",
+ CalciteAssert.toString(r));
+ }
// catalog
- assertEquals(
- "TABLE_CAT=null\n",
- CalciteAssert.toString(
- metaData.getCatalogs()));
+ try (ResultSet r = metaData.getCatalogs()) {
+ assertEquals(
+ "TABLE_CAT=null\n",
+ CalciteAssert.toString(r));
+ }
// schemas
- assertEquals(
- "TABLE_SCHEM=adhoc; TABLE_CATALOG=null\n"
- + "TABLE_SCHEM=metadata; TABLE_CATALOG=null\n",
- CalciteAssert.toString(
- metaData.getSchemas()));
+ try (ResultSet r = metaData.getSchemas()) {
+ assertEquals(
+ "TABLE_SCHEM=adhoc; TABLE_CATALOG=null\n"
+ + "TABLE_SCHEM=metadata; TABLE_CATALOG=null\n",
+ CalciteAssert.toString(r));
+ }
// schemas (qualified)
- assertEquals(
- "TABLE_SCHEM=adhoc; TABLE_CATALOG=null\n",
- CalciteAssert.toString(
- metaData.getSchemas(null, "adhoc")));
+ try (ResultSet r = metaData.getSchemas(null, "adhoc")) {
+ assertEquals(
+ "TABLE_SCHEM=adhoc; TABLE_CATALOG=null\n",
+ CalciteAssert.toString(r));
+ }
// table types
- assertEquals(
- "TABLE_TYPE=TABLE\n"
- + "TABLE_TYPE=VIEW\n",
- CalciteAssert.toString(
- metaData.getTableTypes()));
+ try (ResultSet r = metaData.getTableTypes()) {
+ assertEquals("TABLE_TYPE=TABLE\n"
+ + "TABLE_TYPE=VIEW\n",
+ CalciteAssert.toString(r));
+ }
return null;
} catch (SQLException e) {
[3/7] calcite git commit: [CALCITE-2128] Add SQL dialect for Jethro
Data (Jonathan Doron)
Posted by jh...@apache.org.
[CALCITE-2128] Add SQL dialect for Jethro Data (Jonathan Doron)
Before creating a JethroDataSqlDialect, SqlDialectFactoryImpl issues a
"show functions extended" command to Jethro, storing the results in a
cache for next time, and passes the list of supported functions to the
dialect.
Close apache/calcite#602
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/facd83d3
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/facd83d3
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/facd83d3
Branch: refs/heads/master
Commit: facd83d311098dd3f35294ba969a19cbf6d54467
Parents: 0ced3b7
Author: msydoron <ms...@gmail.com>
Authored: Mon Dec 18 15:30:55 2017 +0200
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Feb 16 10:18:01 2018 -0800
----------------------------------------------------------------------
.../apache/calcite/adapter/jdbc/JdbcRules.java | 148 +++++++-----
.../apache/calcite/adapter/jdbc/JdbcSchema.java | 5 +-
.../apache/calcite/adapter/jdbc/JdbcTable.java | 2 +-
.../calcite/adapter/jdbc/JdbcTableScan.java | 2 +-
.../rules/AbstractJoinExtractFilterRule.java | 85 +++++++
.../rel/rules/JoinExtractFilterRule.java | 49 +---
.../java/org/apache/calcite/sql/SqlDialect.java | 43 +++-
.../apache/calcite/sql/SqlDialectFactory.java | 4 +-
.../calcite/sql/SqlDialectFactoryImpl.java | 21 ++
.../sql/dialect/JethroDataSqlDialect.java | 235 +++++++++++++++++++
.../rel/rel2sql/RelToSqlConverterTest.java | 24 ++
11 files changed, 490 insertions(+), 128 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
index 86b44af..44f9c09 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
@@ -35,6 +35,7 @@ import org.apache.calcite.rel.SingleRel;
import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.Calc;
import org.apache.calcite.rel.core.CorrelationId;
import org.apache.calcite.rel.core.Filter;
import org.apache.calcite.rel.core.Intersect;
@@ -47,16 +48,6 @@ import org.apache.calcite.rel.core.Sort;
import org.apache.calcite.rel.core.TableModify;
import org.apache.calcite.rel.core.Union;
import org.apache.calcite.rel.core.Values;
-import org.apache.calcite.rel.logical.LogicalAggregate;
-import org.apache.calcite.rel.logical.LogicalCalc;
-import org.apache.calcite.rel.logical.LogicalFilter;
-import org.apache.calcite.rel.logical.LogicalIntersect;
-import org.apache.calcite.rel.logical.LogicalJoin;
-import org.apache.calcite.rel.logical.LogicalMinus;
-import org.apache.calcite.rel.logical.LogicalProject;
-import org.apache.calcite.rel.logical.LogicalTableModify;
-import org.apache.calcite.rel.logical.LogicalUnion;
-import org.apache.calcite.rel.logical.LogicalValues;
import org.apache.calcite.rel.metadata.RelMdUtil;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.rel2sql.SqlImplementor;
@@ -121,23 +112,35 @@ public class JdbcRules {
}
/** Rule that converts a join to JDBC. */
- private static class JdbcJoinRule extends JdbcConverterRule {
- private JdbcJoinRule(JdbcConvention out) {
- super(LogicalJoin.class, Convention.NONE, out, "JdbcJoinRule");
+ public static class JdbcJoinRule extends JdbcConverterRule {
+ /** Creates a JdbcJoinRule. */
+ public JdbcJoinRule(JdbcConvention out) {
+ super(Join.class, Convention.NONE, out, "JdbcJoinRule");
}
@Override public RelNode convert(RelNode rel) {
- LogicalJoin join = (LogicalJoin) rel;
+ return convert((Join) rel, true);
+ }
+
+ /**
+ * Converts a {@code Join} into a {@code JdbcJoin}.
+ *
+ * @param join Join operator to convert
+ * @param convertInputTraits Whether to convert input to {@code join}'s
+ * JDBC convention
+ * @return A new JdbcJoin
+ */
+ public RelNode convert(Join join, boolean convertInputTraits) {
final List<RelNode> newInputs = new ArrayList<>();
for (RelNode input : join.getInputs()) {
- if (!(input.getConvention() == getOutTrait())) {
+ if (convertInputTraits && input.getConvention() != getOutTrait()) {
input =
convert(input,
input.getTraitSet().replace(out));
}
newInputs.add(input);
}
- if (!canJoinOnCondition(join.getCondition())) {
+ if (convertInputTraits && !canJoinOnCondition(join.getCondition())) {
return null;
}
try {
@@ -200,7 +203,7 @@ public class JdbcRules {
/** Join operator implemented in JDBC convention. */
public static class JdbcJoin extends Join implements JdbcRel {
/** Creates a JdbcJoin. */
- protected JdbcJoin(RelOptCluster cluster, RelTraitSet traitSet,
+ public JdbcJoin(RelOptCluster cluster, RelTraitSet traitSet,
RelNode left, RelNode right, RexNode condition,
Set<CorrelationId> variablesSet, JoinRelType joinType)
throws InvalidRelException {
@@ -254,16 +257,16 @@ public class JdbcRules {
}
/**
- * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalCalc} to an
+ * Rule to convert a {@link org.apache.calcite.rel.core.Calc} to an
* {@link org.apache.calcite.adapter.jdbc.JdbcRules.JdbcCalc}.
*/
private static class JdbcCalcRule extends JdbcConverterRule {
private JdbcCalcRule(JdbcConvention out) {
- super(LogicalCalc.class, Convention.NONE, out, "JdbcCalcRule");
+ super(Calc.class, Convention.NONE, out, "JdbcCalcRule");
}
public RelNode convert(RelNode rel) {
- final LogicalCalc calc = (LogicalCalc) rel;
+ final Calc calc = (Calc) rel;
// If there's a multiset, let FarragoMultisetSplitter work on it
// first.
@@ -327,16 +330,16 @@ public class JdbcRules {
}
/**
- * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalProject} to
+ * Rule to convert a {@link org.apache.calcite.rel.core.Project} to
* an {@link org.apache.calcite.adapter.jdbc.JdbcRules.JdbcProject}.
*/
- private static class JdbcProjectRule extends JdbcConverterRule {
- private JdbcProjectRule(JdbcConvention out) {
- super(LogicalProject.class, Convention.NONE, out, "JdbcProjectRule");
+ public static class JdbcProjectRule extends JdbcConverterRule {
+ public JdbcProjectRule(JdbcConvention out) {
+ super(Project.class, Convention.NONE, out, "JdbcProjectRule");
}
public RelNode convert(RelNode rel) {
- final LogicalProject project = (LogicalProject) rel;
+ final Project project = (Project) rel;
return new JdbcProject(
rel.getCluster(),
@@ -349,7 +352,7 @@ public class JdbcRules {
}
}
- /** Implementation of {@link org.apache.calcite.rel.logical.LogicalProject} in
+ /** Implementation of {@link org.apache.calcite.rel.core.Project} in
* {@link JdbcConvention jdbc calling convention}. */
public static class JdbcProject
extends Project
@@ -388,16 +391,16 @@ public class JdbcRules {
}
/**
- * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalFilter} to
+ * Rule to convert a {@link org.apache.calcite.rel.core.Filter} to
* an {@link org.apache.calcite.adapter.jdbc.JdbcRules.JdbcFilter}.
*/
- private static class JdbcFilterRule extends JdbcConverterRule {
- private JdbcFilterRule(JdbcConvention out) {
- super(LogicalFilter.class, Convention.NONE, out, "JdbcFilterRule");
+ public static class JdbcFilterRule extends JdbcConverterRule {
+ public JdbcFilterRule(JdbcConvention out) {
+ super(Filter.class, Convention.NONE, out, "JdbcFilterRule");
}
public RelNode convert(RelNode rel) {
- final LogicalFilter filter = (LogicalFilter) rel;
+ final Filter filter = (Filter) rel;
return new JdbcFilter(
rel.getCluster(),
@@ -431,16 +434,16 @@ public class JdbcRules {
}
/**
- * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalAggregate}
+ * Rule to convert a {@link org.apache.calcite.rel.core.Aggregate}
* to a {@link org.apache.calcite.adapter.jdbc.JdbcRules.JdbcAggregate}.
*/
- private static class JdbcAggregateRule extends JdbcConverterRule {
- private JdbcAggregateRule(JdbcConvention out) {
- super(LogicalAggregate.class, Convention.NONE, out, "JdbcAggregateRule");
+ public static class JdbcAggregateRule extends JdbcConverterRule {
+ public JdbcAggregateRule(JdbcConvention out) {
+ super(Aggregate.class, Convention.NONE, out, "JdbcAggregateRule");
}
public RelNode convert(RelNode rel) {
- final LogicalAggregate agg = (LogicalAggregate) rel;
+ final Aggregate agg = (Aggregate) rel;
if (agg.getGroupSets().size() != 1) {
// GROUPING SETS not supported; see
// [CALCITE-734] Push GROUPING SETS to underlying SQL via JDBC adapter
@@ -511,17 +514,36 @@ public class JdbcRules {
* Rule to convert a {@link org.apache.calcite.rel.core.Sort} to an
* {@link org.apache.calcite.adapter.jdbc.JdbcRules.JdbcSort}.
*/
- private static class JdbcSortRule extends JdbcConverterRule {
- private JdbcSortRule(JdbcConvention out) {
+ public static class JdbcSortRule extends JdbcConverterRule {
+ /** Creates a JdbcSortRule. */
+ public JdbcSortRule(JdbcConvention out) {
super(Sort.class, Convention.NONE, out, "JdbcSortRule");
}
public RelNode convert(RelNode rel) {
- final Sort sort = (Sort) rel;
+ return convert((Sort) rel, true);
+ }
+
+ /**
+ * Converts a {@code Sort} into a {@code JdbcSort}.
+ *
+ * @param sort Sort operator to convert
+ * @param convertInputTraits Whether to convert input to {@code sort}'s
+ * JDBC convention
+ * @return A new JdbcSort
+ */
+ public RelNode convert(Sort sort, boolean convertInputTraits) {
final RelTraitSet traitSet = sort.getTraitSet().replace(out);
- return new JdbcSort(rel.getCluster(), traitSet,
- convert(sort.getInput(), traitSet), sort.getCollation(), sort.offset,
- sort.fetch);
+
+ final RelNode input;
+ if (convertInputTraits) {
+ input = convert(sort.getInput(), traitSet);
+ } else {
+ input = sort.getInput();
+ }
+
+ return new JdbcSort(sort.getCluster(), traitSet,
+ input, sort.getCollation(), sort.offset, sort.fetch);
}
}
@@ -553,16 +575,16 @@ public class JdbcRules {
}
/**
- * Rule to convert an {@link org.apache.calcite.rel.logical.LogicalUnion} to a
+ * Rule to convert an {@link org.apache.calcite.rel.core.Union} to a
* {@link org.apache.calcite.adapter.jdbc.JdbcRules.JdbcUnion}.
*/
- private static class JdbcUnionRule extends JdbcConverterRule {
- private JdbcUnionRule(JdbcConvention out) {
- super(LogicalUnion.class, Convention.NONE, out, "JdbcUnionRule");
+ public static class JdbcUnionRule extends JdbcConverterRule {
+ public JdbcUnionRule(JdbcConvention out) {
+ super(Union.class, Convention.NONE, out, "JdbcUnionRule");
}
public RelNode convert(RelNode rel) {
- final LogicalUnion union = (LogicalUnion) rel;
+ final Union union = (Union) rel;
final RelTraitSet traitSet =
union.getTraitSet().replace(out);
return new JdbcUnion(rel.getCluster(), traitSet,
@@ -596,16 +618,16 @@ public class JdbcRules {
}
/**
- * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalIntersect}
+ * Rule to convert a {@link org.apache.calcite.rel.core.Intersect}
* to a {@link org.apache.calcite.adapter.jdbc.JdbcRules.JdbcIntersect}.
*/
- private static class JdbcIntersectRule extends JdbcConverterRule {
+ public static class JdbcIntersectRule extends JdbcConverterRule {
private JdbcIntersectRule(JdbcConvention out) {
- super(LogicalIntersect.class, Convention.NONE, out, "JdbcIntersectRule");
+ super(Intersect.class, Convention.NONE, out, "JdbcIntersectRule");
}
public RelNode convert(RelNode rel) {
- final LogicalIntersect intersect = (LogicalIntersect) rel;
+ final Intersect intersect = (Intersect) rel;
if (intersect.all) {
return null; // INTERSECT ALL not implemented
}
@@ -640,16 +662,16 @@ public class JdbcRules {
}
/**
- * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalMinus} to a
+ * Rule to convert a {@link org.apache.calcite.rel.core.Minus} to a
* {@link org.apache.calcite.adapter.jdbc.JdbcRules.JdbcMinus}.
*/
- private static class JdbcMinusRule extends JdbcConverterRule {
+ public static class JdbcMinusRule extends JdbcConverterRule {
private JdbcMinusRule(JdbcConvention out) {
- super(LogicalMinus.class, Convention.NONE, out, "JdbcMinusRule");
+ super(Minus.class, Convention.NONE, out, "JdbcMinusRule");
}
public RelNode convert(RelNode rel) {
- final LogicalMinus minus = (LogicalMinus) rel;
+ final Minus minus = (Minus) rel;
if (minus.all) {
return null; // EXCEPT ALL not implemented
}
@@ -681,20 +703,16 @@ public class JdbcRules {
/** Rule that converts a table-modification to JDBC. */
public static class JdbcTableModificationRule extends JdbcConverterRule {
private JdbcTableModificationRule(JdbcConvention out) {
- super(
- LogicalTableModify.class,
- Convention.NONE,
- out,
+ super(TableModify.class, Convention.NONE, out,
"JdbcTableModificationRule");
}
@Override public RelNode convert(RelNode rel) {
- final LogicalTableModify modify =
- (LogicalTableModify) rel;
+ final TableModify modify =
+ (TableModify) rel;
final ModifiableTable modifiableTable =
modify.getTable().unwrap(ModifiableTable.class);
- if (modifiableTable == null
- /* || modifiableTable.getExpression(tableInSchema) == null */) {
+ if (modifiableTable == null) {
return null;
}
final RelTraitSet traitSet =
@@ -759,11 +777,11 @@ public class JdbcRules {
/** Rule that converts a values operator to JDBC. */
public static class JdbcValuesRule extends JdbcConverterRule {
private JdbcValuesRule(JdbcConvention out) {
- super(LogicalValues.class, Convention.NONE, out, "JdbcValuesRule");
+ super(Values.class, Convention.NONE, out, "JdbcValuesRule");
}
@Override public RelNode convert(RelNode rel) {
- LogicalValues values = (LogicalValues) rel;
+ Values values = (Values) rel;
return new JdbcValues(values.getCluster(), values.getRowType(),
values.getTuples(), values.getTraitSet().replace(out));
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java
----------------------------------------------------------------------
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 8e7ecdf..eb91b14 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
@@ -104,7 +104,8 @@ public class JdbcSchema implements Schema {
DataSource dataSource,
String catalog,
String schema) {
- return create(parentSchema, name, dataSource, new SqlDialectFactoryImpl(), catalog, schema);
+ return create(parentSchema, name, dataSource,
+ SqlDialectFactoryImpl.INSTANCE, catalog, schema);
}
public static JdbcSchema create(
@@ -174,7 +175,7 @@ public class JdbcSchema implements Schema {
*/
@Deprecated // to be removed before 2.0
public static SqlDialect createDialect(DataSource dataSource) {
- return createDialect(new SqlDialectFactoryImpl(), dataSource);
+ return createDialect(SqlDialectFactoryImpl.INSTANCE, dataSource);
}
/** Returns a suitable SQL dialect for the given data source. */
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
index b093eb2..02b6207 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
@@ -74,7 +74,7 @@ import java.util.List;
* The resulting queryable can then be converted to a SQL query, which can be
* executed efficiently on the JDBC server.</p>
*/
-class JdbcTable extends AbstractQueryableTable
+public class JdbcTable extends AbstractQueryableTable
implements TranslatableTable, ScannableTable, ModifiableTable {
private RelProtoDataType protoRowType;
private final JdbcSchema jdbcSchema;
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java
index 7ef8938..b621b85 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java
@@ -30,7 +30,7 @@ import java.util.List;
* Relational expression representing a scan of a table in a JDBC data source.
*/
public class JdbcTableScan extends TableScan implements JdbcRel {
- final JdbcTable jdbcTable;
+ protected final JdbcTable jdbcTable;
protected JdbcTableScan(
RelOptCluster cluster,
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/rel/rules/AbstractJoinExtractFilterRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AbstractJoinExtractFilterRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AbstractJoinExtractFilterRule.java
new file mode 100644
index 0000000..106aa28
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AbstractJoinExtractFilterRule.java
@@ -0,0 +1,85 @@
+/*
+ * 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.rel.rules;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptRuleOperand;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
+
+/**
+ * Rule to convert an
+ * {@link org.apache.calcite.rel.core.Join inner join} to a
+ * {@link org.apache.calcite.rel.core.Filter filter} on top of a
+ * {@link org.apache.calcite.rel.core.Join cartesian inner join}.
+ *
+ * <p>One benefit of this transformation is that after it, the join condition
+ * can be combined with conditions and expressions above the join. It also makes
+ * the <code>FennelCartesianJoinRule</code> applicable.
+ *
+ * <p>The constructor is parameterized to allow any sub-class of
+ * {@link org.apache.calcite.rel.core.Join}.</p>
+ */
+public abstract class AbstractJoinExtractFilterRule extends RelOptRule {
+ /** Creates an AbstractJoinExtractFilterRule. */
+ protected AbstractJoinExtractFilterRule(RelOptRuleOperand operand,
+ RelBuilderFactory relBuilderFactory, String description) {
+ super(operand, relBuilderFactory, description);
+ }
+
+ public void onMatch(RelOptRuleCall call) {
+ final Join join = call.rel(0);
+
+ if (join.getJoinType() != JoinRelType.INNER) {
+ return;
+ }
+
+ if (join.getCondition().isAlwaysTrue()) {
+ return;
+ }
+
+ if (!join.getSystemFieldList().isEmpty()) {
+ // FIXME Enable this rule for joins with system fields
+ return;
+ }
+
+ final RelBuilder builder = call.builder();
+
+ // NOTE jvs 14-Mar-2006: See JoinCommuteRule for why we
+ // preserve attribute semiJoinDone here.
+
+ final RelNode cartesianJoin =
+ join.copy(
+ join.getTraitSet(),
+ builder.literal(true),
+ join.getLeft(),
+ join.getRight(),
+ join.getJoinType(),
+ join.isSemiJoinDone());
+
+ builder.push(cartesianJoin)
+ .filter(join.getCondition());
+
+ call.transformTo(builder.build());
+ }
+}
+
+// End AbstractJoinExtractFilterRule.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/rel/rules/JoinExtractFilterRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinExtractFilterRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinExtractFilterRule.java
index 8c4a02d..1e7e661 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinExtractFilterRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinExtractFilterRule.java
@@ -16,11 +16,7 @@
*/
package org.apache.calcite.rel.rules;
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Join;
-import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.logical.LogicalJoin;
import org.apache.calcite.tools.RelBuilderFactory;
@@ -39,7 +35,7 @@ import org.apache.calcite.tools.RelBuilderFactory;
* {@link org.apache.calcite.rel.core.Join}, not just
* {@link org.apache.calcite.rel.logical.LogicalJoin}.</p>
*/
-public final class JoinExtractFilterRule extends RelOptRule {
+public final class JoinExtractFilterRule extends AbstractJoinExtractFilterRule {
//~ Static fields/initializers ---------------------------------------------
/** The singleton. */
@@ -50,14 +46,6 @@ public final class JoinExtractFilterRule extends RelOptRule {
//~ Constructors -----------------------------------------------------------
/**
- * Creates an JoinExtractFilterRule.
- */
- @Deprecated // to be removed before 2.0
- public JoinExtractFilterRule(Class<? extends Join> clazz) {
- this(clazz, RelFactories.LOGICAL_BUILDER);
- }
-
- /**
* Creates a JoinExtractFilterRule.
*/
public JoinExtractFilterRule(Class<? extends Join> clazz,
@@ -67,41 +55,6 @@ public final class JoinExtractFilterRule extends RelOptRule {
//~ Methods ----------------------------------------------------------------
- public void onMatch(RelOptRuleCall call) {
- final Join join = call.rel(0);
-
- if (join.getJoinType() != JoinRelType.INNER) {
- return;
- }
-
- if (join.getCondition().isAlwaysTrue()) {
- return;
- }
-
- if (!join.getSystemFieldList().isEmpty()) {
- // FIXME Enable this rule for joins with system fields
- return;
- }
-
- // NOTE jvs 14-Mar-2006: See JoinCommuteRule for why we
- // preserve attribute semiJoinDone here.
-
- RelNode cartesianJoinRel =
- join.copy(
- join.getTraitSet(),
- join.getCluster().getRexBuilder().makeLiteral(true),
- join.getLeft(),
- join.getRight(),
- join.getJoinType(),
- join.isSemiJoinDone());
-
- final RelFactories.FilterFactory factory =
- RelFactories.DEFAULT_FILTER_FACTORY;
- RelNode filterRel =
- factory.createFilter(cartesianJoinRel, join.getCondition());
-
- call.transformTo(filterRel);
- }
}
// End JoinExtractFilterRule.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
index 42cf7b1..07bc60a 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
@@ -23,6 +23,7 @@ import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.sql.dialect.AnsiSqlDialect;
import org.apache.calcite.sql.dialect.CalciteSqlDialect;
+import org.apache.calcite.sql.dialect.JethroDataSqlDialect;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.BasicSqlType;
@@ -157,7 +158,7 @@ public class SqlDialect {
/** Creates an empty context. Use {@link #EMPTY_CONTEXT} if possible. */
protected static Context emptyContext() {
return new ContextImpl(DatabaseProduct.UNKNOWN, null, null, -1, -1, null,
- NullCollation.HIGH);
+ NullCollation.HIGH, JethroDataSqlDialect.JethroInfo.EMPTY);
}
/**
@@ -502,6 +503,12 @@ public class SqlDialect {
return false;
}
+ /** Returns whether this dialect supports a given function or operator. */
+ public boolean supportsFunction(SqlOperator operator, RelDataType type,
+ List<RelDataType> paramTypes) {
+ return true;
+ }
+
public CalendarPolicy getCalendarPolicy() {
return CalendarPolicy.NULL;
}
@@ -778,6 +785,7 @@ public class SqlDialect {
HIVE("Apache Hive", null, NullCollation.LOW),
INFORMIX("Informix", null, NullCollation.HIGH),
INGRES("Ingres", null, NullCollation.HIGH),
+ JETHRO("JethroData", "\"", NullCollation.LOW),
LUCIDDB("LucidDB", "\"", NullCollation.HIGH),
INTERBASE("Interbase", null, NullCollation.HIGH),
PHOENIX("Phoenix", "\"", NullCollation.HIGH),
@@ -839,7 +847,7 @@ public class SqlDialect {
* <p>Since databases have many versions and flavors, this dummy dialect
* is at best an approximation. If you want exact information, better to
* use a dialect created from an actual connection's metadata
- * (see {@link SqlDialect#create(java.sql.DatabaseMetaData)}).
+ * (see {@link SqlDialectFactory#create(java.sql.DatabaseMetaData)}).
*
* @return Dialect representing lowest-common-denominator behavior for
* all versions of this database
@@ -868,6 +876,8 @@ public class SqlDialect {
Context withIdentifierQuoteString(String identifierQuoteString);
@Nonnull NullCollation nullCollation();
Context withNullCollation(@Nonnull NullCollation nullCollation);
+ JethroDataSqlDialect.JethroInfo jethroInfo();
+ Context withJethroInfo(JethroDataSqlDialect.JethroInfo jethroInfo);
}
/** Implementation of Context. */
@@ -879,11 +889,13 @@ public class SqlDialect {
private final int databaseMinorVersion;
private final String identifierQuoteString;
private final NullCollation nullCollation;
+ private final JethroDataSqlDialect.JethroInfo jethroInfo;
private ContextImpl(DatabaseProduct databaseProduct,
String databaseProductName, String databaseVersion,
int databaseMajorVersion, int databaseMinorVersion,
- String identifierQuoteString, NullCollation nullCollation) {
+ String identifierQuoteString, NullCollation nullCollation,
+ JethroDataSqlDialect.JethroInfo jethroInfo) {
this.databaseProduct = Preconditions.checkNotNull(databaseProduct);
this.databaseProductName = databaseProductName;
this.databaseVersion = databaseVersion;
@@ -891,6 +903,7 @@ public class SqlDialect {
this.databaseMinorVersion = databaseMinorVersion;
this.identifierQuoteString = identifierQuoteString;
this.nullCollation = Preconditions.checkNotNull(nullCollation);
+ this.jethroInfo = Preconditions.checkNotNull(jethroInfo);
}
@Nonnull public DatabaseProduct databaseProduct() {
@@ -901,7 +914,7 @@ public class SqlDialect {
@Nonnull DatabaseProduct databaseProduct) {
return new ContextImpl(databaseProduct, databaseProductName,
databaseVersion, databaseMajorVersion, databaseMinorVersion,
- identifierQuoteString, nullCollation);
+ identifierQuoteString, nullCollation, jethroInfo);
}
public String databaseProductName() {
@@ -911,7 +924,7 @@ public class SqlDialect {
public Context withDatabaseProductName(String databaseProductName) {
return new ContextImpl(databaseProduct, databaseProductName,
databaseVersion, databaseMajorVersion, databaseMinorVersion,
- identifierQuoteString, nullCollation);
+ identifierQuoteString, nullCollation, jethroInfo);
}
public String databaseVersion() {
@@ -921,7 +934,7 @@ public class SqlDialect {
public Context withDatabaseVersion(String databaseVersion) {
return new ContextImpl(databaseProduct, databaseProductName,
databaseVersion, databaseMajorVersion, databaseMinorVersion,
- identifierQuoteString, nullCollation);
+ identifierQuoteString, nullCollation, jethroInfo);
}
public int databaseMajorVersion() {
@@ -931,7 +944,7 @@ public class SqlDialect {
public Context withDatabaseMajorVersion(int databaseMajorVersion) {
return new ContextImpl(databaseProduct, databaseProductName,
databaseVersion, databaseMajorVersion, databaseMinorVersion,
- identifierQuoteString, nullCollation);
+ identifierQuoteString, nullCollation, jethroInfo);
}
public int databaseMinorVersion() {
@@ -941,7 +954,7 @@ public class SqlDialect {
public Context withDatabaseMinorVersion(int databaseMinorVersion) {
return new ContextImpl(databaseProduct, databaseProductName,
databaseVersion, databaseMajorVersion, databaseMinorVersion,
- identifierQuoteString, nullCollation);
+ identifierQuoteString, nullCollation, jethroInfo);
}
public String identifierQuoteString() {
@@ -951,7 +964,7 @@ public class SqlDialect {
public Context withIdentifierQuoteString(String identifierQuoteString) {
return new ContextImpl(databaseProduct, databaseProductName,
databaseVersion, databaseMajorVersion, databaseMinorVersion,
- identifierQuoteString, nullCollation);
+ identifierQuoteString, nullCollation, jethroInfo);
}
@Nonnull public NullCollation nullCollation() {
@@ -961,7 +974,17 @@ public class SqlDialect {
public Context withNullCollation(@Nonnull NullCollation nullCollation) {
return new ContextImpl(databaseProduct, databaseProductName,
databaseVersion, databaseMajorVersion, databaseMinorVersion,
- identifierQuoteString, nullCollation);
+ identifierQuoteString, nullCollation, jethroInfo);
+ }
+
+ @Nonnull public JethroDataSqlDialect.JethroInfo jethroInfo() {
+ return jethroInfo;
+ }
+
+ public Context withJethroInfo(JethroDataSqlDialect.JethroInfo jethroInfo) {
+ return new ContextImpl(databaseProduct, databaseProductName,
+ databaseVersion, databaseMajorVersion, databaseMinorVersion,
+ identifierQuoteString, nullCollation, jethroInfo);
}
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/sql/SqlDialectFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialectFactory.java b/core/src/main/java/org/apache/calcite/sql/SqlDialectFactory.java
index 73de073..202b8fb 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDialectFactory.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDialectFactory.java
@@ -20,7 +20,7 @@ import java.sql.Connection;
import java.sql.DatabaseMetaData;
/**
- * <code>SqlDialectFactory</code> constructs a <code>SqlDialect</code> appropriate
+ * Creates a <code>SqlDialect</code> appropriate
* for a given database metadata object.
*/
public interface SqlDialectFactory {
@@ -34,6 +34,8 @@ public interface SqlDialectFactory {
*
* @param databaseMetaData used to determine which dialect of SQL to
* generate
+ *
+ * @throws RuntimeException if there was an error creating the dialect
*/
SqlDialect create(DatabaseMetaData databaseMetaData);
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java b/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java
index c2bf4e3..18de463 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java
@@ -17,6 +17,7 @@
package org.apache.calcite.sql;
import org.apache.calcite.config.NullCollation;
+
import org.apache.calcite.sql.dialect.AccessSqlDialect;
import org.apache.calcite.sql.dialect.AnsiSqlDialect;
import org.apache.calcite.sql.dialect.CalciteSqlDialect;
@@ -30,6 +31,7 @@ import org.apache.calcite.sql.dialect.InfobrightSqlDialect;
import org.apache.calcite.sql.dialect.InformixSqlDialect;
import org.apache.calcite.sql.dialect.IngresSqlDialect;
import org.apache.calcite.sql.dialect.InterbaseSqlDialect;
+import org.apache.calcite.sql.dialect.JethroDataSqlDialect;
import org.apache.calcite.sql.dialect.LucidDbSqlDialect;
import org.apache.calcite.sql.dialect.MssqlSqlDialect;
import org.apache.calcite.sql.dialect.MysqlSqlDialect;
@@ -44,6 +46,9 @@ import org.apache.calcite.sql.dialect.SybaseSqlDialect;
import org.apache.calcite.sql.dialect.TeradataSqlDialect;
import org.apache.calcite.sql.dialect.VerticaSqlDialect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Locale;
@@ -52,14 +57,23 @@ import java.util.Locale;
* The default implementation of a <code>SqlDialectFactory</code>.
*/
public class SqlDialectFactoryImpl implements SqlDialectFactory {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SqlDialectFactoryImpl.class);
+
+ public static final SqlDialectFactoryImpl INSTANCE = new SqlDialectFactoryImpl();
+
+ private final JethroDataSqlDialect.JethroInfoCache jethroCache =
+ JethroDataSqlDialect.createCache();
+
public SqlDialect create(DatabaseMetaData databaseMetaData) {
String databaseProductName;
int databaseMajorVersion;
int databaseMinorVersion;
+ String databaseVersion;
try {
databaseProductName = databaseMetaData.getDatabaseProductName();
databaseMajorVersion = databaseMetaData.getDatabaseMajorVersion();
databaseMinorVersion = databaseMetaData.getDatabaseMinorVersion();
+ databaseVersion = databaseMetaData.getDatabaseProductVersion();
} catch (SQLException e) {
throw new RuntimeException("while detecting database product", e);
}
@@ -71,6 +85,7 @@ public class SqlDialectFactoryImpl implements SqlDialectFactory {
.withDatabaseProductName(databaseProductName)
.withDatabaseMajorVersion(databaseMajorVersion)
.withDatabaseMinorVersion(databaseMinorVersion)
+ .withDatabaseVersion(databaseVersion)
.withIdentifierQuoteString(quoteString)
.withNullCollation(nullCollation);
switch (upperProductName) {
@@ -86,6 +101,9 @@ public class SqlDialectFactoryImpl implements SqlDialectFactory {
return new IngresSqlDialect(c);
case "INTERBASE":
return new InterbaseSqlDialect(c);
+ case "JETHRODATA":
+ return new JethroDataSqlDialect(
+ c.withJethroInfo(jethroCache.get(databaseMetaData)));
case "LUCIDDB":
return new LucidDbSqlDialect(c);
case "ORACLE":
@@ -184,6 +202,8 @@ public class SqlDialectFactoryImpl implements SqlDialectFactory {
return IngresSqlDialect.DEFAULT;
case INTERBASE:
return InterbaseSqlDialect.DEFAULT;
+ case JETHRO:
+ throw new RuntimeException("Jethro does not support simple creation");
case LUCIDDB:
return LucidDbSqlDialect.DEFAULT;
case MSSQL:
@@ -216,6 +236,7 @@ public class SqlDialectFactoryImpl implements SqlDialectFactory {
return null;
}
}
+
}
// End SqlDialectFactoryImpl.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/main/java/org/apache/calcite/sql/dialect/JethroDataSqlDialect.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/JethroDataSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/JethroDataSqlDialect.java
new file mode 100644
index 0000000..26f0148
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/JethroDataSqlDialect.java
@@ -0,0 +1,235 @@
+/*
+ * 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.sql.dialect;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.SqlDialect;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.type.SqlTypeName;
+
+import com.google.common.base.Preconditions;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * A <code>SqlDialect</code> implementation for the JethroData database.
+ */
+public class JethroDataSqlDialect extends SqlDialect {
+ private final JethroInfo info;
+
+ /** Creates a JethroDataSqlDialect. */
+ public JethroDataSqlDialect(Context context) {
+ super(context);
+ this.info = context.jethroInfo();
+ }
+
+ @Override public boolean supportsCharSet() {
+ return false;
+ }
+
+ @Override public SqlNode emulateNullDirection(SqlNode node,
+ boolean nullsFirst, boolean desc) {
+ return node;
+ }
+
+ @Override public boolean supportsAggregateFunction(SqlKind kind) {
+ switch (kind) {
+ case COUNT:
+ case SUM:
+ case AVG:
+ case MIN:
+ case MAX:
+ case STDDEV_POP:
+ case STDDEV_SAMP:
+ case VAR_POP:
+ case VAR_SAMP:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ @Override public boolean supportsFunction(SqlOperator operator,
+ RelDataType type, List<RelDataType> paramTypes) {
+ switch (operator.getKind()) {
+ case IS_NOT_NULL:
+ case IS_NULL:
+ case AND:
+ case OR:
+ case NOT:
+ case BETWEEN:
+ case CASE:
+ case CAST:
+ return true;
+ }
+ final Set<JethroSupportedFunction> functions =
+ info.supportedFunctions.get(operator.getName());
+
+ if (functions != null) {
+ for (JethroSupportedFunction f : functions) {
+ if (f.argumentsMatch(paramTypes)) {
+ return true;
+ }
+ }
+ }
+ LOGGER.debug("Unsupported function in jethro: " + operator + " with params "
+ + paramTypes);
+ return false;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override public boolean supportsOffsetFetch() {
+ return false;
+ }
+
+ @Override public boolean supportsNestedAggregations() {
+ return false;
+ }
+
+ public static JethroInfoCache createCache() {
+ return new JethroInfoCacheImpl();
+ }
+
+ /** Information about a function supported by Jethro. */
+ static class JethroSupportedFunction {
+ private final List<SqlTypeName> operandTypes;
+
+ JethroSupportedFunction(String name, String operands) {
+ Preconditions.checkNotNull(name); // not currently used
+ final ImmutableList.Builder<SqlTypeName> b = ImmutableList.builder();
+ for (String strType : operands.split(":")) {
+ b.add(parse(strType));
+ }
+ this.operandTypes = b.build();
+ }
+
+ private SqlTypeName parse(String strType) {
+ switch (strType.toLowerCase(Locale.ROOT)) {
+ case "bigint":
+ case "long":
+ return SqlTypeName.BIGINT;
+ case "integer":
+ case "int":
+ return SqlTypeName.INTEGER;
+ case "double":
+ return SqlTypeName.DOUBLE;
+ case "float":
+ return SqlTypeName.FLOAT;
+ case "string":
+ return SqlTypeName.VARCHAR;
+ case "timestamp":
+ return SqlTypeName.TIMESTAMP;
+ default:
+ return SqlTypeName.ANY;
+ }
+ }
+
+ boolean argumentsMatch(List<RelDataType> paramTypes) {
+ if (paramTypes.size() != operandTypes.size()) {
+ return false;
+ }
+ for (int i = 0; i < paramTypes.size(); i++) {
+ if (paramTypes.get(i).getSqlTypeName() != operandTypes.get(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /** Stores information about capabilities of Jethro databases. */
+ public interface JethroInfoCache {
+ JethroInfo get(DatabaseMetaData databaseMetaData);
+ }
+
+ /** Implementation of {@code JethroInfoCache}. */
+ private static class JethroInfoCacheImpl implements JethroInfoCache {
+ final Map<String, JethroInfo> map = new HashMap<>();
+
+ public JethroInfo get(final DatabaseMetaData metaData) {
+ try {
+ assert "JethroData".equals(metaData.getDatabaseProductName());
+ String productVersion = metaData.getDatabaseProductVersion();
+ synchronized (JethroInfoCacheImpl.this) {
+ JethroInfo info = map.get(productVersion);
+ if (info == null) {
+ final Connection c = metaData.getConnection();
+ info = makeInfo(c);
+ map.put(productVersion, info);
+ }
+ return info;
+ }
+ } catch (Exception e) {
+ LOGGER.error("Failed to create JethroDataDialect", e);
+ throw new RuntimeException("Failed to create JethroDataDialect", e);
+ }
+ }
+
+ private JethroInfo makeInfo(Connection jethroConnection) {
+ try (Statement jethroStatement = jethroConnection.createStatement();
+ ResultSet functionsTupleSet =
+ jethroStatement.executeQuery("show functions extended")) {
+ final Multimap<String, JethroSupportedFunction> supportedFunctions =
+ LinkedHashMultimap.create();
+ while (functionsTupleSet.next()) {
+ String functionName = functionsTupleSet.getString(1);
+ String operandsType = functionsTupleSet.getString(3);
+ supportedFunctions.put(functionName,
+ new JethroSupportedFunction(functionName, operandsType));
+ }
+ return new JethroInfo(supportedFunctions);
+ } catch (Exception e) {
+ final String msg =
+ "Jethro server failed to execute 'show functions extended'";
+ LOGGER.error(msg, e);
+ throw new RuntimeException(msg
+ + "; make sure your Jethro server is up to date", e);
+ }
+ }
+ }
+
+ /** Information about the capabilities of a Jethro database. */
+ public static class JethroInfo {
+ public static final JethroInfo EMPTY = new JethroInfo(
+ ImmutableSetMultimap.<String, JethroSupportedFunction>of());
+
+ private final ImmutableSetMultimap<String, JethroSupportedFunction> supportedFunctions;
+
+ public JethroInfo(Multimap<String, JethroSupportedFunction> supportedFunctions) {
+ this.supportedFunctions = ImmutableSetMultimap.copyOf(supportedFunctions);
+ }
+ }
+}
+
+// End JethroDataSqlDialect.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/facd83d3/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index d6bb976..2cdda74 100644
--- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -29,9 +29,11 @@ import org.apache.calcite.rel.rules.UnionMergeRule;
import org.apache.calcite.runtime.FlatLists;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.sql.SqlDialect;
+import org.apache.calcite.sql.SqlDialect.Context;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.dialect.CalciteSqlDialect;
import org.apache.calcite.sql.dialect.HiveSqlDialect;
+import org.apache.calcite.sql.dialect.JethroDataSqlDialect;
import org.apache.calcite.sql.dialect.MysqlSqlDialect;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql2rel.SqlToRelConverter;
@@ -95,6 +97,18 @@ public class RelToSqlConverterTest {
return Frameworks.getPlanner(config);
}
+ private static JethroDataSqlDialect jethroDataSqlDialect() {
+ Context dummyContext = SqlDialect.EMPTY_CONTEXT
+ .withDatabaseProduct(SqlDialect.DatabaseProduct.JETHRO)
+ .withDatabaseMajorVersion(1)
+ .withDatabaseMinorVersion(0)
+ .withDatabaseVersion("1.0")
+ .withIdentifierQuoteString("\"")
+ .withNullCollation(NullCollation.HIGH)
+ .withJethroInfo(JethroDataSqlDialect.JethroInfo.EMPTY);
+ return new JethroDataSqlDialect(dummyContext);
+ }
+
private static MysqlSqlDialect mySqlDialect(NullCollation nullCollation) {
return new MysqlSqlDialect(SqlDialect.EMPTY_CONTEXT
.withDatabaseProduct(SqlDialect.DatabaseProduct.MYSQL)
@@ -422,6 +436,16 @@ public class RelToSqlConverterTest {
sql(query).dialect(hive2_1_0_Dialect).ok(expected);
}
+ @Test public void testJethroDataSelectQueryWithOrderByDescAndNullsFirstShouldBeEmulated() {
+ final String query = "select \"product_id\" from \"product\"\n"
+ + "order by \"product_id\" desc nulls first";
+
+ final String expected = "SELECT \"product_id\"\n"
+ + "FROM \"foodmart\".\"product\"\n"
+ + "ORDER BY \"product_id\", \"product_id\" DESC";
+ sql(query).dialect(jethroDataSqlDialect()).ok(expected);
+ }
+
@Test public void testMySqlSelectQueryWithOrderByDescAndNullsFirstShouldBeEmulated() {
final String query = "select \"product_id\" from \"product\"\n"
+ "order by \"product_id\" desc nulls first";