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 2015/01/22 01:33:38 UTC
[1/3] incubator-calcite git commit: [CALCITE-544] Implement Union in
Interpreter;
[CALCITE-562] Implement inner JOIN in interpreter and improve handling of
scalar expressions
Repository: incubator-calcite
Updated Branches:
refs/heads/master 4e1854044 -> 66cfb120f
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index c0a83ae..b8c0235 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -25,6 +25,8 @@ import org.apache.calcite.rel.RelShuttle;
import org.apache.calcite.rel.RelVisitor;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.Calc;
+import org.apache.calcite.rel.core.Filter;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.rel.core.Project;
@@ -54,7 +56,9 @@ import org.apache.calcite.rex.RexFieldAccess;
import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexLocalRef;
+import org.apache.calcite.rex.RexMultisetUtil;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexOver;
import org.apache.calcite.rex.RexProgram;
import org.apache.calcite.rex.RexProgramBuilder;
import org.apache.calcite.rex.RexShuttle;
@@ -80,6 +84,7 @@ import org.apache.calcite.util.mapping.MappingType;
import org.apache.calcite.util.mapping.Mappings;
import com.google.common.base.Function;
+import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@@ -104,6 +109,41 @@ public abstract class RelOptUtil {
public static final double EPSILON = 1.0e-5;
+ /** Predicate for whether a filter contains multisets or windowed
+ * aggregates. */
+ public static final Predicate<Filter> FILTER_PREDICATE =
+ new Predicate<Filter>() {
+ public boolean apply(Filter filter) {
+ return !(B
+ && RexMultisetUtil.containsMultiset(filter.getCondition(), true)
+ || RexOver.containsOver(filter.getCondition()));
+ }
+ };
+
+ /** Predicate for whether a project contains multisets or windowed
+ * aggregates. */
+ public static final Predicate<Project> PROJECT_PREDICATE =
+ new Predicate<Project>() {
+ public boolean apply(Project project) {
+ return !(B
+ && RexMultisetUtil.containsMultiset(project.getProjects(), true)
+ || RexOver.containsOver(project.getProjects(), null));
+ }
+ };
+
+ /** Predicate for whether a calc contains multisets or windowed
+ * aggregates. */
+ public static final Predicate<Calc> CALC_PREDICATE =
+ new Predicate<Calc>() {
+ public boolean apply(Calc calc) {
+ return !(B
+ && RexMultisetUtil.containsMultiset(calc.getProgram())
+ || calc.getProgram().containsAggs());
+ }
+ };
+
+ static final boolean B = false;
+
private static final Function<RelDataTypeField, RelDataType> GET_TYPE =
new Function<RelDataTypeField, RelDataType>() {
public RelDataType apply(RelDataTypeField field) {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
index 33072d1..d055a40 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
@@ -381,6 +381,18 @@ public final class RelTraitSet extends AbstractList<RelTrait> {
return plusAll(additionalTraits.traits);
}
+ /** Returns a list of traits that are in {@code traitSet} but not in this
+ * RelTraitSet. */
+ public ImmutableList<RelTrait> difference(RelTraitSet traitSet) {
+ final ImmutableList.Builder<RelTrait> builder = ImmutableList.builder();
+ for (Pair<RelTrait, RelTrait> pair : Pair.zip(traits, traitSet.traits)) {
+ if (pair.left != pair.right) {
+ builder.add(pair.right);
+ }
+ }
+ return builder.build();
+ }
+
/** Cache of trait sets. */
private static class Cache {
final Map<List<RelTrait>, RelTraitSet> map =
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
index a712861..2adfb0e 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
@@ -159,6 +159,11 @@ class RelSet {
subsets.add(subset);
+ if (planner.root != null
+ && planner.root.set == this) {
+ planner.ensureRootConverters();
+ }
+
if (planner.listener != null) {
postEquivalenceEvent(planner, subset);
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index 6e238d8..d8e26ae 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -333,6 +333,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
// Making a node the root changes its importance.
this.ruleQueue.recompute(this.root);
+ ensureRootConverters();
}
public RelNode getRoot() {
@@ -728,6 +729,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
* query
*/
public RelNode findBestExp() {
+ ensureRootConverters();
useApplicableMaterializations();
int cumulativeTicks = 0;
for (VolcanoPlannerPhase phase : VolcanoPlannerPhase.values()) {
@@ -818,6 +820,33 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
return cheapest;
}
+ /** Ensures that the subset that is the root relational expression contains
+ * converters to all other subsets in its equivalence set.
+ *
+ * <p>Thus the planner tries to find cheap implementations of those other
+ * subsets, which can then be converted to the root. This is the only place
+ * in the plan where explicit converters are required; elsewhere, a consumer
+ * will be asking for the result in a particular convention, but the root has
+ * no consumers. */
+ void ensureRootConverters() {
+ final Set<RelSubset> subsets = Sets.newHashSet();
+ for (RelNode rel : root.getRels()) {
+ if (rel instanceof AbstractConverter) {
+ subsets.add((RelSubset) ((AbstractConverter) rel).getInput());
+ }
+ }
+ for (RelSubset subset : root.set.subsets) {
+ final ImmutableList<RelTrait> difference =
+ root.getTraitSet().difference(subset.getTraitSet());
+ if (difference.size() == 1 && subsets.add(subset)) {
+ register(
+ new AbstractConverter(subset.getCluster(), subset,
+ difference.get(0).getTraitDef(), root.getTraitSet()),
+ root);
+ }
+ }
+ }
+
/**
* Returns a multi-line string describing the provenance of a tree of
* relational expressions. For each node in the tree, prints the rule that
@@ -1545,6 +1574,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
set.getOrCreateSubset(
root.getCluster(),
root.getTraitSet());
+ ensureRootConverters();
}
return set;
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
index 47b753b..0782170 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
@@ -16,8 +16,8 @@
*/
package org.apache.calcite.prepare;
-import org.apache.calcite.adapter.enumerable.EnumerableConvention;
import org.apache.calcite.adapter.enumerable.EnumerableRel;
+import org.apache.calcite.interpreter.BindableConvention;
import org.apache.calcite.jdbc.CalcitePrepare;
import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.plan.RelOptMaterialization;
@@ -59,7 +59,7 @@ class CalciteMaterializer extends CalcitePrepareImpl.CalcitePreparingStmt {
CatalogReader catalogReader, CalciteSchema schema,
RelOptPlanner planner) {
super(context, catalogReader, catalogReader.getTypeFactory(), schema,
- EnumerableRel.Prefer.ANY, planner, EnumerableConvention.INSTANCE);
+ EnumerableRel.Prefer.ANY, planner, BindableConvention.INSTANCE);
}
/** Populates a materialization record, converting a table path
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index f4b9ff5..e075996 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -17,18 +17,20 @@
package org.apache.calcite.prepare;
import org.apache.calcite.DataContext;
+import org.apache.calcite.adapter.enumerable.EnumerableBindable;
import org.apache.calcite.adapter.enumerable.EnumerableConvention;
+import org.apache.calcite.adapter.enumerable.EnumerableInterpretable;
import org.apache.calcite.adapter.enumerable.EnumerableRel;
-import org.apache.calcite.adapter.enumerable.EnumerableRelImplementor;
import org.apache.calcite.adapter.enumerable.EnumerableRules;
import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.avatica.AvaticaParameter;
import org.apache.calcite.avatica.ColumnMetaData;
-import org.apache.calcite.avatica.Helper;
import org.apache.calcite.avatica.Meta;
-import org.apache.calcite.avatica.util.Spaces;
import org.apache.calcite.config.CalciteConnectionConfig;
+import org.apache.calcite.interpreter.BindableConvention;
+import org.apache.calcite.interpreter.Bindables;
+import org.apache.calcite.interpreter.Interpreters;
import org.apache.calcite.jdbc.CalcitePrepare;
import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.linq4j.Enumerable;
@@ -39,7 +41,6 @@ import org.apache.calcite.linq4j.function.Function1;
import org.apache.calcite.linq4j.tree.BinaryExpression;
import org.apache.calcite.linq4j.tree.BlockStatement;
import org.apache.calcite.linq4j.tree.Blocks;
-import org.apache.calcite.linq4j.tree.ClassDeclaration;
import org.apache.calcite.linq4j.tree.ConstantExpression;
import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.linq4j.tree.Expressions;
@@ -89,7 +90,6 @@ import org.apache.calcite.rex.RexNode;
import org.apache.calcite.runtime.Bindable;
import org.apache.calcite.runtime.Hook;
import org.apache.calcite.runtime.Typed;
-import org.apache.calcite.runtime.Utilities;
import org.apache.calcite.schema.Schemas;
import org.apache.calcite.server.CalciteServerStatement;
import org.apache.calcite.sql.SqlBinaryOperator;
@@ -115,15 +115,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
-import org.codehaus.commons.compiler.CompileException;
-import org.codehaus.commons.compiler.CompilerFactoryFactory;
-import org.codehaus.commons.compiler.IClassBodyEvaluator;
-import org.codehaus.commons.compiler.ICompilerFactory;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.StringReader;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.DatabaseMetaData;
@@ -155,6 +146,13 @@ public class CalcitePrepareImpl implements CalcitePrepare {
* disabled, then enabled. */
private static final boolean ENABLE_COLLATION_TRAIT = true;
+ /** Whether the bindable convention should be the root convention of any
+ * plan. If not, enumerable convention is the default. */
+ public static final boolean ENABLE_BINDABLE = false;
+
+ /** Whether the enumerable convention is enabled. */
+ public static final boolean ENABLE_ENUMERABLE = true;
+
private static final Set<String> SIMPLE_SQLS =
ImmutableSet.of(
"SELECT 1",
@@ -164,7 +162,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
"values 1",
"VALUES 1");
- private static final List<RelOptRule> DEFAULT_RULES =
+ private static final List<RelOptRule> ENUMERABLE_RULES =
ImmutableList.of(
EnumerableRules.ENUMERABLE_JOIN_RULE,
EnumerableRules.ENUMERABLE_SEMI_JOIN_RULE,
@@ -182,7 +180,10 @@ public class CalcitePrepareImpl implements CalcitePrepare {
EnumerableRules.ENUMERABLE_TABLE_MODIFICATION_RULE,
EnumerableRules.ENUMERABLE_VALUES_RULE,
EnumerableRules.ENUMERABLE_WINDOW_RULE,
- EnumerableRules.ENUMERABLE_TABLE_FUNCTION_SCAN_RULE,
+ EnumerableRules.ENUMERABLE_TABLE_FUNCTION_SCAN_RULE);
+
+ private static final List<RelOptRule> DEFAULT_RULES =
+ ImmutableList.of(
AggregateStarTableRule.INSTANCE,
AggregateStarTableRule.INSTANCE2,
TableScanRule.INSTANCE,
@@ -257,7 +258,8 @@ public class CalcitePrepareImpl implements CalcitePrepare {
context.getRootSchema(),
null,
new HepPlanner(new HepProgramBuilder().build()),
- EnumerableConvention.INSTANCE);
+ ENABLE_BINDABLE ? BindableConvention.INSTANCE
+ : EnumerableConvention.INSTANCE);
final SqlToRelConverter converter =
preparingStmt.getSqlToRelConverter(validator, catalogReader);
final RelNode relNode = converter.convertQuery(sqlNode1, false, true);
@@ -314,6 +316,23 @@ public class CalcitePrepareImpl implements CalcitePrepare {
planner.addRule(rule);
}
+ if (ENABLE_BINDABLE) {
+ for (RelOptRule rule : Bindables.RULES) {
+ planner.addRule(rule);
+ }
+ }
+
+ if (ENABLE_ENUMERABLE) {
+ for (RelOptRule rule : ENUMERABLE_RULES) {
+ planner.addRule(rule);
+ }
+ }
+
+ if (ENABLE_BINDABLE && ENABLE_ENUMERABLE) {
+ planner.addRule(
+ EnumerableBindable.EnumerableToBindableConverterRule.INSTANCE);
+ }
+
// Change the below to enable constant-reduction.
if (false) {
for (RelOptRule rule : CONSTANT_REDUCTION_RULES) {
@@ -443,7 +462,8 @@ public class CalcitePrepareImpl implements CalcitePrepare {
context.getRootSchema(),
prefer,
planner,
- EnumerableConvention.INSTANCE);
+ ENABLE_BINDABLE ? BindableConvention.INSTANCE
+ : EnumerableConvention.INSTANCE);
final RelDataType x;
final Prepare.PreparedResult preparedResult;
@@ -524,15 +544,19 @@ public class CalcitePrepareImpl implements CalcitePrepare {
if (preparedResult instanceof Typed) {
resultClazz = (Class) ((Typed) preparedResult).getElementType();
}
+ //noinspection unchecked
+ final Bindable<T> bindable = preparedResult.getBindable();
return new CalciteSignature<T>(
sql,
parameters,
preparingStmt.internalParameters,
jdbcType,
columns,
- Meta.CursorFactory.deduce(columns, resultClazz),
+ preparingStmt.resultConvention == BindableConvention.INSTANCE
+ ? Meta.CursorFactory.ARRAY
+ : Meta.CursorFactory.deduce(columns, resultClazz),
maxRowCount,
- preparedResult.getBindable());
+ bindable);
}
private List<ColumnMetaData> getColumnMetaDataList(
@@ -780,15 +804,6 @@ public class CalcitePrepareImpl implements CalcitePrepare {
return sqlToRelConverter;
}
- @Override protected EnumerableRelImplementor getRelImplementor(
- RexBuilder rexBuilder) {
- return new EnumerableRelImplementor(rexBuilder, internalParameters);
- }
-
- @Override protected boolean shouldAlwaysWriteJavaFile() {
- return false;
- }
-
@Override public RelNode flattenTypes(
RelNode rootRel,
boolean restructure) {
@@ -861,26 +876,12 @@ public class CalcitePrepareImpl implements CalcitePrepare {
SqlKind sqlKind) {
RelDataType resultType = rootRel.getRowType();
boolean isDml = sqlKind.belongsTo(SqlKind.DML);
- EnumerableRelImplementor relImplementor =
- getRelImplementor(rootRel.getCluster().getRexBuilder());
- ClassDeclaration expr =
- relImplementor.implementRoot((EnumerableRel) rootRel, prefer);
- String s = Expressions.toString(expr.memberDeclarations, "\n", false);
-
- if (DEBUG) {
- debugCode(System.out, s);
- }
-
- Hook.JAVA_PLAN.run(s);
-
final Bindable bindable;
- try {
- bindable = getBindable(expr, s);
- } catch (Exception e) {
- throw Helper.INSTANCE.wrap(
- "Error while compiling generated Java code:\n"
- + s,
- e);
+ if (resultConvention == BindableConvention.INSTANCE) {
+ bindable = Interpreters.bindable(rootRel);
+ } else {
+ bindable = EnumerableInterpretable.toBindable(internalParameters,
+ context.spark(), (EnumerableRel) rootRel, prefer);
}
if (timingTracer != null) {
@@ -911,54 +912,6 @@ public class CalcitePrepareImpl implements CalcitePrepare {
}
};
}
-
- /**
- * Prints the given code with line numbering.
- */
- private void debugCode(PrintStream out, String code) {
- out.println();
- StringReader sr = new StringReader(code);
- BufferedReader br = new BufferedReader(sr);
- try {
- String line;
- for (int i = 1; (line = br.readLine()) != null; i++) {
- out.print("/*");
- String number = Integer.toString(i);
- if (number.length() < 4) {
- Spaces.append(out, 4 - number.length());
- }
- out.print(number);
- out.print(" */ ");
- out.println(line);
- }
- } catch (IOException e) {
- // not possible
- }
- }
-
- private Bindable getBindable(ClassDeclaration expr,
- String s) throws CompileException, IOException {
- if (context.spark().enabled()) {
- return context.spark().compile(expr, s);
- }
- ICompilerFactory compilerFactory;
- try {
- compilerFactory = CompilerFactoryFactory.getDefaultCompilerFactory();
- } catch (Exception e) {
- throw new IllegalStateException(
- "Unable to instantiate java compiler", e);
- }
- IClassBodyEvaluator cbe = compilerFactory.newClassBodyEvaluator();
- cbe.setClassName(expr.name);
- cbe.setExtendedClass(Utilities.class);
- cbe.setImplementedInterfaces(new Class[]{Bindable.class, Typed.class});
- cbe.setParentClassLoader(getClass().getClassLoader());
- if (DEBUG) {
- // Add line numbers to the generated janino class
- cbe.setDebuggingInformation(true, true, true);
- }
- return (Bindable) cbe.createInstance(new StringReader(s));
- }
}
/** An {@code EXPLAIN} statement, prepared and ready to execute. */
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index ae4e691..25181ea 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -21,7 +21,6 @@ import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.jdbc.CalcitePrepare;
import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.plan.Convention;
-import org.apache.calcite.plan.RelImplementor;
import org.apache.calcite.plan.RelOptLattice;
import org.apache.calcite.plan.RelOptMaterialization;
import org.apache.calcite.plan.RelOptPlanner;
@@ -32,7 +31,6 @@ import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.logical.LogicalTableModify;
import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexExecutorImpl;
import org.apache.calcite.runtime.Bindable;
import org.apache.calcite.runtime.Hook;
@@ -53,6 +51,7 @@ import org.apache.calcite.util.Pair;
import org.apache.calcite.util.trace.CalciteTimingTracer;
import org.apache.calcite.util.trace.CalciteTrace;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.lang.reflect.Type;
@@ -328,14 +327,6 @@ public abstract class Prepare {
SqlValidator validator,
CatalogReader catalogReader);
- /**
- * Protected method to allow subclasses to override construction of
- * RelImplementor.
- */
- protected abstract RelImplementor getRelImplementor(RexBuilder rexBuilder);
-
- protected abstract boolean shouldAlwaysWriteJavaFile();
-
public abstract RelNode flattenTypes(
RelNode rootRel,
boolean restructure);
@@ -521,14 +512,10 @@ public abstract class Prepare {
RelNode rootRel,
LogicalTableModify.Operation tableModOp,
boolean isDml) {
- assert rowType != null;
- assert parameterRowType != null;
- assert fieldOrigins != null;
- assert rootRel != null;
- this.rowType = rowType;
- this.parameterRowType = parameterRowType;
- this.fieldOrigins = fieldOrigins;
- this.rootRel = rootRel;
+ this.rowType = Preconditions.checkNotNull(rowType);
+ this.parameterRowType = Preconditions.checkNotNull(parameterRowType);
+ this.fieldOrigins = Preconditions.checkNotNull(fieldOrigins);
+ this.rootRel = Preconditions.checkNotNull(rootRel);
this.tableModOp = tableModOp;
this.isDml = isDml;
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
index f91c45f..b616979 100644
--- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
@@ -26,6 +26,7 @@ import org.apache.calcite.plan.RelOptSchema;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.logical.LogicalTableScan;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.schema.ExtensibleTable;
@@ -196,16 +197,22 @@ public class RelOptTableImpl implements Prepare.PreparingTable {
if (table instanceof TranslatableTable) {
return ((TranslatableTable) table).toRel(context, this);
}
- RelOptCluster cluster = context.getCluster();
- Class elementType = deduceElementType();
- final RelNode scan = new EnumerableTableScan(cluster,
- cluster.traitSetOf(EnumerableConvention.INSTANCE), this, elementType);
- if (table instanceof FilterableTable
- || table instanceof ProjectableFilterableTable) {
- return new EnumerableInterpreter(cluster, scan.getTraitSet(),
- scan, 1d);
+ if (CalcitePrepareImpl.ENABLE_BINDABLE) {
+ return new LogicalTableScan(context.getCluster(), this);
+ }
+ if (CalcitePrepareImpl.ENABLE_ENUMERABLE) {
+ RelOptCluster cluster = context.getCluster();
+ Class elementType = deduceElementType();
+ final RelNode scan = new EnumerableTableScan(cluster,
+ cluster.traitSetOf(EnumerableConvention.INSTANCE), this, elementType);
+ if (table instanceof FilterableTable
+ || table instanceof ProjectableFilterableTable) {
+ return new EnumerableInterpreter(cluster, scan.getTraitSet(),
+ scan, 1d);
+ }
+ return scan;
}
- return scan;
+ throw new AssertionError();
}
private Class deduceElementType() {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java b/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java
index 86fe1eb..5591ca3 100644
--- a/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java
@@ -24,6 +24,8 @@ import org.apache.calcite.plan.RelTrait;
import org.apache.calcite.plan.RelTraitDef;
import org.apache.calcite.rel.RelNode;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
/**
@@ -46,24 +48,32 @@ public abstract class ConverterRule extends RelOptRule {
* @param out Trait which is converted to
* @param description Description of rule
*/
- public ConverterRule(
- Class<? extends RelNode> clazz,
- RelTrait in,
- RelTrait out,
+ public ConverterRule(Class<? extends RelNode> clazz, RelTrait in,
+ RelTrait out, String description) {
+ this(clazz, Predicates.<RelNode>alwaysTrue(), in, out, description);
+ }
+
+ /**
+ * Creates a <code>ConverterRule</code> with a predicate.
+ *
+ * @param clazz Type of relational expression to consider converting
+ * @param predicate Predicate on the relational expression
+ * @param in Trait of relational expression to consider converting
+ * @param out Trait which is converted to
+ * @param description Description of rule
+ */
+ public <R extends RelNode> ConverterRule(Class<R> clazz,
+ Predicate<? super R> predicate, RelTrait in, RelTrait out,
String description) {
- super(
- new ConverterRelOptRuleOperand(clazz, in),
+ super(new ConverterRelOptRuleOperand(clazz, in, predicate),
description == null
? "ConverterRule<in=" + in + ",out=" + out + ">"
: description);
- assert in != null;
- assert out != null;
+ this.inTrait = Preconditions.checkNotNull(in);
+ this.outTrait = Preconditions.checkNotNull(out);
// Source and target traits must have same type
assert in.getTraitDef() == out.getTraitDef();
-
- this.inTrait = in;
- this.outTrait = out;
}
//~ Methods ----------------------------------------------------------------
@@ -116,9 +126,9 @@ public abstract class ConverterRule extends RelOptRule {
* Operand to an instance of the converter rule.
*/
private static class ConverterRelOptRuleOperand extends RelOptRuleOperand {
- public ConverterRelOptRuleOperand(
- Class<? extends RelNode> clazz, RelTrait in) {
- super(clazz, in, Predicates.<RelNode>alwaysTrue(), any());
+ public <R extends RelNode> ConverterRelOptRuleOperand(Class<R> clazz,
+ RelTrait in, Predicate<? super R> predicate) {
+ super(clazz, in, predicate, any());
}
public boolean matches(RelNode rel) {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/rel/core/Window.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Window.java b/core/src/main/java/org/apache/calcite/rel/core/Window.java
index fc090f8..b8885b4 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Window.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Window.java
@@ -18,6 +18,8 @@ package org.apache.calcite.rel.core;
import org.apache.calcite.linq4j.Ord;
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.RelCollationImpl;
@@ -25,6 +27,7 @@ import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rel.SingleRel;
+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.RexChecker;
@@ -167,6 +170,21 @@ public abstract class Window extends SingleRel {
return constants;
}
+ public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ // Cost is proportional to the number of rows and the number of
+ // components (groups and aggregate functions). There is
+ // no I/O cost.
+ //
+ // TODO #1. Add memory cost.
+ // TODO #2. MIN and MAX have higher CPU cost than SUM and COUNT.
+ final double rowsIn = RelMetadataQuery.getRowCount(getInput());
+ int count = groups.size();
+ for (Group group : groups) {
+ count += group.aggCalls.size();
+ }
+ return planner.getCostFactory().makeCost(rowsIn, rowsIn * count, 0);
+ }
+
/**
* Group of windowed aggregate calls that have the same window specification.
*
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java b/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
index 51e0beb..1e43611 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
@@ -33,6 +33,7 @@ import org.apache.calcite.prepare.CalcitePrepareImpl;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.Util;
import com.google.common.collect.ImmutableList;
@@ -78,7 +79,7 @@ public class RexExecutorImpl implements RelOptPlanner.Executor {
Expressions.convert_(root0_, DataContext.class)));
final List<Expression> expressions =
RexToLixTranslator.translateProjects(programBuilder.getProgram(),
- javaTypeFactory, blockBuilder, null, getter, null);
+ javaTypeFactory, blockBuilder, null, root_, getter, null);
blockBuilder.add(
Expressions.return_(null,
Expressions.newArrayInit(Object[].class, expressions)));
@@ -88,7 +89,7 @@ public class RexExecutorImpl implements RelOptPlanner.Executor {
ImmutableList.of(root0_), blockBuilder.toBlock());
String code = Expressions.toString(methodDecl);
if (CalcitePrepareImpl.DEBUG) {
- System.out.println(code);
+ Util.debugCode(System.out, code);
}
return code;
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/runtime/ArrayBindable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/ArrayBindable.java b/core/src/main/java/org/apache/calcite/runtime/ArrayBindable.java
new file mode 100644
index 0000000..2c3e078
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/runtime/ArrayBindable.java
@@ -0,0 +1,30 @@
+/*
+ * 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.runtime;
+
+/**
+ * Extension to {@link Bindable} that returns rows that are arrays of objects.
+ *
+ * <p>It also implements {@link Typed}; the {@link #getElementType()} method
+ * must return {@code Object[].class}.
+ */
+public interface ArrayBindable extends Bindable<Object[]>, Typed {
+ // override
+ Class<Object[]> getElementType();
+}
+
+// End ArrayBindable.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java b/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java
index a2a4140..52dc9d5 100644
--- a/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java
+++ b/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java
@@ -80,7 +80,7 @@ public class AggregateFunctionImpl implements AggregateFunction,
}
/** Creates an aggregate function, or returns null. */
- public static AggregateFunction create(Class<?> clazz) {
+ public static AggregateFunctionImpl create(Class<?> clazz) {
final Method initMethod = ReflectiveFunctionBase.findMethod(clazz, "init");
final Method addMethod = ReflectiveFunctionBase.findMethod(clazz, "add");
final Method mergeMethod = null; // TODO:
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/sql/SqlKind.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index 8d37d4c..2f3cf26 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -94,8 +94,8 @@ public enum SqlKind {
* JOIN operator or compound FROM clause.
*
* <p>A FROM clause with more than one table is represented as if it were a
- * join. For example, "FROM x, y, z" is represented as "JOIN(x, JOIN(x,
- * y))".</p>
+ * join. For example, "FROM x, y, z" is represented as
+ * "JOIN(x, JOIN(x, y))".</p>
*/
JOIN,
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/tools/Programs.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Programs.java b/core/src/main/java/org/apache/calcite/tools/Programs.java
index a16e83c..115cbf1 100644
--- a/core/src/main/java/org/apache/calcite/tools/Programs.java
+++ b/core/src/main/java/org/apache/calcite/tools/Programs.java
@@ -17,6 +17,7 @@
package org.apache.calcite.tools;
import org.apache.calcite.adapter.enumerable.EnumerableRules;
+import org.apache.calcite.interpreter.NoneToBindableConverterRule;
import org.apache.calcite.plan.RelOptCostImpl;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelOptRule;
@@ -76,6 +77,7 @@ public class Programs {
public static final ImmutableList<RelOptRule> CALC_RULES =
ImmutableList.of(
+ NoneToBindableConverterRule.INSTANCE,
EnumerableRules.ENUMERABLE_CALC_RULE,
EnumerableRules.ENUMERABLE_FILTER_TO_CALC_RULE,
EnumerableRules.ENUMERABLE_PROJECT_TO_CALC_RULE,
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index b03d0d4..779196a 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -21,7 +21,9 @@ import org.apache.calcite.adapter.java.ReflectiveSchema;
import org.apache.calcite.adapter.jdbc.JdbcSchema;
import org.apache.calcite.avatica.util.DateTimeUtils;
import org.apache.calcite.avatica.util.TimeUnitRange;
+import org.apache.calcite.interpreter.Context;
import org.apache.calcite.interpreter.Row;
+import org.apache.calcite.interpreter.Scalar;
import org.apache.calcite.linq4j.AbstractEnumerable;
import org.apache.calcite.linq4j.CorrelateJoinType;
import org.apache.calcite.linq4j.Enumerable;
@@ -43,6 +45,7 @@ import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.linq4j.tree.Types;
import org.apache.calcite.rel.metadata.Metadata;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.runtime.ArrayBindable;
import org.apache.calcite.runtime.BinarySearch;
import org.apache.calcite.runtime.Bindable;
import org.apache.calcite.runtime.Enumerables;
@@ -50,7 +53,6 @@ import org.apache.calcite.runtime.FlatLists;
import org.apache.calcite.runtime.ResultSetEnumerable;
import org.apache.calcite.runtime.SortedMultiMap;
import org.apache.calcite.runtime.SqlFunctions;
-import org.apache.calcite.runtime.Typed;
import org.apache.calcite.schema.FilterableTable;
import org.apache.calcite.schema.ModifiableTable;
import org.apache.calcite.schema.QueryableTable;
@@ -63,6 +65,7 @@ import org.apache.calcite.sql.SqlExplainLevel;
import com.google.common.collect.ImmutableMap;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.Time;
@@ -174,7 +177,7 @@ public enum BuiltInMethod {
ENUMERATOR_RESET(Enumerator.class, "reset"),
ENUMERABLE_ENUMERATOR(Enumerable.class, "enumerator"),
ENUMERABLE_FOREACH(Enumerable.class, "foreach", Function1.class),
- TYPED_GET_ELEMENT_TYPE(Typed.class, "getElementType"),
+ TYPED_GET_ELEMENT_TYPE(ArrayBindable.class, "getElementType"),
BINDABLE_BIND(Bindable.class, "bind", DataContext.class),
RESULT_SET_GET_DATE2(ResultSet.class, "getDate", int.class, Calendar.class),
RESULT_SET_GET_TIME2(ResultSet.class, "getTime", int.class, Calendar.class),
@@ -295,12 +298,17 @@ public enum BuiltInMethod {
NON_CUMULATIVE_COST(NonCumulativeCost.class, "getNonCumulativeCost"),
EXPLAIN_VISIBILITY(ExplainVisibility.class, "isVisibleInExplain",
SqlExplainLevel.class),
+ SCALAR_EXECUTE1(Scalar.class, "execute", Context.class),
+ SCALAR_EXECUTE2(Scalar.class, "execute", Context.class, Object[].class),
+ CONTEXT_VALUES(Context.class, "values", true),
+ CONTEXT_ROOT(Context.class, "root", true),
DATA_CONTEXT_GET_QUERY_PROVIDER(DataContext.class, "getQueryProvider"),
PREDICATES(Predicates.class, "getPredicates"),
METADATA_REL(Metadata.class, "rel");
public final Method method;
public final Constructor constructor;
+ public final Field field;
public static final ImmutableMap<Method, BuiltInMethod> MAP;
@@ -318,11 +326,19 @@ public enum BuiltInMethod {
BuiltInMethod(Class clazz, String methodName, Class... argumentTypes) {
this.method = Types.lookupMethod(clazz, methodName, argumentTypes);
this.constructor = null;
+ this.field = null;
}
BuiltInMethod(Class clazz, Class... argumentTypes) {
this.method = null;
this.constructor = Types.lookupConstructor(clazz, argumentTypes);
+ this.field = null;
+ }
+
+ BuiltInMethod(Class clazz, String fieldName, boolean dummy) {
+ this.method = null;
+ this.constructor = null;
+ this.field = Types.lookupField(clazz, fieldName);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/util/Util.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java
index d25ba3c..4831a60 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.util;
+import org.apache.calcite.avatica.util.Spaces;
import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.runtime.CalciteException;
@@ -30,12 +31,15 @@ import com.google.common.collect.ImmutableMap;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
+import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Array;
@@ -1913,8 +1917,9 @@ public class Util {
* Returns the ordinal of the first element in the list which is equal to a
* previous element in the list.
*
- * <p>For example, <code>firstDuplicate(Arrays.asList("a", "b", "c", "b",
- * "a"))</code> returns 3, the ordinal of the 2nd "b".
+ * <p>For example,
+ * <code>firstDuplicate(Arrays.asList("a", "b", "c", "b", "a"))</code>
+ * returns 3, the ordinal of the 2nd "b".
*
* @param list List
* @return Ordinal of first duplicate, or -1 if not found
@@ -2065,6 +2070,30 @@ public class Util {
};
}
+ /**
+ * Prints the given code with line numbering.
+ */
+ public static void debugCode(PrintStream out, String code) {
+ out.println();
+ StringReader sr = new StringReader(code);
+ BufferedReader br = new BufferedReader(sr);
+ try {
+ String line;
+ for (int i = 1; (line = br.readLine()) != null; i++) {
+ out.print("/*");
+ String number = Integer.toString(i);
+ if (number.length() < 4) {
+ Spaces.append(out, 4 - number.length());
+ }
+ out.print(number);
+ out.print(" */ ");
+ out.println(line);
+ }
+ } catch (IOException e) {
+ // not possible
+ }
+ }
+
//~ Inner Classes ----------------------------------------------------------
/**
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
index e419651..bec93d8 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -2433,40 +2433,46 @@ public class SqlParserTest {
// CURRENT_TIME - returns time w/ timezone
checkExp("CURRENT_TIME(3)", "CURRENT_TIME(3)");
- // checkFails("SELECT CURRENT_TIME() FROM foo", "SELECT CURRENT_TIME()
- // FROM `FOO`");
+ // checkFails("SELECT CURRENT_TIME() FROM foo",
+ // "SELECT CURRENT_TIME() FROM `FOO`");
+
checkExp("CURRENT_TIME", "`CURRENT_TIME`");
checkExp("CURRENT_TIME(x+y)", "CURRENT_TIME((`X` + `Y`))");
// LOCALTIME returns time w/o TZ
checkExp("LOCALTIME(3)", "LOCALTIME(3)");
- // checkFails("SELECT LOCALTIME() FROM foo", "SELECT LOCALTIME() FROM
- // `FOO`");
+ // checkFails("SELECT LOCALTIME() FROM foo",
+ // "SELECT LOCALTIME() FROM `FOO`");
+
checkExp("LOCALTIME", "`LOCALTIME`");
checkExp("LOCALTIME(x+y)", "LOCALTIME((`X` + `Y`))");
// LOCALTIMESTAMP - returns timestamp w/o TZ
checkExp("LOCALTIMESTAMP(3)", "LOCALTIMESTAMP(3)");
- // checkFails("SELECT LOCALTIMESTAMP() FROM foo", "SELECT
- // LOCALTIMESTAMP() FROM `FOO`");
+ // checkFails("SELECT LOCALTIMESTAMP() FROM foo",
+ // "SELECT LOCALTIMESTAMP() FROM `FOO`");
+
checkExp("LOCALTIMESTAMP", "`LOCALTIMESTAMP`");
checkExp("LOCALTIMESTAMP(x+y)", "LOCALTIMESTAMP((`X` + `Y`))");
// CURRENT_DATE - returns DATE
checkExp("CURRENT_DATE(3)", "CURRENT_DATE(3)");
- // checkFails("SELECT CURRENT_DATE() FROM foo", "SELECT CURRENT_DATE()
- // FROM `FOO`");
+ // checkFails("SELECT CURRENT_DATE() FROM foo",
+ // "SELECT CURRENT_DATE() FROM `FOO`");
checkExp("CURRENT_DATE", "`CURRENT_DATE`");
- // checkFails("SELECT CURRENT_DATE(x+y) FROM foo", "CURRENT_DATE((`X` +
- // `Y`))"); CURRENT_TIMESTAMP - returns timestamp w/ TZ
+ // checkFails("SELECT CURRENT_DATE(x+y) FROM foo",
+ // "CURRENT_DATE((`X` + `Y`))");
+
+ // CURRENT_TIMESTAMP - returns timestamp w/ TZ
checkExp("CURRENT_TIMESTAMP(3)", "CURRENT_TIMESTAMP(3)");
- // checkFails("SELECT CURRENT_TIMESTAMP() FROM foo", "SELECT
- // CURRENT_TIMESTAMP() FROM `FOO`");
+ // checkFails("SELECT CURRENT_TIMESTAMP() FROM foo",
+ // "SELECT CURRENT_TIMESTAMP() FROM `FOO`");
+
checkExp("CURRENT_TIMESTAMP", "`CURRENT_TIMESTAMP`");
checkExp("CURRENT_TIMESTAMP(x+y)", "CURRENT_TIMESTAMP((`X` + `Y`))");
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/InterpreterTest.java b/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
index 77a9311..042e37e 100644
--- a/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
@@ -100,9 +100,7 @@ public class InterpreterTest {
RelNode convert = planner.convert(validate);
final Interpreter interpreter = new Interpreter(null, convert);
- assertRows(interpreter,
- "[_ISO-8859-1'b', 2]",
- "[_ISO-8859-1'c', 3]");
+ assertRows(interpreter, "[b, 2]", "[c, 3]");
}
private static void assertRows(Interpreter interpreter, String... rows) {
@@ -209,6 +207,39 @@ public class InterpreterTest {
new Interpreter(new MyDataContext(planner), convert);
assertRows(interpreter, "[0]", "[10]");
}
+
+ /** Tests executing a UNION ALL query using an interpreter. */
+ @Test public void testInterpretUnionAll() throws Exception {
+ rootSchema.add("simple", new ScannableTableTest.SimpleTable());
+ SqlNode parse =
+ planner.parse("select * from \"simple\"\n"
+ + "union all\n"
+ + "select * from \"simple\"\n");
+
+ SqlNode validate = planner.validate(parse);
+ RelNode convert = planner.convert(validate);
+
+ final Interpreter interpreter =
+ new Interpreter(new MyDataContext(planner), convert);
+ assertRows(interpreter,
+ "[0]", "[10]", "[20]", "[30]", "[0]", "[10]", "[20]", "[30]");
+ }
+
+ /** Tests executing a UNION query using an interpreter. */
+ @Test public void testInterpretUnion() throws Exception {
+ rootSchema.add("simple", new ScannableTableTest.SimpleTable());
+ SqlNode parse =
+ planner.parse("select * from \"simple\"\n"
+ + "union\n"
+ + "select * from \"simple\"\n");
+
+ SqlNode validate = planner.validate(parse);
+ RelNode convert = planner.convert(validate);
+
+ final Interpreter interpreter =
+ new Interpreter(new MyDataContext(planner), convert);
+ assertRows(interpreter, "[0]", "[10]", "[20]", "[30]");
+ }
}
// End InterpreterTest.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/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 5a89d9a..6727c68 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -2129,6 +2129,7 @@ public class JdbcTest {
/** Tests that a relatively complex query on the foodmart schema creates
* an in-memory aggregate table and then uses it. */
+ @Ignore // DO NOT CHECK IN
@Test public void testFoodmartLattice() throws IOException {
// 8: select ... from customer, sales, time ... group by ...
final FoodmartTest.FoodmartQuery query =
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/test/java/org/apache/calcite/test/LatticeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/LatticeTest.java b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
index ebd19b3..4f53fbb 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -299,7 +299,7 @@ public class LatticeTest {
.enableMaterializations(true)
.explainContains(""
+ "EnumerableCalc(expr#0..3=[{inputs}], expr#4=[10], expr#5=[*($t3, $t4)], proj#0..2=[{exprs}], US=[$t5])\n"
- + " EnumerableAggregate(group=[{0}], C=[$SUM0($2)], Q=[MIN($1)], agg#2=[SUM($4)])\n"
+ + " EnumerableAggregate(group=[{0}], C=[$SUM0($2)], Q=[MIN($1)], agg#2=[$SUM0($4)])\n"
+ " EnumerableTableScan(table=[[adhoc, m{27, 31}")
.returnsUnordered("the_year=1997; C=86837; Q=Q1; US=2667730.0000")
.sameResultWithMaterializationsDisabled();
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/test/resources/sql/misc.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.oq b/core/src/test/resources/sql/misc.oq
index 152b827..142eba6 100644
--- a/core/src/test/resources/sql/misc.oq
+++ b/core/src/test/resources/sql/misc.oq
@@ -480,7 +480,7 @@ from "sales_fact_1997" as s
join "product_class" as pc using ("product_class_id")
where c."city" = 'San Francisco'
and pc."product_department" = 'Snacks';
-EnumerableCalc(expr#0..56=[{inputs}], $f0=[$t20], $f1=[$t21], $f2=[$t22], $f3=[$t23], $f4=[$t24], $f5=[$t25], $f6=[$t26], $f7=[$t27], $f8=[$t28], $f9=[$t29], $f10=[$t30], $f11=[$t31], $f12=[$t32], $f13=[$t33], $f14=[$t34], $f15=[$t35], $f16=[$t36], $f17=[$t37], $f18=[$t38], $f19=[$t39], $f20=[$t40], $f21=[$t41], $f22=[$t42], $f23=[$t43], $f24=[$t44], $f25=[$t45], $f26=[$t46], $f27=[$t47], $f28=[$t48], $f29=[$t49], $f30=[$t50], $f31=[$t51], $f32=[$t52], $f33=[$t53], $f34=[$t54], $f35=[$t55], $f36=[$t56], $f37=[$t5], $f38=[$t6], $f39=[$t7], $f40=[$t8], $f41=[$t9], $f42=[$t10], $f43=[$t11], $f44=[$t12], $f45=[$t13], $f46=[$t14], $f47=[$t15], $f48=[$t16], $f49=[$t17], $f50=[$t18], $f51=[$t19], $f52=[$t0], $f53=[$t1], $f54=[$t2], $f55=[$t3], $f56=[$t4])
+EnumerableCalc(expr#0..56=[{inputs}], product_id=[$t20], time_id=[$t21], customer_id=[$t22], promotion_id=[$t23], store_id=[$t24], store_sales=[$t25], store_cost=[$t26], unit_sales=[$t27], customer_id0=[$t28], account_num=[$t29], lname=[$t30], fname=[$t31], mi=[$t32], address1=[$t33], address2=[$t34], address3=[$t35], address4=[$t36], city=[$t37], state_province=[$t38], postal_code=[$t39], country=[$t40], customer_region_id=[$t41], phone1=[$t42], phone2=[$t43], birthdate=[$t44], marital_status=[$t45], yearly_income=[$t46], gender=[$t47], total_children=[$t48], num_children_at_home=[$t49], education=[$t50], date_accnt_opened=[$t51], member_card=[$t52], occupation=[$t53], houseowner=[$t54], num_cars_owned=[$t55], fullname=[$t56], product_class_id=[$t5], product_id0=[$t6], brand_name=[$t7], product_name=[$t8], SKU=[$t9], SRP=[$t10], gross_weight=[$t11], net_weight=[$t12], recyclable_package=[$t13], low_fat=[$t14], units_per_case=[$t15], cases_per_pallet=[$t16], shelf_width=[$t17], shel
f_height=[$t18], shelf_depth=[$t19], product_class_id0=[$t0], product_subcategory=[$t1], product_category=[$t2], product_department=[$t3], product_family=[$t4])
EnumerableJoin(condition=[=($6, $20)], joinType=[inner])
EnumerableJoin(condition=[=($0, $5)], joinType=[inner])
EnumerableCalc(expr#0..4=[{inputs}], expr#5=['Snacks'], expr#6=[=($t3, $t5)], proj#0..4=[{exprs}], $condition=[$t6])
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
index da5e60a..67e39af 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
@@ -48,8 +48,9 @@ public class ConditionalExpression extends AbstractNode {
.append(Blocks.toBlock(expressionList.get(i + 1)));
}
if (expressionList.size() % 2 == 1) {
- writer.append(" else ").append(Blocks.toBlock(expressionList.get(
- expressionList.size() - 1)));
+ writer.append(" else ")
+ .append(
+ Blocks.toBlock(expressionList.get(expressionList.size() - 1)));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
index 01bc947..cfe794c 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
@@ -380,6 +380,15 @@ public abstract class Types {
.toString(argumentTypes));
}
+ public static Field lookupField(Type type, String name) {
+ final Class clazz = toClass(type);
+ try {
+ return clazz.getField(name);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException("while resolving field in class " + type);
+ }
+ }
+
public static void discard(Object o) {
if (false) {
discard(o);
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/spark/src/main/java/org/apache/calcite/adapter/spark/SparkHandlerImpl.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/calcite/adapter/spark/SparkHandlerImpl.java b/spark/src/main/java/org/apache/calcite/adapter/spark/SparkHandlerImpl.java
index 38b1c09..5086dad 100644
--- a/spark/src/main/java/org/apache/calcite/adapter/spark/SparkHandlerImpl.java
+++ b/spark/src/main/java/org/apache/calcite/adapter/spark/SparkHandlerImpl.java
@@ -22,8 +22,7 @@ import org.apache.calcite.linq4j.tree.ClassDeclaration;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.runtime.Bindable;
-import org.apache.calcite.runtime.Typed;
+import org.apache.calcite.runtime.ArrayBindable;
import org.apache.calcite.util.javac.JaninoCompiler;
import org.apache.spark.api.java.JavaSparkContext;
@@ -102,14 +101,13 @@ public class SparkHandlerImpl implements CalcitePrepare.SparkHandler {
return true;
}
- public Bindable compile(ClassDeclaration expr, String s) {
+ public ArrayBindable compile(ClassDeclaration expr, String s) {
try {
String className = "CalciteProgram" + classId.getAndIncrement();
File file = new File(SRC_DIR, className + ".java");
FileWriter fileWriter = new FileWriter(file, false);
String source = "public class " + className + "\n"
- + " implements " + Bindable.class.getName()
- + ", " + Typed.class.getName()
+ + " implements " + ArrayBindable.class.getName()
+ ", " + Serializable.class.getName()
+ " {\n"
+ s + "\n"
@@ -128,7 +126,7 @@ public class SparkHandlerImpl implements CalcitePrepare.SparkHandler {
compiler.compile();
Class<?> clazz = Class.forName(className);
Object o = clazz.newInstance();
- return (Bindable) o;
+ return (ArrayBindable) o;
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java b/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java
index 0d89f6f..24ebc99 100644
--- a/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java
+++ b/spark/src/main/java/org/apache/calcite/adapter/spark/SparkRules.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.adapter.spark;
+import org.apache.calcite.DataContext;
import org.apache.calcite.adapter.enumerable.EnumerableConvention;
import org.apache.calcite.adapter.enumerable.JavaRowFormat;
import org.apache.calcite.adapter.enumerable.PhysType;
@@ -343,7 +344,8 @@ public abstract class SparkRules {
builder2,
new RexToLixTranslator.InputGetterImpl(
Collections.singletonList(
- Pair.of((Expression) e_, result.physType))), null);
+ Pair.of((Expression) e_, result.physType))),
+ null);
builder2.add(
Expressions.ifThen(
Expressions.not(condition),
@@ -358,9 +360,11 @@ public abstract class SparkRules {
typeFactory,
builder2,
null,
+ DataContext.ROOT,
new RexToLixTranslator.InputGetterImpl(
Collections.singletonList(
- Pair.of((Expression) e_, result.physType))), null);
+ Pair.of((Expression) e_, result.physType))),
+ null);
builder2.add(
Expressions.return_(null,
Expressions.convert_(
[3/3] incubator-calcite git commit: [CALCITE-544] Implement Union in
Interpreter;
[CALCITE-562] Implement inner JOIN in interpreter and improve handling of
scalar expressions
Posted by jh...@apache.org.
[CALCITE-544] Implement Union in Interpreter;
[CALCITE-562] Implement inner JOIN in interpreter and improve handling of scalar expressions
Also, progress towards [CALCITE-558] Add BINDABLE convention and make it the default convention for query root, but currently ENUMERABLE is still the default. You can enable BINDABLE by setting CalcitePrepareImpl.ENABLE_BINDABLE; there are 184 test failures.
New interface ArrayBindable extends Bindable. Unlike Bindable the return is guaranteed to be an Object[]. Enumerable convention expects generated code to return a Bindable, which might return custom classes or arrays, and if there is a single column, the array is optimized to the raw column value. Bindable convention assumes that relational expressions implement ArrayBindable and return arrays of column values; the arrays are not optimized if there is only one column.
New interface Scalar represents a compiled way to execute a scalar expression (or expressions) and is easily built from a RexNode or AggregateCall.
Close apache/incubator-calcite#43
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/66cfb120
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/66cfb120
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/66cfb120
Branch: refs/heads/master
Commit: 66cfb120fca58e4c809748e2bcef4d3d5a7c6b82
Parents: 4e18540
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Dec 29 17:40:39 2014 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Jan 21 15:57:37 2015 -0800
----------------------------------------------------------------------
.../calcite/adapter/clone/ArrayTable.java | 21 +-
.../calcite/adapter/enumerable/AggImpState.java | 2 +-
.../calcite/adapter/enumerable/EnumUtils.java | 2 -
.../adapter/enumerable/EnumerableAggregate.java | 14 +-
.../adapter/enumerable/EnumerableBindable.java | 102 ++++
.../adapter/enumerable/EnumerableCalc.java | 2 +
.../adapter/enumerable/EnumerableCalcRule.java | 21 +-
.../enumerable/EnumerableConvention.java | 4 +
.../enumerable/EnumerableFilterRule.java | 20 +-
.../enumerable/EnumerableInterpretable.java | 205 +++++++
.../enumerable/EnumerableProjectRule.java | 20 +-
.../enumerable/EnumerableRelImplementor.java | 2 +-
.../adapter/enumerable/EnumerableSort.java | 4 +-
.../adapter/enumerable/EnumerableWindow.java | 32 +-
.../enumerable/EnumerableWindowRule.java | 4 +-
.../adapter/enumerable/JavaRowFormat.java | 1 -
.../adapter/enumerable/PhysTypeImpl.java | 17 +-
.../calcite/adapter/enumerable/RexImpTable.java | 12 +-
.../adapter/enumerable/RexToLixTranslator.java | 71 ++-
.../calcite/adapter/java/ReflectiveSchema.java | 36 +-
.../apache/calcite/adapter/jdbc/JdbcTable.java | 12 +-
.../calcite/interpreter/AggregateNode.java | 345 +++++++++--
.../calcite/interpreter/BindableConvention.java | 64 ++
.../apache/calcite/interpreter/BindableRel.java | 31 +
.../apache/calcite/interpreter/Bindables.java | 583 +++++++++++++++++++
.../org/apache/calcite/interpreter/Context.java | 8 +
.../apache/calcite/interpreter/FilterNode.java | 13 +-
.../interpreter/InterpretableConvention.java | 58 ++
.../interpreter/InterpretableConverter.java | 55 ++
.../calcite/interpreter/InterpretableRel.java | 55 ++
.../apache/calcite/interpreter/Interpreter.java | 182 +++---
.../calcite/interpreter/Interpreters.java | 50 ++
.../calcite/interpreter/JaninoRexCompiler.java | 191 ++++++
.../apache/calcite/interpreter/JoinNode.java | 76 +++
.../org/apache/calcite/interpreter/Nodes.java | 20 +-
.../NoneToBindableConverterRule.java | 44 ++
.../apache/calcite/interpreter/ProjectNode.java | 27 +-
.../org/apache/calcite/interpreter/Scalar.java | 1 +
.../apache/calcite/interpreter/ScanNode.java | 173 ------
.../apache/calcite/interpreter/SortNode.java | 47 +-
.../calcite/interpreter/TableScanNode.java | 174 ++++++
.../apache/calcite/interpreter/UnionNode.java | 58 ++
.../apache/calcite/interpreter/ValuesNode.java | 38 +-
.../apache/calcite/interpreter/WindowNode.java | 39 ++
.../org/apache/calcite/jdbc/CalcitePrepare.java | 5 +-
.../org/apache/calcite/plan/RelOptUtil.java | 40 ++
.../org/apache/calcite/plan/RelTraitSet.java | 12 +
.../org/apache/calcite/plan/volcano/RelSet.java | 5 +
.../calcite/plan/volcano/VolcanoPlanner.java | 30 +
.../calcite/prepare/CalciteMaterializer.java | 4 +-
.../calcite/prepare/CalcitePrepareImpl.java | 145 ++---
.../org/apache/calcite/prepare/Prepare.java | 23 +-
.../apache/calcite/prepare/RelOptTableImpl.java | 25 +-
.../calcite/rel/convert/ConverterRule.java | 38 +-
.../org/apache/calcite/rel/core/Window.java | 18 +
.../org/apache/calcite/rex/RexExecutorImpl.java | 5 +-
.../apache/calcite/runtime/ArrayBindable.java | 30 +
.../schema/impl/AggregateFunctionImpl.java | 2 +-
.../java/org/apache/calcite/sql/SqlKind.java | 4 +-
.../java/org/apache/calcite/tools/Programs.java | 2 +
.../org/apache/calcite/util/BuiltInMethod.java | 20 +-
.../main/java/org/apache/calcite/util/Util.java | 33 +-
.../calcite/sql/parser/SqlParserTest.java | 30 +-
.../apache/calcite/test/InterpreterTest.java | 37 +-
.../java/org/apache/calcite/test/JdbcTest.java | 1 +
.../org/apache/calcite/test/LatticeTest.java | 2 +-
core/src/test/resources/sql/misc.oq | 2 +-
.../linq4j/tree/ConditionalExpression.java | 5 +-
.../org/apache/calcite/linq4j/tree/Types.java | 9 +
.../calcite/adapter/spark/SparkHandlerImpl.java | 10 +-
.../calcite/adapter/spark/SparkRules.java | 8 +-
71 files changed, 2830 insertions(+), 651 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java b/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java
index 7c7ccf3..5d1c58a 100644
--- a/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java
@@ -16,7 +16,10 @@
*/
package org.apache.calcite.adapter.clone;
+import org.apache.calcite.DataContext;
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.Ord;
import org.apache.calcite.linq4j.QueryProvider;
@@ -25,6 +28,7 @@ import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelProtoDataType;
+import org.apache.calcite.schema.ScannableTable;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.Statistic;
import org.apache.calcite.schema.Statistics;
@@ -49,7 +53,7 @@ import java.util.List;
* values in the column; see {@link Representation} and
* {@link RepresentationType}.
*/
-class ArrayTable extends AbstractQueryableTable {
+class ArrayTable extends AbstractQueryableTable implements ScannableTable {
private final RelProtoDataType protoRowType;
private final Supplier<Content> supplier;
@@ -76,6 +80,15 @@ class ArrayTable extends AbstractQueryableTable {
return Statistics.of(content.size, keys);
}
+ public Enumerable<Object[]> scan(DataContext root) {
+ return new AbstractEnumerable<Object[]>() {
+ public Enumerator<Object[]> enumerator() {
+ final Content content = supplier.get();
+ return content.arrayEnumerator();
+ }
+ };
+ }
+
public <T> Queryable<T> asQueryable(final QueryProvider queryProvider,
SchemaPlus schema, String tableName) {
return new AbstractTableQueryable<T>(queryProvider, schema, this,
@@ -802,6 +815,10 @@ class ArrayTable extends AbstractQueryableTable {
}
}
+ public Enumerator<Object[]> arrayEnumerator() {
+ return new ArrayEnumerator(size, columns);
+ }
+
/** Enumerator over a table with a single column; each element
* returned is an object. */
private static class ObjectEnumerator implements Enumerator<Object> {
@@ -834,7 +851,7 @@ class ArrayTable extends AbstractQueryableTable {
/** Enumerator over a table with more than one column; each element
* returned is an array. */
- private static class ArrayEnumerator implements Enumerator {
+ private static class ArrayEnumerator implements Enumerator<Object[]> {
final int rowCount;
final List<Column> columns;
int i = -1;
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/AggImpState.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/AggImpState.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/AggImpState.java
index 1c8909a..b100cec 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/AggImpState.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/AggImpState.java
@@ -24,7 +24,7 @@ import java.util.List;
/**
* Represents internal state when implementing aggregate functions.
*/
-class AggImpState {
+public class AggImpState {
public final int aggIdx;
public final AggregateCall call;
public final AggImplementor implementor;
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java
index d1948f1..17e0bf5 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java
@@ -56,8 +56,6 @@ public class EnumUtils {
public static final String[] LEFT_RIGHT = {"left", "right"};
- static final boolean B = false;
-
/** Declares a method that overrides another method. */
public static MethodDeclaration overridingMethodDecl(Method method,
Iterable<ParameterExpression> parameters,
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
index 532821f..38f3ee9 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
@@ -38,13 +38,11 @@ import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.SqlAggFunction;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.util.BuiltInMethod;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.lang.reflect.Type;
@@ -54,15 +52,7 @@ import java.util.List;
/** Implementation of {@link org.apache.calcite.rel.core.Aggregate} in
* {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
-public class EnumerableAggregate extends Aggregate
- implements EnumerableRel {
- private static final List<SqlAggFunction> SUPPORTED_AGGREGATIONS =
- ImmutableList.of(
- SqlStdOperatorTable.COUNT,
- SqlStdOperatorTable.MIN,
- SqlStdOperatorTable.MAX,
- SqlStdOperatorTable.SUM);
-
+public class EnumerableAggregate extends Aggregate implements EnumerableRel {
public EnumerableAggregate(
RelOptCluster cluster,
RelTraitSet traitSet,
@@ -209,7 +199,7 @@ public class EnumerableAggregate extends Aggregate
for (final AggImpState agg : aggs) {
agg.context =
new AggContext() {
- public org.apache.calcite.sql.SqlAggFunction aggregation() {
+ public SqlAggFunction aggregation() {
return agg.call.getAggregation();
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBindable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBindable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBindable.java
new file mode 100644
index 0000000..2ad069e
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBindable.java
@@ -0,0 +1,102 @@
+/*
+ * 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.enumerable;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.interpreter.BindableConvention;
+import org.apache.calcite.interpreter.BindableRel;
+import org.apache.calcite.interpreter.Node;
+import org.apache.calcite.interpreter.Row;
+import org.apache.calcite.interpreter.Sink;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.ConverterImpl;
+import org.apache.calcite.rel.convert.ConverterRule;
+import org.apache.calcite.runtime.ArrayBindable;
+import org.apache.calcite.runtime.Bindable;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.List;
+
+/**
+ * Relational expression that converts an enumerable input to interpretable
+ * calling convention.
+ *
+ * @see org.apache.calcite.adapter.enumerable.EnumerableConvention
+ * @see org.apache.calcite.interpreter.BindableConvention
+ */
+public class EnumerableBindable extends ConverterImpl implements BindableRel {
+ protected EnumerableBindable(RelOptCluster cluster, RelNode input) {
+ super(cluster, ConventionTraitDef.INSTANCE,
+ cluster.traitSetOf(BindableConvention.INSTANCE), input);
+ }
+
+ @Override public EnumerableBindable copy(RelTraitSet traitSet,
+ List<RelNode> inputs) {
+ return new EnumerableBindable(getCluster(), sole(inputs));
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ final ImmutableMap<String, Object> map = ImmutableMap.of();
+ final Bindable bindable = EnumerableInterpretable.toBindable(map, null,
+ (EnumerableRel) getInput(), EnumerableRel.Prefer.ARRAY);
+ final ArrayBindable arrayBindable = EnumerableInterpretable.box(bindable);
+ return arrayBindable.bind(dataContext);
+ }
+
+ public Node implement(final InterpreterImplementor implementor) {
+ return new Node() {
+ public void run() throws InterruptedException {
+ final Sink sink =
+ implementor.relSinks.get(EnumerableBindable.this).get(0);
+ final Enumerable<Object[]> enumerable = bind(implementor.dataContext);
+ final Enumerator<Object[]> enumerator = enumerable.enumerator();
+ while (enumerator.moveNext()) {
+ sink.send(Row.asCopy(enumerator.current()));
+ }
+ }
+ };
+ }
+
+ /**
+ * Rule that converts any enumerable relational expression to bindable.
+ */
+ public static class EnumerableToBindableConverterRule extends ConverterRule {
+ public static final EnumerableToBindableConverterRule INSTANCE =
+ new EnumerableToBindableConverterRule();
+
+ private EnumerableToBindableConverterRule() {
+ super(EnumerableRel.class, EnumerableConvention.INSTANCE,
+ BindableConvention.INSTANCE, "EnumerableToBindableConverterRule");
+ }
+
+ @Override public RelNode convert(RelNode rel) {
+ return new EnumerableBindable(rel.getCluster(), rel);
+ }
+ }
+}
+
+// End EnumerableBindable.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
index b467163..b93256d 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.adapter.enumerable;
+import org.apache.calcite.DataContext;
import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.linq4j.Enumerator;
import org.apache.calcite.linq4j.tree.BlockBuilder;
@@ -144,6 +145,7 @@ public class EnumerableCalc extends Calc implements EnumerableRel {
typeFactory,
builder3,
physType,
+ DataContext.ROOT,
new RexToLixTranslator.InputGetterImpl(
Collections.singletonList(
Pair.of(input, result.physType))),
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
index 35c83dd..793dcf8 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
@@ -17,11 +17,10 @@
package org.apache.calcite.adapter.enumerable;
import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.logical.LogicalCalc;
-import org.apache.calcite.rex.RexMultisetUtil;
-import org.apache.calcite.rex.RexProgram;
/**
* Rule to convert a {@link org.apache.calcite.rel.logical.LogicalCalc} to an
@@ -29,22 +28,14 @@ import org.apache.calcite.rex.RexProgram;
*/
class EnumerableCalcRule extends ConverterRule {
EnumerableCalcRule() {
- super(LogicalCalc.class, Convention.NONE, EnumerableConvention.INSTANCE,
- "EnumerableCalcRule");
+ // The predicate ensures that if there's a multiset, FarragoMultisetSplitter
+ // will work on it first.
+ super(LogicalCalc.class, RelOptUtil.CALC_PREDICATE, Convention.NONE,
+ EnumerableConvention.INSTANCE, "EnumerableCalcRule");
}
public RelNode convert(RelNode rel) {
final LogicalCalc calc = (LogicalCalc) rel;
-
- // If there's a multiset, let FarragoMultisetSplitter work on it
- // first.
- final RexProgram program = calc.getProgram();
- if (EnumUtils.B
- && RexMultisetUtil.containsMultiset(program)
- || program.containsAggs()) {
- return null;
- }
-
return new EnumerableCalc(
rel.getCluster(),
rel.getTraitSet().replace(EnumerableConvention.INSTANCE),
@@ -52,7 +43,7 @@ class EnumerableCalcRule extends ConverterRule {
calc.getInput(),
calc.getInput().getTraitSet()
.replace(EnumerableConvention.INSTANCE)),
- program,
+ calc.getProgram(),
calc.getCollationList());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java
index a8ad841..ac1533a 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java
@@ -29,6 +29,10 @@ import org.apache.calcite.plan.RelTraitDef;
public enum EnumerableConvention implements Convention {
INSTANCE;
+ /** Cost of an enumerable node versus implementing an equivalent node in a
+ * "typical" calling convention. */
+ public static final double COST_MULTIPLIER = 1.0d;
+
@Override public String toString() {
return getName();
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
index 81bbaf2..51fcdd4 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
@@ -17,11 +17,10 @@
package org.apache.calcite.adapter.enumerable;
import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.logical.LogicalFilter;
-import org.apache.calcite.rex.RexMultisetUtil;
-import org.apache.calcite.rex.RexOver;
/**
* Rule to convert a {@link org.apache.calcite.rel.logical.LogicalFilter} to an
@@ -29,24 +28,15 @@ import org.apache.calcite.rex.RexOver;
*/
class EnumerableFilterRule extends ConverterRule {
EnumerableFilterRule() {
- super(LogicalFilter.class, Convention.NONE, EnumerableConvention.INSTANCE,
- "EnumerableFilterRule");
+ super(LogicalFilter.class, RelOptUtil.FILTER_PREDICATE, Convention.NONE,
+ EnumerableConvention.INSTANCE, "EnumerableFilterRule");
}
public RelNode convert(RelNode rel) {
final LogicalFilter filter = (LogicalFilter) rel;
-
- if (EnumUtils.B
- && RexMultisetUtil.containsMultiset(filter.getCondition(), true)
- || RexOver.containsOver(filter.getCondition())) {
- return null;
- }
-
- return new EnumerableFilter(
- rel.getCluster(),
+ return new EnumerableFilter(rel.getCluster(),
rel.getTraitSet().replace(EnumerableConvention.INSTANCE),
- convert(
- filter.getInput(),
+ convert(filter.getInput(),
filter.getInput().getTraitSet()
.replace(EnumerableConvention.INSTANCE)),
filter.getCondition());
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java
new file mode 100644
index 0000000..19d5f2a
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java
@@ -0,0 +1,205 @@
+/*
+ * 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.enumerable;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.avatica.Helper;
+import org.apache.calcite.interpreter.InterpretableConvention;
+import org.apache.calcite.interpreter.InterpretableRel;
+import org.apache.calcite.interpreter.Interpreter;
+import org.apache.calcite.interpreter.Node;
+import org.apache.calcite.interpreter.Row;
+import org.apache.calcite.interpreter.Sink;
+import org.apache.calcite.jdbc.CalcitePrepare;
+import org.apache.calcite.linq4j.AbstractEnumerable;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.linq4j.tree.ClassDeclaration;
+import org.apache.calcite.linq4j.tree.Expressions;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.prepare.CalcitePrepareImpl;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.ConverterImpl;
+import org.apache.calcite.runtime.ArrayBindable;
+import org.apache.calcite.runtime.Bindable;
+import org.apache.calcite.runtime.Hook;
+import org.apache.calcite.runtime.Typed;
+import org.apache.calcite.runtime.Utilities;
+import org.apache.calcite.util.Util;
+
+import org.codehaus.commons.compiler.CompileException;
+import org.codehaus.commons.compiler.CompilerFactoryFactory;
+import org.codehaus.commons.compiler.IClassBodyEvaluator;
+import org.codehaus.commons.compiler.ICompilerFactory;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Relational expression that converts an enumerable input to interpretable
+ * calling convention.
+ *
+ * @see EnumerableConvention
+ * @see org.apache.calcite.interpreter.BindableConvention
+ */
+public class EnumerableInterpretable extends ConverterImpl
+ implements InterpretableRel {
+ protected EnumerableInterpretable(RelOptCluster cluster, RelNode input) {
+ super(cluster, ConventionTraitDef.INSTANCE,
+ cluster.traitSetOf(InterpretableConvention.INSTANCE), input);
+ }
+
+ @Override public EnumerableInterpretable copy(RelTraitSet traitSet,
+ List<RelNode> inputs) {
+ return new EnumerableInterpretable(getCluster(), sole(inputs));
+ }
+
+ public Node implement(final InterpreterImplementor implementor) {
+ final Bindable bindable = toBindable(implementor.internalParameters,
+ implementor.spark, (EnumerableRel) getInput(),
+ EnumerableRel.Prefer.ARRAY);
+ final ArrayBindable arrayBindable = box(bindable);
+ final Enumerable<Object[]> enumerable =
+ arrayBindable.bind(implementor.dataContext);
+ return new EnumerableNode(enumerable, implementor.interpreter, this);
+ }
+
+ public static Bindable toBindable(Map<String, Object> parameters,
+ CalcitePrepare.SparkHandler spark, EnumerableRel rel,
+ EnumerableRel.Prefer prefer) {
+ EnumerableRelImplementor relImplementor =
+ new EnumerableRelImplementor(rel.getCluster().getRexBuilder(),
+ parameters);
+
+ final ClassDeclaration expr = relImplementor.implementRoot(rel, prefer);
+ String s = Expressions.toString(expr.memberDeclarations, "\n", false);
+
+ if (CalcitePrepareImpl.DEBUG) {
+ Util.debugCode(System.out, s);
+ }
+
+ Hook.JAVA_PLAN.run(s);
+
+ try {
+ if (spark != null && spark.enabled()) {
+ return spark.compile(expr, s);
+ } else {
+ return getBindable(expr, s, rel.getRowType().getFieldCount());
+ }
+ } catch (Exception e) {
+ throw Helper.INSTANCE.wrap("Error while compiling generated Java code:\n"
+ + s, e);
+ }
+ }
+
+ static ArrayBindable getArrayBindable(ClassDeclaration expr, String s,
+ int fieldCount) throws CompileException, IOException {
+ Bindable bindable = getBindable(expr, s, fieldCount);
+ return box(bindable);
+ }
+
+ static Bindable getBindable(ClassDeclaration expr, String s, int fieldCount)
+ throws CompileException, IOException {
+ ICompilerFactory compilerFactory;
+ try {
+ compilerFactory = CompilerFactoryFactory.getDefaultCompilerFactory();
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Unable to instantiate java compiler", e);
+ }
+ IClassBodyEvaluator cbe = compilerFactory.newClassBodyEvaluator();
+ cbe.setClassName(expr.name);
+ cbe.setExtendedClass(Utilities.class);
+ cbe.setImplementedInterfaces(
+ fieldCount == 1
+ ? new Class[] {Bindable.class, Typed.class}
+ : new Class[] {ArrayBindable.class});
+ cbe.setParentClassLoader(EnumerableInterpretable.class.getClassLoader());
+ if (CalcitePrepareImpl.DEBUG) {
+ // Add line numbers to the generated janino class
+ cbe.setDebuggingInformation(true, true, true);
+ }
+ return (Bindable) cbe.createInstance(new StringReader(s));
+ }
+
+ /** Converts a bindable over scalar values into an array bindable, with each
+ * row as an array of 1 element. */
+ static ArrayBindable box(final Bindable bindable) {
+ if (bindable instanceof ArrayBindable) {
+ return (ArrayBindable) bindable;
+ }
+ return new ArrayBindable() {
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ final Enumerable<?> enumerable = bindable.bind(dataContext);
+ return new AbstractEnumerable<Object[]>() {
+ public Enumerator<Object[]> enumerator() {
+ final Enumerator<?> enumerator = enumerable.enumerator();
+ return new Enumerator<Object[]>() {
+ public Object[] current() {
+ return new Object[] {enumerator.current()};
+ }
+
+ public boolean moveNext() {
+ return enumerator.moveNext();
+ }
+
+ public void reset() {
+ enumerator.reset();
+ }
+
+ public void close() {
+ enumerator.close();
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+
+ /** Interpreter node that reads from an {@link Enumerable}.
+ *
+ * <p>From the interpreter's perspective, it is a leaf node. */
+ private static class EnumerableNode implements Node {
+ private final Enumerable<Object[]> enumerable;
+ private final Sink sink;
+
+ public EnumerableNode(Enumerable<Object[]> enumerable,
+ Interpreter interpreter, EnumerableInterpretable rel) {
+ this.enumerable = enumerable;
+ this.sink = interpreter.sink(rel);
+ }
+
+ public void run() throws InterruptedException {
+ final Enumerator<Object[]> enumerator = enumerable.enumerator();
+ while (enumerator.moveNext()) {
+ Object[] values = enumerator.current();
+ sink.send(Row.of(values));
+ }
+ }
+ }
+}
+
+// End EnumerableInterpretable.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
index 919856c..158365c 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
@@ -17,12 +17,11 @@
package org.apache.calcite.adapter.enumerable;
import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.logical.LogicalProject;
-import org.apache.calcite.rex.RexMultisetUtil;
-import org.apache.calcite.rex.RexOver;
/**
* Rule to convert a {@link org.apache.calcite.rel.logical.LogicalProject} to an
@@ -30,24 +29,15 @@ import org.apache.calcite.rex.RexOver;
*/
class EnumerableProjectRule extends ConverterRule {
EnumerableProjectRule() {
- super(LogicalProject.class, Convention.NONE, EnumerableConvention.INSTANCE,
- "EnumerableProjectRule");
+ super(LogicalProject.class, RelOptUtil.PROJECT_PREDICATE, Convention.NONE,
+ EnumerableConvention.INSTANCE, "EnumerableProjectRule");
}
public RelNode convert(RelNode rel) {
final LogicalProject project = (LogicalProject) rel;
-
- if (EnumUtils.B
- && RexMultisetUtil.containsMultiset(project.getProjects(), true)
- || RexOver.containsOver(project.getProjects(), null)) {
- return null;
- }
-
- return new EnumerableProject(
- rel.getCluster(),
+ return new EnumerableProject(rel.getCluster(),
rel.getTraitSet().replace(EnumerableConvention.INSTANCE),
- convert(
- project.getInput(),
+ convert(project.getInput(),
project.getInput().getTraitSet()
.replace(EnumerableConvention.INSTANCE)),
project.getProjects(),
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
index d69fffd..4280a7e 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
@@ -142,7 +142,7 @@ public class EnumerableRelImplementor extends JavaRelImplementor {
Expressions.list(root0_),
block));
memberDeclarations.add(
- Expressions.methodDecl(Modifier.PUBLIC, Type.class,
+ Expressions.methodDecl(Modifier.PUBLIC, Class.class,
BuiltInMethod.TYPED_GET_ELEMENT_TYPE.method.getName(),
Collections.<ParameterExpression>emptyList(),
Blocks.toFunctionBlock(
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java
index 7c6bec5..a20279c 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSort.java
@@ -71,8 +71,8 @@ public class EnumerableSort extends Sort implements EnumerableRel {
BuiltInMethod.ORDER_BY.method,
Expressions.list(
builder.append("keySelector", pair.left))
- .appendIfNotNull(builder.appendIfNotNull("comparator",
- pair.right)))));
+ .appendIfNotNull(
+ builder.appendIfNotNull("comparator", pair.right)))));
return implementor.result(physType, builder.toBlock());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
index aa0ada7..7650c62 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
@@ -38,7 +38,6 @@ import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.AggregateCall;
import org.apache.calcite.rel.core.Window;
-import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rex.RexInputRef;
@@ -46,6 +45,7 @@ import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexWindowBound;
import org.apache.calcite.runtime.SortedMultiMap;
+import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.util.BuiltInMethod;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
@@ -75,18 +75,8 @@ public class EnumerableWindow extends Window implements EnumerableRel {
}
public RelOptCost computeSelfCost(RelOptPlanner planner) {
- // Cost is proportional to the number of rows and the number of
- // components (groups and aggregate functions). There is
- // no I/O cost.
- //
- // TODO #1. Add memory cost.
- // TODO #2. MIN and MAX have higher CPU cost than SUM and COUNT.
- final double rowsIn = RelMetadataQuery.getRowCount(getInput());
- int count = groups.size();
- for (Group group : groups) {
- count += group.aggCalls.size();
- }
- return planner.getCostFactory().makeCost(rowsIn, rowsIn * count, 0);
+ return super.computeSelfCost(planner)
+ .multiplyBy(EnumerableConvention.COST_MULTIPLIER);
}
/** Implementation of {@link RexToLixTranslator.InputGetter}
@@ -373,8 +363,9 @@ public class EnumerableWindow extends Window implements EnumerableRel {
builder4.append("totalRows", rowCountWhenNonEmpty);
} else {
frameRowCount =
- builder4.append("totalRows", Expressions.condition(hasRows,
- rowCountWhenNonEmpty, Expressions.constant(0)));
+ builder4.append("totalRows",
+ Expressions.condition(hasRows, rowCountWhenNonEmpty,
+ Expressions.constant(0)));
}
ParameterExpression actualStart = Expressions.parameter(
@@ -585,10 +576,11 @@ public class EnumerableWindow extends Window implements EnumerableRel {
}
//noinspection UnnecessaryLocalVariable
- Expression res = block.append("rowInFrame", Expressions.foldAnd(
- ImmutableList.of(hasRows,
- Expressions.greaterThanOrEqual(rowIndex, minIndex),
- Expressions.lessThanOrEqual(rowIndex, maxIndex))));
+ Expression res = block.append("rowInFrame",
+ Expressions.foldAnd(
+ ImmutableList.of(hasRows,
+ Expressions.greaterThanOrEqual(rowIndex, minIndex),
+ Expressions.lessThanOrEqual(rowIndex, maxIndex))));
return res;
}
@@ -757,7 +749,7 @@ public class EnumerableWindow extends Window implements EnumerableRel {
for (final AggImpState agg: aggs) {
agg.context =
new WinAggContext() {
- public org.apache.calcite.sql.SqlAggFunction aggregation() {
+ public SqlAggFunction aggregation() {
return agg.call.getAggregation();
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowRule.java
index 58e199f..a295470 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowRule.java
@@ -23,8 +23,8 @@ import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.logical.LogicalWindow;
/**
- * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalAggregate} to
- * an {@link org.apache.calcite.adapter.enumerable.EnumerableAggregate}.
+ * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalWindow} to
+ * an {@link org.apache.calcite.adapter.enumerable.EnumerableWindow}.
*/
class EnumerableWindowRule extends ConverterRule {
EnumerableWindowRule() {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java
index 146f420..ac87aad 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/JavaRowFormat.java
@@ -199,7 +199,6 @@ public enum JavaRowFormat {
Type javaRowClass(
JavaTypeFactory typeFactory,
RelDataType type) {
- assert type.getFieldCount() > 1;
return Object[].class;
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
index 54b6424..59ec646 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
@@ -77,10 +77,19 @@ public class PhysTypeImpl implements PhysType {
JavaTypeFactory typeFactory,
RelDataType rowType,
JavaRowFormat format) {
- final JavaRowFormat format2 = format.optimize(rowType);
- final Type javaRowClass = format2.javaRowClass(typeFactory, rowType);
- return new PhysTypeImpl(
- typeFactory, rowType, javaRowClass, format2);
+ return of(typeFactory, rowType, format, true);
+ }
+
+ public static PhysType of(
+ JavaTypeFactory typeFactory,
+ RelDataType rowType,
+ JavaRowFormat format,
+ boolean optimize) {
+ if (optimize) {
+ format = format.optimize(rowType);
+ }
+ final Type javaRowClass = format.javaRowClass(typeFactory, rowType);
+ return new PhysTypeImpl(typeFactory, rowType, javaRowClass, format);
}
static PhysType of(
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/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 1d721f8..e1fd9b0 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
@@ -70,7 +70,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import static org.apache.calcite.DataContext.ROOT;
import static org.apache.calcite.linq4j.tree.ExpressionType.Add;
import static org.apache.calcite.linq4j.tree.ExpressionType.AndAlso;
import static org.apache.calcite.linq4j.tree.ExpressionType.Divide;
@@ -1695,6 +1694,7 @@ public class RexImpTable {
return Expressions.constant(true);
}
final SqlOperator op = call.getOperator();
+ final Expression root = translator.getRoot();
if (op == CURRENT_USER
|| op == SESSION_USER
|| op == USER) {
@@ -1707,15 +1707,15 @@ public class RexImpTable {
// the empty string because a role has to be set explicitly.
return Expressions.constant("");
} else if (op == CURRENT_TIMESTAMP) {
- return Expressions.call(BuiltInMethod.CURRENT_TIMESTAMP.method, ROOT);
+ return Expressions.call(BuiltInMethod.CURRENT_TIMESTAMP.method, root);
} else if (op == CURRENT_TIME) {
- return Expressions.call(BuiltInMethod.CURRENT_TIME.method, ROOT);
+ return Expressions.call(BuiltInMethod.CURRENT_TIME.method, root);
} else if (op == CURRENT_DATE) {
- return Expressions.call(BuiltInMethod.CURRENT_DATE.method, ROOT);
+ return Expressions.call(BuiltInMethod.CURRENT_DATE.method, root);
} else if (op == LOCALTIMESTAMP) {
- return Expressions.call(BuiltInMethod.LOCAL_TIMESTAMP.method, ROOT);
+ return Expressions.call(BuiltInMethod.LOCAL_TIMESTAMP.method, root);
} else if (op == LOCALTIME) {
- return Expressions.call(BuiltInMethod.LOCAL_TIME.method, ROOT);
+ return Expressions.call(BuiltInMethod.LOCAL_TIME.method, root);
} else {
throw new AssertionError("unknown function " + op);
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index 92bd345..aceafa5 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -51,6 +51,8 @@ import org.apache.calcite.util.NlsString;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
+import com.google.common.collect.ImmutableMap;
+
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
@@ -86,6 +88,7 @@ public class RexToLixTranslator {
final JavaTypeFactory typeFactory;
final RexBuilder builder;
private final RexProgram program;
+ private final Expression root;
private final RexToLixTranslator.InputGetter inputGetter;
private final BlockBuilder list;
private final Map<? extends RexNode, Boolean> exprNullableMap;
@@ -101,13 +104,9 @@ public class RexToLixTranslator {
}
}
- private RexToLixTranslator(
- RexProgram program,
- JavaTypeFactory typeFactory,
- InputGetter inputGetter,
- BlockBuilder list) {
- this(
- program, typeFactory, inputGetter, list,
+ private RexToLixTranslator(RexProgram program, JavaTypeFactory typeFactory,
+ Expression root, InputGetter inputGetter, BlockBuilder list) {
+ this(program, typeFactory, root, inputGetter, list,
Collections.<RexNode, Boolean>emptyMap(),
new RexBuilder(typeFactory));
}
@@ -115,29 +114,32 @@ public class RexToLixTranslator {
private RexToLixTranslator(
RexProgram program,
JavaTypeFactory typeFactory,
+ Expression root,
InputGetter inputGetter,
BlockBuilder list,
Map<RexNode, Boolean> exprNullableMap,
RexBuilder builder) {
- this(program, typeFactory, inputGetter, list, exprNullableMap, builder,
- null);
+ this(program, typeFactory, root, inputGetter, list, exprNullableMap,
+ builder, null);
}
private RexToLixTranslator(
RexProgram program,
JavaTypeFactory typeFactory,
+ Expression root,
InputGetter inputGetter,
BlockBuilder list,
Map<? extends RexNode, Boolean> exprNullableMap,
RexBuilder builder,
RexToLixTranslator parent) {
- this(program, typeFactory, inputGetter, list, exprNullableMap, builder,
- parent, null);
+ this(program, typeFactory, root, inputGetter, list, exprNullableMap,
+ builder, parent, null);
}
private RexToLixTranslator(
RexProgram program,
JavaTypeFactory typeFactory,
+ Expression root,
InputGetter inputGetter,
BlockBuilder list,
Map<? extends RexNode, Boolean> exprNullableMap,
@@ -146,6 +148,7 @@ public class RexToLixTranslator {
Function1<String, InputGetter> correlates) {
this.program = program;
this.typeFactory = typeFactory;
+ this.root = root;
this.inputGetter = inputGetter;
this.list = list;
this.exprNullableMap = exprNullableMap;
@@ -162,16 +165,17 @@ public class RexToLixTranslator {
* @param typeFactory Type factory
* @param list List of statements, populated with declarations
* @param outputPhysType Output type, or null
+ * @param root Root expression
* @param inputGetter Generates expressions for inputs
* @param correlates Provider of references to the values of correlated
* variables
* @return Sequence of expressions, optional condition
*/
- public static List<Expression> translateProjects(
- RexProgram program,
+ public static List<Expression> translateProjects(RexProgram program,
JavaTypeFactory typeFactory,
BlockBuilder list,
PhysType outputPhysType,
+ Expression root,
InputGetter inputGetter,
Function1<String, InputGetter> correlates) {
List<Type> storageTypes = null;
@@ -182,7 +186,7 @@ public class RexToLixTranslator {
storageTypes.add(outputPhysType.getJavaFieldType(i));
}
}
- return new RexToLixTranslator(program, typeFactory, inputGetter, list)
+ return new RexToLixTranslator(program, typeFactory, root, inputGetter, list)
.setCorrelates(correlates)
.translateList(program.getProjectList(), storageTypes);
}
@@ -190,7 +194,8 @@ public class RexToLixTranslator {
/** Creates a translator for translating aggregate functions. */
public static RexToLixTranslator forAggregation(JavaTypeFactory typeFactory,
BlockBuilder list, InputGetter inputGetter) {
- return new RexToLixTranslator(null, typeFactory, inputGetter, list);
+ final ParameterExpression root = DataContext.ROOT;
+ return new RexToLixTranslator(null, typeFactory, root, inputGetter, list);
}
Expression translate(RexNode expr) {
@@ -509,9 +514,7 @@ public class RexToLixTranslator {
}
return nullAs.handle(
convert(
- Expressions.call(
- DataContext.ROOT,
- BuiltInMethod.DATA_CONTEXT_GET.method,
+ Expressions.call(root, BuiltInMethod.DATA_CONTEXT_GET.method,
Expressions.constant("?" + expr.getIndex())),
storageType));
}
@@ -677,8 +680,9 @@ public class RexToLixTranslator {
if (program.getCondition() == null) {
return RexImpTable.TRUE_EXPR;
}
+ final ParameterExpression root = DataContext.ROOT;
RexToLixTranslator translator =
- new RexToLixTranslator(program, typeFactory, inputGetter, list);
+ new RexToLixTranslator(program, typeFactory, root, inputGetter, list);
translator = translator.setCorrelates(correlates);
return translator.translate(
program.getCondition(),
@@ -844,14 +848,6 @@ public class RexToLixTranslator {
return Expressions.convert_(operand, toType);
}
- private static <T> T elvis(T t0, T t1) {
- return t0 != null ? t0 : t1;
- }
-
- private static <T> T elvis(T t0, T t1, T t2) {
- return t0 != null ? t0 : t1 != null ? t1 : t2;
- }
-
public Expression translateConstructor(
List<RexNode> operandList, SqlKind kind) {
switch (kind) {
@@ -936,23 +932,21 @@ public class RexToLixTranslator {
/** Creates a read-only copy of this translator that records that a given
* expression is nullable. */
- public RexToLixTranslator setNullable(Map<? extends RexNode,
- Boolean> nullable) {
+ public RexToLixTranslator setNullable(
+ Map<? extends RexNode, Boolean> nullable) {
if (nullable == null || nullable.isEmpty()) {
return this;
}
- return new RexToLixTranslator(
- program, typeFactory, inputGetter, list, nullable, builder, this,
- correlates);
+ return new RexToLixTranslator(program, typeFactory, root, inputGetter, list,
+ nullable, builder, this, correlates);
}
public RexToLixTranslator setBlock(BlockBuilder block) {
if (block == list) {
return this;
}
- return new RexToLixTranslator(
- program, typeFactory, inputGetter, block,
- Collections.<RexNode, Boolean>emptyMap(), builder, this, correlates);
+ return new RexToLixTranslator(program, typeFactory, root, inputGetter,
+ block, ImmutableMap.<RexNode, Boolean>of(), builder, this, correlates);
}
public RexToLixTranslator setCorrelates(
@@ -960,8 +954,7 @@ public class RexToLixTranslator {
if (this.correlates == correlates) {
return this;
}
- return new RexToLixTranslator(
- program, typeFactory, inputGetter, list,
+ return new RexToLixTranslator(program, typeFactory, root, inputGetter, list,
Collections.<RexNode, Boolean>emptyMap(), builder, this, correlates);
}
@@ -983,6 +976,10 @@ public class RexToLixTranslator {
return null;
}
+ public Expression getRoot() {
+ return root;
+ }
+
/** Translates a field of an input to an expression. */
public interface InputGetter {
Expression field(BlockBuilder list, int index, Type storageType);
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java b/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java
index 27b5151..a7155a1 100644
--- a/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java
+++ b/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java
@@ -16,11 +16,13 @@
*/
package org.apache.calcite.adapter.java;
+import org.apache.calcite.DataContext;
import org.apache.calcite.linq4j.Enumerable;
import org.apache.calcite.linq4j.Enumerator;
import org.apache.calcite.linq4j.Linq4j;
import org.apache.calcite.linq4j.QueryProvider;
import org.apache.calcite.linq4j.Queryable;
+import org.apache.calcite.linq4j.function.Function1;
import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.linq4j.tree.Primitive;
@@ -28,6 +30,7 @@ import org.apache.calcite.linq4j.tree.Types;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.schema.Function;
+import org.apache.calcite.schema.ScannableTable;
import org.apache.calcite.schema.Schema;
import org.apache.calcite.schema.SchemaFactory;
import org.apache.calcite.schema.SchemaPlus;
@@ -178,7 +181,7 @@ public class ReflectiveSchema
/** Table that is implemented by reading from a Java object. */
private static class ReflectiveTable
extends AbstractQueryableTable
- implements Table {
+ implements Table, ScannableTable {
private final Type elementType;
private final Enumerable enumerable;
@@ -196,6 +199,16 @@ public class ReflectiveSchema
return Statistics.UNKNOWN;
}
+ public Enumerable<Object[]> scan(DataContext root) {
+ if (elementType == Object[].class) {
+ //noinspection unchecked
+ return enumerable;
+ } else {
+ //noinspection unchecked
+ return enumerable.select(new FieldSelector((Class) elementType));
+ }
+ }
+
public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
SchemaPlus schema, String tableName) {
return new AbstractTableQueryable<T>(queryProvider, schema, this,
@@ -323,6 +336,27 @@ public class ReflectiveSchema
schema.getParentSchema(), schema.getName()), field);
}
}
+
+ /** Function that returns an array of a given object's field values. */
+ private static class FieldSelector implements Function1<Object, Object[]> {
+ private final Field[] fields;
+
+ public FieldSelector(Class elementType) {
+ this.fields = elementType.getFields();
+ }
+
+ public Object[] apply(Object o) {
+ try {
+ final Object[] objects = new Object[fields.length];
+ for (int i = 0; i < fields.length; i++) {
+ objects[i] = fields[i].get(o);
+ }
+ return objects;
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
}
// End ReflectiveSchema.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/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 135568b..7e68c52 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
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.adapter.jdbc;
+import org.apache.calcite.DataContext;
import org.apache.calcite.adapter.java.AbstractQueryableTable;
import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.jdbc.CalciteConnection;
@@ -33,6 +34,7 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rel.type.RelProtoDataType;
import org.apache.calcite.runtime.ResultSetEnumerable;
+import org.apache.calcite.schema.ScannableTable;
import org.apache.calcite.schema.Schema;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.TranslatableTable;
@@ -61,7 +63,8 @@ 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 implements TranslatableTable {
+class JdbcTable extends AbstractQueryableTable
+ implements TranslatableTable, ScannableTable {
private RelProtoDataType protoRowType;
private final JdbcSchema jdbcSchema;
private final String jdbcCatalogName;
@@ -156,6 +159,13 @@ class JdbcTable extends AbstractQueryableTable implements TranslatableTable {
return new JdbcTableQueryable<T>(queryProvider, schema, tableName);
}
+ public Enumerable<Object[]> scan(DataContext root) {
+ final JavaTypeFactory typeFactory = root.getTypeFactory();
+ final SqlString sql = generateSql();
+ return ResultSetEnumerable.of(jdbcSchema.getDataSource(), sql.getSql(),
+ JdbcUtils.ObjectArrayRowBuilder.factory(fieldClasses(typeFactory)));
+ }
+
/** Enumerable that returns the contents of a {@link JdbcTable} by connecting
* to the JDBC data source. */
private class JdbcTableQueryable<T> extends AbstractTableQueryable<T> {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java b/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java
index 145b44e..1dff33a 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java
@@ -16,15 +16,40 @@
*/
package org.apache.calcite.interpreter;
+import org.apache.calcite.DataContext;
+import org.apache.calcite.adapter.enumerable.AggAddContext;
+import org.apache.calcite.adapter.enumerable.AggImpState;
+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.enumerable.RexToLixTranslator;
+import org.apache.calcite.adapter.enumerable.impl.AggAddContextImpl;
+import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.interpreter.Row.RowBuilder;
+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.ParameterExpression;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.impl.AggregateFunctionImpl;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.Pair;
+import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -36,9 +61,12 @@ public class AggregateNode extends AbstractSingleNode<Aggregate> {
private final List<Grouping> groups = Lists.newArrayList();
private final ImmutableBitSet unionGroups;
private final int outputRowLength;
+ private final ImmutableList<AccumulatorFactory> accumulatorFactories;
+ private final DataContext dataContext;
public AggregateNode(Interpreter interpreter, Aggregate rel) {
super(interpreter, rel);
+ this.dataContext = interpreter.getDataContext();
ImmutableBitSet union = ImmutableBitSet.of();
@@ -53,10 +81,15 @@ public class AggregateNode extends AbstractSingleNode<Aggregate> {
this.outputRowLength = unionGroups.cardinality()
+ (rel.indicator ? unionGroups.cardinality() : 0)
+ rel.getAggCallList().size();
+
+ ImmutableList.Builder<AccumulatorFactory> builder = ImmutableList.builder();
+ for (AggregateCall aggregateCall : rel.getAggCallList()) {
+ builder.add(getAccumulator(aggregateCall));
+ }
+ accumulatorFactories = builder.build();
}
public void run() throws InterruptedException {
-
Row r;
while ((r = source.receive()) != null) {
for (Grouping group : groups) {
@@ -69,53 +102,173 @@ public class AggregateNode extends AbstractSingleNode<Aggregate> {
}
}
- private AccumulatorList getNewAccumList() {
- AccumulatorList list = new AccumulatorList();
- for (AggregateCall call : rel.getAggCallList()) {
- list.add(getAccumulator(call));
+ private AccumulatorFactory getAccumulator(final AggregateCall call) {
+ if (call.getAggregation() == SqlStdOperatorTable.COUNT) {
+ return new AccumulatorFactory() {
+ public Accumulator get() {
+ return new CountAccumulator(call);
+ }
+ };
+ } else if (call.getAggregation() == SqlStdOperatorTable.SUM) {
+ return new UdaAccumulatorFactory(
+ AggregateFunctionImpl.create(IntSum.class), call);
+ } else {
+ final JavaTypeFactory typeFactory =
+ (JavaTypeFactory) rel.getCluster().getTypeFactory();
+ int stateOffset = 0;
+ final AggImpState agg = new AggImpState(0, call, false);
+ int stateSize = agg.state.size();
+
+ final BlockBuilder builder2 = new BlockBuilder();
+ final PhysType inputPhysType =
+ PhysTypeImpl.of(typeFactory, rel.getInput().getRowType(),
+ JavaRowFormat.ARRAY);
+ final RelDataTypeFactory.FieldInfoBuilder builder = typeFactory.builder();
+ for (Expression expression : agg.state) {
+ builder.add("a",
+ typeFactory.createJavaType((Class) expression.getType()));
+ }
+ final PhysType accPhysType =
+ PhysTypeImpl.of(typeFactory, builder.build(), JavaRowFormat.ARRAY);
+ final ParameterExpression inParameter =
+ Expressions.parameter(inputPhysType.getJavaRowType(), "in");
+ final ParameterExpression acc_ =
+ Expressions.parameter(accPhysType.getJavaRowType(), "acc");
+
+ List<Expression> accumulator =
+ new ArrayList<Expression>(stateSize);
+ for (int j = 0; j < stateSize; j++) {
+ accumulator.add(accPhysType.fieldReference(acc_, j + stateOffset));
+ }
+ agg.state = accumulator;
+
+ AggAddContext addContext =
+ new AggAddContextImpl(builder2, accumulator) {
+ public List<RexNode> rexArguments() {
+ List<RelDataTypeField> inputTypes =
+ inputPhysType.getRowType().getFieldList();
+ List<RexNode> args = new ArrayList<RexNode>();
+ for (Integer index : agg.call.getArgList()) {
+ args.add(
+ new RexInputRef(index, inputTypes.get(index).getType()));
+ }
+ return args;
+ }
+
+ public RexToLixTranslator rowTranslator() {
+ return RexToLixTranslator.forAggregation(typeFactory,
+ currentBlock(),
+ new RexToLixTranslator.InputGetterImpl(
+ Collections.singletonList(
+ Pair.of((Expression) inParameter, inputPhysType))))
+ .setNullable(currentNullables());
+ }
+ };
+
+ agg.implementor.implementAdd(agg.context, addContext);
+
+ final ParameterExpression context_ =
+ Expressions.parameter(Context.class, "context");
+ final ParameterExpression outputValues_ =
+ Expressions.parameter(Object[].class, "outputValues");
+ Scalar addScalar =
+ JaninoRexCompiler.baz(context_, outputValues_, builder2.toBlock());
+ return new ScalarAccumulatorDef(null, addScalar, null,
+ rel.getInput().getRowType().getFieldCount(), stateSize, dataContext);
}
- return list;
}
- private static Accumulator getAccumulator(final AggregateCall call) {
- String agg = call.getAggregation().getName();
+ /** Accumulator for calls to the COUNT function. */
+ private static class CountAccumulator implements Accumulator {
+ private final AggregateCall call;
+ long cnt;
- if (agg.equals("COUNT")) {
- return new Accumulator() {
- long cnt = 0;
+ public CountAccumulator(AggregateCall call) {
+ this.call = call;
+ cnt = 0;
+ }
- public void send(Row row) {
- boolean notNull = true;
- for (Integer i : call.getArgList()) {
- if (row.getObject(i) == null) {
- notNull = false;
- break;
- }
- }
- if (notNull) {
- cnt++;
- }
+ public void send(Row row) {
+ boolean notNull = true;
+ for (Integer i : call.getArgList()) {
+ if (row.getObject(i) == null) {
+ notNull = false;
+ break;
}
+ }
+ if (notNull) {
+ cnt++;
+ }
+ }
- public Object end() {
- return cnt;
- }
+ public Object end() {
+ return cnt;
+ }
+ }
- };
- } else {
- throw new UnsupportedOperationException(
- String.format("Aggregate doesn't currently support "
- + "the %s aggregate function.", agg));
+ /** Creates an {@link Accumulator}. */
+ private interface AccumulatorFactory extends Supplier<Accumulator> {
+ }
+
+ /** Accumulator powered by {@link Scalar} code fragments. */
+ private static class ScalarAccumulatorDef implements AccumulatorFactory {
+ final Scalar initScalar;
+ final Scalar addScalar;
+ final Scalar endScalar;
+ final Context sendContext;
+ final Context endContext;
+ final int rowLength;
+ final int accumulatorLength;
+
+ private ScalarAccumulatorDef(Scalar initScalar, Scalar addScalar,
+ Scalar endScalar, int rowLength, int accumulatorLength,
+ DataContext root) {
+ this.initScalar = initScalar;
+ this.addScalar = addScalar;
+ this.endScalar = endScalar;
+ this.accumulatorLength = accumulatorLength;
+ this.rowLength = rowLength;
+ this.sendContext = new Context(root);
+ this.sendContext.values = new Object[rowLength + accumulatorLength];
+ this.endContext = new Context(root);
+ this.endContext.values = new Object[accumulatorLength];
+ }
+
+ public Accumulator get() {
+ return new ScalarAccumulator(this, new Object[accumulatorLength]);
+ }
+ }
+
+ /** Accumulator powered by {@link Scalar} code fragments. */
+ private static class ScalarAccumulator implements Accumulator {
+ final ScalarAccumulatorDef def;
+ final Object[] values;
+
+ private ScalarAccumulator(ScalarAccumulatorDef def, Object[] values) {
+ this.def = def;
+ this.values = values;
}
+ public void send(Row row) {
+ System.arraycopy(row.getValues(), 0, def.sendContext.values, 0,
+ def.rowLength);
+ System.arraycopy(values, 0, def.sendContext.values, def.rowLength,
+ values.length);
+ def.addScalar.execute(def.sendContext, values);
+ }
+
+ public Object end() {
+ System.arraycopy(values, 0, def.endContext.values, 0, values.length);
+ return def.endScalar.execute(def.endContext);
+ }
}
/**
- * Internal class to track groupings
+ * Internal class to track groupings.
*/
private class Grouping {
- private ImmutableBitSet grouping;
- private Map<Row, AccumulatorList> accum = Maps.newHashMap();
+ private final ImmutableBitSet grouping;
+ private final Map<Row, AccumulatorList> accumulators = Maps.newHashMap();
private Grouping(ImmutableBitSet grouping) {
this.grouping = grouping;
@@ -129,15 +282,19 @@ public class AggregateNode extends AbstractSingleNode<Aggregate> {
}
Row key = builder.build();
- if (!accum.containsKey(key)) {
- accum.put(key, getNewAccumList());
+ if (!accumulators.containsKey(key)) {
+ AccumulatorList list = new AccumulatorList();
+ for (AccumulatorFactory factory : accumulatorFactories) {
+ list.add(factory.get());
+ }
+ accumulators.put(key, list);
}
- accum.get(key).send(row);
+ accumulators.get(key).send(row);
}
public void end(Sink sink) throws InterruptedException {
- for (Map.Entry<Row, AccumulatorList> e : accum.entrySet()) {
+ for (Map.Entry<Row, AccumulatorList> e : accumulators.entrySet()) {
final Row key = e.getKey();
final AccumulatorList list = e.getValue();
@@ -188,6 +345,120 @@ public class AggregateNode extends AbstractSingleNode<Aggregate> {
void send(Row row);
Object end();
}
+
+ /** Implementation of {@code SUM} over INTEGER values as a user-defined
+ * aggregate. */
+ public static class IntSum {
+ public IntSum() {
+ }
+ public int init() {
+ return 0;
+ }
+ public int add(int accumulator, int v) {
+ return accumulator + v;
+ }
+ public int merge(int accumulator0, int accumulator1) {
+ return accumulator0 + accumulator1;
+ }
+ public int result(int accumulator) {
+ return accumulator;
+ }
+ }
+
+ /** Implementation of {@code SUM} over BIGINT values as a user-defined
+ * aggregate. */
+ public static class LongSum {
+ public LongSum() {
+ }
+ public long init() {
+ return 0L;
+ }
+ public long add(long accumulator, int v) {
+ return accumulator + v;
+ }
+ public long merge(long accumulator0, long accumulator1) {
+ return accumulator0 + accumulator1;
+ }
+ public long result(long accumulator) {
+ return accumulator;
+ }
+ }
+
+ /** Accumulator factory based on a user-defined aggregate function. */
+ private static class UdaAccumulatorFactory implements AccumulatorFactory {
+ public final AggregateFunctionImpl aggFunction;
+ public final int argOrdinal;
+ public final Object instance;
+
+ public UdaAccumulatorFactory(AggregateFunctionImpl aggFunction,
+ AggregateCall call) {
+ this.aggFunction = aggFunction;
+ if (call.getArgList().size() != 1) {
+ throw new UnsupportedOperationException("in current implementation, "
+ + "aggregate must have precisely one argument");
+ }
+ argOrdinal = call.getArgList().get(0);
+ if (aggFunction.isStatic) {
+ instance = null;
+ } else {
+ try {
+ instance = aggFunction.declaringClass.newInstance();
+ } catch (InstantiationException e) {
+ throw Throwables.propagate(e);
+ } catch (IllegalAccessException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+ }
+
+ public Accumulator get() {
+ return new UdaAccumulator(this);
+ }
+ }
+
+ /** Accumulator based upon a user-defined aggregate. */
+ private static class UdaAccumulator implements Accumulator {
+ private final UdaAccumulatorFactory factory;
+ private Object value;
+
+ public UdaAccumulator(UdaAccumulatorFactory factory) {
+ this.factory = factory;
+ try {
+ this.value = factory.aggFunction.initMethod.invoke(factory.instance);
+ } catch (IllegalAccessException e) {
+ throw Throwables.propagate(e);
+ } catch (InvocationTargetException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ public void send(Row row) {
+ final Object[] args = {value, row.getValues()[factory.argOrdinal]};
+ for (int i = 1; i < args.length; i++) {
+ if (args[i] == null) {
+ return; // one of the arguments is null; don't add to the total
+ }
+ }
+ try {
+ value = factory.aggFunction.addMethod.invoke(factory.instance, args);
+ } catch (IllegalAccessException e) {
+ throw Throwables.propagate(e);
+ } catch (InvocationTargetException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ public Object end() {
+ final Object[] args = {value};
+ try {
+ return factory.aggFunction.resultMethod.invoke(factory.instance, args);
+ } catch (IllegalAccessException e) {
+ throw Throwables.propagate(e);
+ } catch (InvocationTargetException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+ }
}
// End AggregateNode.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java b/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java
new file mode 100644
index 0000000..d74745c
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/BindableConvention.java
@@ -0,0 +1,64 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTrait;
+import org.apache.calcite.plan.RelTraitDef;
+
+/**
+ * Calling convention that returns results as an
+ * {@link org.apache.calcite.linq4j.Enumerable} of object arrays.
+ *
+ * <p>The relational expression needs to implement
+ * {@link org.apache.calcite.runtime.ArrayBindable}.
+ * Unlike {@link org.apache.calcite.adapter.enumerable.EnumerableConvention},
+ * no code generation is required.
+ */
+public enum BindableConvention implements Convention {
+ INSTANCE;
+
+ /** Cost of a bindable node versus implementing an equivalent node in a
+ * "typical" calling convention. */
+ public static final double COST_MULTIPLIER = 2.0d;
+
+ @Override public String toString() {
+ return getName();
+ }
+
+ public Class getInterface() {
+ return BindableRel.class;
+ }
+
+ public String getName() {
+ return "BINDABLE";
+ }
+
+ public RelTraitDef getTraitDef() {
+ return ConventionTraitDef.INSTANCE;
+ }
+
+ public boolean subsumes(RelTrait trait) {
+ return this == trait;
+ }
+
+ public void register(RelOptPlanner planner) {}
+}
+
+// End BindableConvention.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/BindableRel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/BindableRel.java b/core/src/main/java/org/apache/calcite/interpreter/BindableRel.java
new file mode 100644
index 0000000..7bde2e5
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/BindableRel.java
@@ -0,0 +1,31 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.runtime.ArrayBindable;
+
+/**
+ * Relational expression that can implement itself in Bindable
+ * convention.
+ *
+ * @see org.apache.calcite.interpreter.BindableConvention
+ */
+public interface BindableRel extends RelNode, ArrayBindable, InterpretableRel {
+}
+
+// End BindableRel.java
[2/3] incubator-calcite git commit: [CALCITE-544] Implement Union in
Interpreter;
[CALCITE-562] Implement inner JOIN in interpreter and improve handling of
scalar expressions
Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
new file mode 100644
index 0000000..cfe9b37
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
@@ -0,0 +1,583 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.adapter.enumerable.AggImplementor;
+import org.apache.calcite.adapter.enumerable.RexImpTable;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.InvalidRelException;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelNode;
+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.Filter;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.Sort;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rel.core.Union;
+import org.apache.calcite.rel.core.Values;
+import org.apache.calcite.rel.core.Window;
+import org.apache.calcite.rel.logical.LogicalAggregate;
+import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalUnion;
+import org.apache.calcite.rel.logical.LogicalValues;
+import org.apache.calcite.rel.logical.LogicalWindow;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.ScannableTable;
+import org.apache.calcite.util.ImmutableBitSet;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Utilities pertaining to {@link BindableRel} and {@link BindableConvention}.
+ */
+public class Bindables {
+ private Bindables() {}
+
+ public static final RelOptRule BINDABLE_TABLE_RULE =
+ new BindableTableScanRule();
+
+ public static final RelOptRule BINDABLE_FILTER_RULE =
+ new BindableFilterRule();
+
+ public static final RelOptRule BINDABLE_PROJECT_RULE =
+ new BindableProjectRule();
+
+ public static final RelOptRule BINDABLE_SORT_RULE =
+ new BindableSortRule();
+
+ public static final RelOptRule BINDABLE_JOIN_RULE =
+ new BindableJoinRule();
+
+ public static final RelOptRule BINDABLE_UNION_RULE =
+ new BindableUnionRule();
+
+ public static final RelOptRule BINDABLE_VALUES_RULE =
+ new BindableValuesRule();
+
+ public static final RelOptRule BINDABLE_AGGREGATE_RULE =
+ new BindableAggregateRule();
+
+ public static final RelOptRule BINDABLE_WINDOW_RULE =
+ new BindableWindowRule();
+
+ /** All rules that convert logical relational expression to bindable. */
+ public static final ImmutableList<RelOptRule> RULES =
+ ImmutableList.of(
+ NoneToBindableConverterRule.INSTANCE,
+ BINDABLE_TABLE_RULE,
+ BINDABLE_FILTER_RULE,
+ BINDABLE_PROJECT_RULE,
+ BINDABLE_SORT_RULE,
+ BINDABLE_JOIN_RULE,
+ BINDABLE_UNION_RULE,
+ BINDABLE_VALUES_RULE,
+ BINDABLE_AGGREGATE_RULE,
+ BINDABLE_WINDOW_RULE);
+
+ /** Helper method that converts a bindable relational expression into a
+ * record iterator.
+ *
+ * <p>Any bindable can be compiled; if its input is also bindable, it becomes
+ * part of the same compilation unit.
+ */
+ private static Enumerable<Object[]> help(DataContext dataContext,
+ BindableRel rel) {
+ return new Interpreter(dataContext, rel);
+ }
+
+ /** Rule that converts a {@link ScannableTable} to bindable convention. */
+ private static class BindableTableScanRule extends RelOptRule {
+ public BindableTableScanRule() {
+ super(operand(TableScan.class, none()));
+ }
+
+ @Override public void onMatch(RelOptRuleCall call) {
+ final TableScan scan = call.rel(0);
+ call.transformTo(
+ new BindableTableScan(scan.getCluster(),
+ scan.getTraitSet().replace(BindableConvention.INSTANCE),
+ scan.getTable()));
+ }
+ }
+
+ /** Scan of a table that implements {@link ScannableTable} and therefore can
+ * be converted into an {@link Enumerable}. */
+ private static class BindableTableScan
+ extends TableScan implements BindableRel {
+ BindableTableScan(RelOptCluster cluster, RelTraitSet traits,
+ RelOptTable table) {
+ super(cluster, traits, table);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return table.unwrap(ScannableTable.class).scan(dataContext);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ throw new UnsupportedOperationException(); // TODO:
+ }
+ }
+
+ /** Rule that converts a {@link Filter} to bindable convention. */
+ private static class BindableFilterRule extends ConverterRule {
+ private BindableFilterRule() {
+ super(LogicalFilter.class, RelOptUtil.FILTER_PREDICATE, Convention.NONE,
+ BindableConvention.INSTANCE, "BindableFilterRule");
+ }
+
+ public RelNode convert(RelNode rel) {
+ final LogicalFilter filter = (LogicalFilter) rel;
+ return new BindableFilter(rel.getCluster(),
+ rel.getTraitSet().replace(BindableConvention.INSTANCE),
+ convert(filter.getInput(),
+ filter.getInput().getTraitSet()
+ .replace(BindableConvention.INSTANCE)),
+ filter.getCondition());
+ }
+ }
+
+ /** Implementation of {@link org.apache.calcite.rel.core.Filter}
+ * in bindable convention. */
+ public static class BindableFilter extends Filter implements BindableRel {
+ public BindableFilter(RelOptCluster cluster, RelTraitSet traitSet,
+ RelNode child, RexNode condition) {
+ super(cluster, traitSet, child, condition);
+ assert getConvention() instanceof BindableConvention;
+ }
+
+ public BindableFilter copy(RelTraitSet traitSet, RelNode input,
+ RexNode condition) {
+ return new BindableFilter(getCluster(), traitSet, input, condition);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return help(dataContext, this);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ return new FilterNode(implementor.interpreter, this);
+ }
+ }
+
+ /**
+ * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalProject}
+ * to a {@link BindableProject}.
+ */
+ private static class BindableProjectRule extends ConverterRule {
+ BindableProjectRule() {
+ super(LogicalProject.class, RelOptUtil.PROJECT_PREDICATE, Convention.NONE,
+ BindableConvention.INSTANCE, "BindableProjectRule");
+ }
+
+ public RelNode convert(RelNode rel) {
+ final LogicalProject project = (LogicalProject) rel;
+ return new BindableProject(rel.getCluster(),
+ rel.getTraitSet().replace(BindableConvention.INSTANCE),
+ convert(project.getInput(),
+ project.getInput().getTraitSet()
+ .replace(BindableConvention.INSTANCE)),
+ project.getProjects(),
+ project.getRowType(),
+ Project.Flags.BOXED);
+ }
+ }
+
+ /** Implementation of {@link org.apache.calcite.rel.core.Project} in
+ * bindable calling convention. */
+ public static class BindableProject extends Project implements BindableRel {
+ public BindableProject(RelOptCluster cluster, RelTraitSet traitSet,
+ RelNode child, List<? extends RexNode> exps, RelDataType rowType,
+ int flags) {
+ super(cluster, traitSet, child, exps, rowType, flags);
+ assert getConvention() instanceof BindableConvention;
+ }
+
+ public BindableProject copy(RelTraitSet traitSet, RelNode input,
+ List<RexNode> exps, RelDataType rowType) {
+ return new BindableProject(getCluster(), traitSet, input, exps, rowType,
+ flags);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return help(dataContext, this);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ return new ProjectNode(implementor.interpreter, this);
+ }
+ }
+
+ /**
+ * Rule to convert an {@link org.apache.calcite.rel.core.Sort} to a
+ * {@link org.apache.calcite.interpreter.Bindables.BindableSort}.
+ */
+ private static class BindableSortRule extends ConverterRule {
+ BindableSortRule() {
+ super(Sort.class, Convention.NONE, BindableConvention.INSTANCE,
+ "BindableSortRule");
+ }
+
+ public RelNode convert(RelNode rel) {
+ final Sort sort = (Sort) rel;
+ final RelTraitSet traitSet =
+ sort.getTraitSet().replace(BindableConvention.INSTANCE);
+ final RelNode input = sort.getInput();
+ return new BindableSort(rel.getCluster(), traitSet,
+ convert(input,
+ input.getTraitSet().replace(BindableConvention.INSTANCE)),
+ sort.getCollation(), sort.offset, sort.fetch);
+ }
+ }
+
+ /** Implementation of {@link org.apache.calcite.rel.core.Sort}
+ * bindable calling convention. */
+ public static class BindableSort extends Sort implements BindableRel {
+ public BindableSort(RelOptCluster cluster, RelTraitSet traitSet,
+ RelNode child, RelCollation collation, RexNode offset, RexNode fetch) {
+ super(cluster, traitSet, child, collation, offset, fetch);
+ assert getConvention() instanceof BindableConvention;
+ assert getConvention() == child.getConvention();
+ }
+
+ @Override public BindableSort copy(RelTraitSet traitSet, RelNode newInput,
+ RelCollation newCollation, RexNode offset, RexNode fetch) {
+ return new BindableSort(getCluster(), traitSet, newInput, newCollation,
+ offset, fetch);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return help(dataContext, this);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ return new SortNode(implementor.interpreter, this);
+ }
+ }
+
+ /**
+ * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalJoin}
+ * to a {@link BindableJoin}.
+ */
+ private static class BindableJoinRule extends ConverterRule {
+ BindableJoinRule() {
+ super(LogicalJoin.class, Convention.NONE, BindableConvention.INSTANCE,
+ "BindableJoinRule");
+ }
+
+ public RelNode convert(RelNode rel) {
+ final LogicalJoin join = (LogicalJoin) rel;
+ final BindableConvention out = BindableConvention.INSTANCE;
+ final RelTraitSet traitSet = join.getTraitSet().replace(out);
+ return new BindableJoin(rel.getCluster(), traitSet,
+ convert(join.getLeft(),
+ join.getLeft().getTraitSet()
+ .replace(BindableConvention.INSTANCE)),
+ convert(join.getRight(),
+ join.getRight().getTraitSet()
+ .replace(BindableConvention.INSTANCE)),
+ join.getCondition(), join.getJoinType(), join.getVariablesStopped());
+ }
+ }
+
+ /** Implementation of {@link org.apache.calcite.rel.core.Join} in
+ * bindable calling convention. */
+ public static class BindableJoin extends Join implements BindableRel {
+ protected BindableJoin(RelOptCluster cluster, RelTraitSet traits,
+ RelNode left, RelNode right, RexNode condition, JoinRelType joinType,
+ Set<String> variablesStopped) {
+ super(cluster, traits, left, right, condition, joinType,
+ variablesStopped);
+ }
+
+ public BindableJoin copy(RelTraitSet traitSet, RexNode conditionExpr,
+ RelNode left, RelNode right, JoinRelType joinType,
+ boolean semiJoinDone) {
+ return new BindableJoin(getCluster(), traitSet, left, right,
+ conditionExpr, joinType, variablesStopped);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return help(dataContext, this);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ return new JoinNode(implementor.interpreter, this);
+ }
+ }
+
+ /**
+ * Rule to convert an {@link org.apache.calcite.rel.logical.LogicalUnion}
+ * to a {@link BindableUnion}.
+ */
+ private static class BindableUnionRule extends ConverterRule {
+ BindableUnionRule() {
+ super(LogicalUnion.class, Convention.NONE, BindableConvention.INSTANCE,
+ "BindableUnionRule");
+ }
+
+ public RelNode convert(RelNode rel) {
+ final LogicalUnion union = (LogicalUnion) rel;
+ final BindableConvention out = BindableConvention.INSTANCE;
+ final RelTraitSet traitSet = union.getTraitSet().replace(out);
+ return new BindableUnion(rel.getCluster(), traitSet,
+ convertList(union.getInputs(), out), union.all);
+ }
+ }
+
+ /** Implementation of {@link org.apache.calcite.rel.core.Union} in
+ * bindable calling convention. */
+ public static class BindableUnion extends Union implements BindableRel {
+ public BindableUnion(RelOptCluster cluster, RelTraitSet traitSet,
+ List<RelNode> inputs, boolean all) {
+ super(cluster, traitSet, inputs, all);
+ }
+
+ public BindableUnion copy(RelTraitSet traitSet, List<RelNode> inputs,
+ boolean all) {
+ return new BindableUnion(getCluster(), traitSet, inputs, all);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return help(dataContext, this);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ return new UnionNode(implementor.interpreter, this);
+ }
+ }
+
+ /** Implementation of {@link org.apache.calcite.rel.core.Values}
+ * in bindable calling convention. */
+ public static class BindableValues extends Values implements BindableRel {
+ BindableValues(RelOptCluster cluster, RelDataType rowType,
+ ImmutableList<ImmutableList<RexLiteral>> tuples, RelTraitSet traitSet) {
+ super(cluster, rowType, tuples, traitSet);
+ }
+
+ @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ assert inputs.isEmpty();
+ return new BindableValues(getCluster(), rowType, tuples, traitSet);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return help(dataContext, this);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ return new ValuesNode(implementor.interpreter, this);
+ }
+ }
+
+ /** Rule that converts a {@link Values} to bindable convention. */
+ private static class BindableValuesRule extends ConverterRule {
+ BindableValuesRule() {
+ super(LogicalValues.class, Convention.NONE, BindableConvention.INSTANCE,
+ "BindableValuesRule");
+ }
+
+ @Override public RelNode convert(RelNode rel) {
+ LogicalValues values = (LogicalValues) rel;
+ return new BindableValues(values.getCluster(), values.getRowType(),
+ values.getTuples(),
+ values.getTraitSet().replace(BindableConvention.INSTANCE));
+ }
+ }
+
+ /** Implementation of {@link org.apache.calcite.rel.core.Aggregate}
+ * in bindable calling convention. */
+ public static class BindableAggregate extends Aggregate
+ implements BindableRel {
+ public BindableAggregate(
+ RelOptCluster cluster,
+ RelTraitSet traitSet,
+ RelNode child,
+ boolean indicator,
+ ImmutableBitSet groupSet,
+ List<ImmutableBitSet> groupSets,
+ List<AggregateCall> aggCalls)
+ throws InvalidRelException {
+ super(cluster, traitSet, child, indicator, groupSet, groupSets, aggCalls);
+ assert getConvention() instanceof BindableConvention;
+
+ for (AggregateCall aggCall : aggCalls) {
+ if (aggCall.isDistinct()) {
+ throw new InvalidRelException(
+ "distinct aggregation not supported");
+ }
+ AggImplementor implementor2 =
+ RexImpTable.INSTANCE.get(aggCall.getAggregation(), false);
+ if (implementor2 == null) {
+ throw new InvalidRelException(
+ "aggregation " + aggCall.getAggregation() + " not supported");
+ }
+ }
+ }
+
+ @Override public BindableAggregate copy(RelTraitSet traitSet, RelNode input,
+ boolean indicator, ImmutableBitSet groupSet,
+ List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) {
+ try {
+ return new BindableAggregate(getCluster(), traitSet, input, indicator,
+ groupSet, groupSets, aggCalls);
+ } catch (InvalidRelException e) {
+ // Semantic error not possible. Must be a bug. Convert to
+ // internal error.
+ throw new AssertionError(e);
+ }
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return help(dataContext, this);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ return new AggregateNode(implementor.interpreter, this);
+ }
+ }
+
+ /** Rule that converts an {@link Aggregate} to bindable convention. */
+ private static class BindableAggregateRule extends ConverterRule {
+ BindableAggregateRule() {
+ super(LogicalAggregate.class, Convention.NONE,
+ BindableConvention.INSTANCE, "BindableAggregateRule");
+ }
+
+ public RelNode convert(RelNode rel) {
+ final LogicalAggregate agg = (LogicalAggregate) rel;
+ final RelTraitSet traitSet =
+ agg.getTraitSet().replace(BindableConvention.INSTANCE);
+ try {
+ return new BindableAggregate(rel.getCluster(), traitSet,
+ convert(agg.getInput(), traitSet), agg.indicator, agg.getGroupSet(),
+ agg.getGroupSets(), agg.getAggCallList());
+ } catch (InvalidRelException e) {
+ RelOptPlanner.LOGGER.fine(e.toString());
+ return null;
+ }
+ }
+ }
+
+ /** Implementation of {@link org.apache.calcite.rel.core.Window}
+ * in bindable convention. */
+ public static class BindableWindow extends Window implements BindableRel {
+ /** Creates an BindableWindowRel. */
+ BindableWindow(RelOptCluster cluster, RelTraitSet traits, RelNode child,
+ List<RexLiteral> constants, RelDataType rowType, List<Group> groups) {
+ super(cluster, traits, child, constants, rowType, groups);
+ }
+
+ @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ return new BindableWindow(getCluster(), traitSet, sole(inputs),
+ constants, rowType, groups);
+ }
+
+ @Override public RelOptCost computeSelfCost(RelOptPlanner planner) {
+ return super.computeSelfCost(planner)
+ .multiplyBy(BindableConvention.COST_MULTIPLIER);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return help(dataContext, this);
+ }
+
+ public Node implement(InterpreterImplementor implementor) {
+ return new WindowNode(implementor.interpreter, this);
+ }
+ }
+
+ /**
+ * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalWindow}
+ * to a {@link BindableWindow}.
+ */
+ private static class BindableWindowRule extends ConverterRule {
+ BindableWindowRule() {
+ super(LogicalWindow.class, Convention.NONE, BindableConvention.INSTANCE,
+ "BindableWindowRule");
+ }
+
+ public RelNode convert(RelNode rel) {
+ final LogicalWindow winAgg = (LogicalWindow) rel;
+ final RelTraitSet traitSet =
+ winAgg.getTraitSet().replace(BindableConvention.INSTANCE);
+ final RelNode child = winAgg.getInput();
+ final RelNode convertedChild =
+ convert(child,
+ child.getTraitSet().replace(BindableConvention.INSTANCE));
+ return new BindableWindow(rel.getCluster(), traitSet, convertedChild,
+ winAgg.getConstants(), winAgg.getRowType(), winAgg.groups);
+ }
+ }
+}
+
+// End Bindables.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/Context.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Context.java b/core/src/main/java/org/apache/calcite/interpreter/Context.java
index fc80319..f125454 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Context.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Context.java
@@ -16,12 +16,20 @@
*/
package org.apache.calcite.interpreter;
+import org.apache.calcite.DataContext;
+
/**
* Context for executing a scalar expression in an interpreter.
*/
public class Context {
+ public final DataContext root;
+
/** Values of incoming columns from all inputs. */
public Object[] values;
+
+ Context(DataContext root) {
+ this.root = root;
+ }
}
// End Context.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/FilterNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/FilterNode.java b/core/src/main/java/org/apache/calcite/interpreter/FilterNode.java
index d5461c4..e06e12d 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/FilterNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/FilterNode.java
@@ -18,20 +18,21 @@ package org.apache.calcite.interpreter;
import org.apache.calcite.rel.core.Filter;
+import com.google.common.collect.ImmutableList;
+
/**
* Interpreter node that implements a
* {@link org.apache.calcite.rel.core.Filter}.
*/
-public class FilterNode implements Node {
+public class FilterNode extends AbstractSingleNode<Filter> {
private final Scalar condition;
- private final Source source;
- private final Sink sink;
private final Context context;
public FilterNode(Interpreter interpreter, Filter rel) {
- this.condition = interpreter.compile(rel.getCondition());
- this.source = interpreter.source(rel, 0);
- this.sink = interpreter.sink(rel);
+ super(interpreter, rel);
+ this.condition =
+ interpreter.compile(ImmutableList.of(rel.getCondition()),
+ rel.getInputs());
this.context = interpreter.createContext();
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java b/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java
new file mode 100644
index 0000000..fb41d9d
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/InterpretableConvention.java
@@ -0,0 +1,58 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.adapter.enumerable.EnumerableRel;
+import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelTrait;
+import org.apache.calcite.plan.RelTraitDef;
+
+/**
+ * Calling convention that returns results as an
+ * {@link org.apache.calcite.linq4j.Enumerable} of object arrays.
+ *
+ * <p>Unlike enumerable convention, no code generation is required.
+ */
+public enum InterpretableConvention implements Convention {
+ INSTANCE;
+
+ @Override public String toString() {
+ return getName();
+ }
+
+ public Class getInterface() {
+ return EnumerableRel.class;
+ }
+
+ public String getName() {
+ return "INTERPRETABLE";
+ }
+
+ public RelTraitDef getTraitDef() {
+ return ConventionTraitDef.INSTANCE;
+ }
+
+ public boolean subsumes(RelTrait trait) {
+ return this == trait;
+ }
+
+ public void register(RelOptPlanner planner) {}
+}
+
+// End InterpretableConvention.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/InterpretableConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/InterpretableConverter.java b/core/src/main/java/org/apache/calcite/interpreter/InterpretableConverter.java
new file mode 100644
index 0000000..8b62174
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/InterpretableConverter.java
@@ -0,0 +1,55 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.ConverterImpl;
+import org.apache.calcite.runtime.ArrayBindable;
+
+import java.util.List;
+
+/**
+ * Relational expression that converts any relational expression input to
+ * {@link org.apache.calcite.interpreter.InterpretableConvention}, by wrapping
+ * it in an interpreter.
+ */
+public class InterpretableConverter extends ConverterImpl
+ implements ArrayBindable {
+ protected InterpretableConverter(RelOptCluster cluster, RelTraitSet traits,
+ RelNode input) {
+ super(cluster, ConventionTraitDef.INSTANCE, traits, input);
+ }
+
+ @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+ return new InterpretableConverter(getCluster(), traitSet, sole(inputs));
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return new Interpreter(dataContext, getInput());
+ }
+}
+
+// End InterpretableConverter.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/InterpretableRel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/InterpretableRel.java b/core/src/main/java/org/apache/calcite/interpreter/InterpretableRel.java
new file mode 100644
index 0000000..340299e
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/InterpretableRel.java
@@ -0,0 +1,55 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.jdbc.CalcitePrepare;
+import org.apache.calcite.rel.RelNode;
+
+import com.google.common.collect.Maps;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Relational expression that can implement itself using an interpreter.
+ */
+public interface InterpretableRel extends RelNode {
+ /** Creates an interpreter node to implement this relational expression. */
+ Node implement(InterpreterImplementor implementor);
+
+ /** Context when a {@link RelNode} is being converted to an interpreter
+ * {@link Node}. */
+ class InterpreterImplementor {
+ public final Interpreter interpreter;
+ public final Map<String, Object> internalParameters =
+ Maps.newLinkedHashMap();
+ public final CalcitePrepare.SparkHandler spark;
+ public final DataContext dataContext;
+ public final Map<RelNode, List<Sink>> relSinks = Maps.newHashMap();
+
+ public InterpreterImplementor(Interpreter interpreter,
+ CalcitePrepare.SparkHandler spark,
+ DataContext dataContext) {
+ this.interpreter = interpreter;
+ this.spark = spark;
+ this.dataContext = dataContext;
+ }
+ }
+}
+
+// End InterpretableRel.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
index cbcfa64..93f18ef 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
@@ -26,16 +26,15 @@ 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.fun.SqlStdOperatorTable;
import org.apache.calcite.util.ReflectUtil;
import org.apache.calcite.util.ReflectiveVisitDispatcher;
import org.apache.calcite.util.ReflectiveVisitor;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.math.BigDecimal;
-import java.util.AbstractList;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Map;
@@ -53,9 +52,12 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
private final DataContext dataContext;
private final RelNode rootRel;
private final Map<RelNode, List<RelNode>> relInputs = Maps.newHashMap();
+ protected final ScalarCompiler scalarCompiler;
public Interpreter(DataContext dataContext, RelNode rootRel) {
this.dataContext = dataContext;
+ this.scalarCompiler =
+ new JaninoRexCompiler(rootRel.getCluster().getRexBuilder());
Compiler compiler = new Nodes.CoreCompiler(this);
this.rootRel = compiler.visitRoot(rootRel);
}
@@ -106,96 +108,116 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
}
/** Compiles an expression to an executable form. */
- public Scalar compile(final RexNode node) {
- if (node instanceof RexCall) {
- final RexCall call = (RexCall) node;
- final ImmutableList.Builder<Scalar> list = ImmutableList.builder();
- for (RexNode operand : call.getOperands()) {
- list.add(compile(operand));
- }
- final ImmutableList<Scalar> scalars = list.build();
- return new Scalar() {
- public Object execute(final Context context) {
- final List<Object> args;
- Comparable o0;
- Comparable o1;
- switch (call.getKind()) {
- case LESS_THAN:
- case LESS_THAN_OR_EQUAL:
- case GREATER_THAN:
- case GREATER_THAN_OR_EQUAL:
- case EQUALS:
- case NOT_EQUALS:
- args = lazyArgs(context);
- o0 = (Comparable) args.get(0);
- if (o0 == null) {
- return null;
- }
- o1 = (Comparable) args.get(1);
- if (o1 == null) {
- return null;
- }
- if (o0 instanceof BigDecimal) {
- if (o1 instanceof Double || o1 instanceof Float) {
- o1 = new BigDecimal(((Number) o1).doubleValue());
- } else {
- o1 = new BigDecimal(((Number) o1).longValue());
- }
- }
- if (o1 instanceof BigDecimal) {
- if (o0 instanceof Double || o0 instanceof Float) {
- o0 = new BigDecimal(((Number) o0).doubleValue());
- } else {
- o0 = new BigDecimal(((Number) o0).longValue());
- }
- }
- final int c = o0.compareTo(o1);
+ public Scalar compile(List<RexNode> nodes, List<RelNode> inputs) {
+ return scalarCompiler.compile(inputs, nodes);
+ }
+
+ /** Not used. */
+ private class FooCompiler implements ScalarCompiler {
+ public Scalar compile(List<RelNode> inputs, List<RexNode> nodes) {
+ final RexNode node = nodes.get(0);
+ if (node instanceof RexCall) {
+ final RexCall call = (RexCall) node;
+ final Scalar argScalar = compile(inputs, call.getOperands());
+ return new Scalar() {
+ final Object[] args = new Object[call.getOperands().size()];
+
+ public void execute(final Context context, Object[] results) {
+ results[0] = execute(context);
+ }
+
+ public Object execute(Context context) {
+ Comparable o0;
+ Comparable o1;
switch (call.getKind()) {
case LESS_THAN:
- return c < 0;
case LESS_THAN_OR_EQUAL:
- return c <= 0;
case GREATER_THAN:
- return c > 0;
case GREATER_THAN_OR_EQUAL:
- return c >= 0;
case EQUALS:
- return c == 0;
case NOT_EQUALS:
- return c != 0;
+ argScalar.execute(context, args);
+ o0 = (Comparable) args[0];
+ if (o0 == null) {
+ return null;
+ }
+ o1 = (Comparable) args[1];
+ if (o1 == null) {
+ return null;
+ }
+ if (o0 instanceof BigDecimal) {
+ if (o1 instanceof Double || o1 instanceof Float) {
+ o1 = new BigDecimal(((Number) o1).doubleValue());
+ } else {
+ o1 = new BigDecimal(((Number) o1).longValue());
+ }
+ }
+ if (o1 instanceof BigDecimal) {
+ if (o0 instanceof Double || o0 instanceof Float) {
+ o0 = new BigDecimal(((Number) o0).doubleValue());
+ } else {
+ o0 = new BigDecimal(((Number) o0).longValue());
+ }
+ }
+ final int c = o0.compareTo(o1);
+ switch (call.getKind()) {
+ case LESS_THAN:
+ return c < 0;
+ case LESS_THAN_OR_EQUAL:
+ return c <= 0;
+ case GREATER_THAN:
+ return c > 0;
+ case GREATER_THAN_OR_EQUAL:
+ return c >= 0;
+ case EQUALS:
+ return c == 0;
+ case NOT_EQUALS:
+ return c != 0;
+ default:
+ throw new AssertionError("unknown expression " + call);
+ }
default:
+ if (call.getOperator() == SqlStdOperatorTable.UPPER) {
+ argScalar.execute(context, args);
+ String s0 = (String) args[0];
+ if (s0 == null) {
+ return null;
+ }
+ return s0.toUpperCase();
+ }
+ if (call.getOperator() == SqlStdOperatorTable.SUBSTRING) {
+ argScalar.execute(context, args);
+ String s0 = (String) args[0];
+ Number i1 = (Number) args[1];
+ Number i2 = (Number) args[2];
+ if (s0 == null || i1 == null || i2 == null) {
+ return null;
+ }
+ return s0.substring(i1.intValue() - 1,
+ i1.intValue() - 1 + i2.intValue());
+ }
throw new AssertionError("unknown expression " + call);
}
- default:
- throw new AssertionError("unknown expression " + call);
}
+ };
+ }
+ return new Scalar() {
+ public void execute(Context context, Object[] results) {
+ results[0] = execute(context);
}
- private List<Object> lazyArgs(final Context context) {
- return new AbstractList<Object>() {
- @Override public Object get(int index) {
- return scalars.get(index).execute(context);
- }
-
- @Override public int size() {
- return scalars.size();
- }
- };
+ public Object execute(Context context) {
+ switch (node.getKind()) {
+ case LITERAL:
+ return ((RexLiteral) node).getValue();
+ case INPUT_REF:
+ return context.values[((RexInputRef) node).getIndex()];
+ default:
+ throw new RuntimeException("unknown expression type " + node);
+ }
}
};
}
- return new Scalar() {
- public Object execute(Context context) {
- switch (node.getKind()) {
- case LITERAL:
- return ((RexLiteral) node).getValue();
- case INPUT_REF:
- return context.values[((RexInputRef) node).getIndex()];
- default:
- throw new RuntimeException("unknown expression type " + node);
- }
- }
- };
}
public Source source(RelNode rel, int ordinal) {
@@ -224,7 +246,7 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
}
public Context createContext() {
- return new Context();
+ return new Context(dataContext);
}
public DataContext getDataContext() {
@@ -368,6 +390,12 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
public void rewrite(RelNode r) {
}
}
+
+ /** Converts a list of expressions to a scalar that can compute their
+ * values. */
+ interface ScalarCompiler {
+ Scalar compile(List<RelNode> inputs, List<RexNode> nodes);
+ }
}
// End Interpreter.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/Interpreters.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreters.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreters.java
new file mode 100644
index 0000000..a4b6eb0
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreters.java
@@ -0,0 +1,50 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.runtime.ArrayBindable;
+
+/**
+ * Utilities relating to {@link org.apache.calcite.interpreter.Interpreter}
+ * and {@link org.apache.calcite.interpreter.InterpretableConvention}.
+ */
+public class Interpreters {
+ private Interpreters() {}
+
+ /** Creates a {@link org.apache.calcite.runtime.Bindable} that interprets a
+ * given relational expression. */
+ public static ArrayBindable bindable(final RelNode rel) {
+ if (rel instanceof ArrayBindable) {
+ // E.g. if rel instanceof BindableRel
+ return (ArrayBindable) rel;
+ }
+ return new ArrayBindable() {
+ public Enumerable<Object[]> bind(DataContext dataContext) {
+ return new Interpreter(dataContext, rel);
+ }
+
+ public Class<Object[]> getElementType() {
+ return Object[].class;
+ }
+ };
+ }
+}
+
+// End Interpreters.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/JaninoRexCompiler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/JaninoRexCompiler.java b/core/src/main/java/org/apache/calcite/interpreter/JaninoRexCompiler.java
new file mode 100644
index 0000000..491efa9
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/JaninoRexCompiler.java
@@ -0,0 +1,191 @@
+/*
+ * 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.interpreter;
+
+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.enumerable.RexToLixTranslator;
+import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.linq4j.function.Function1;
+import org.apache.calcite.linq4j.tree.BlockBuilder;
+import org.apache.calcite.linq4j.tree.BlockStatement;
+import org.apache.calcite.linq4j.tree.ClassDeclaration;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.linq4j.tree.Expressions;
+import org.apache.calcite.linq4j.tree.MemberDeclaration;
+import org.apache.calcite.linq4j.tree.ParameterExpression;
+import org.apache.calcite.prepare.CalcitePrepareImpl;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexProgram;
+import org.apache.calcite.rex.RexProgramBuilder;
+import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.Util;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import org.codehaus.commons.compiler.CompileException;
+import org.codehaus.commons.compiler.CompilerFactoryFactory;
+import org.codehaus.commons.compiler.IClassBodyEvaluator;
+import org.codehaus.commons.compiler.ICompilerFactory;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * Compiles a scalar expression ({@link RexNode}) to an expression that
+ * can be evaluated ({@link Scalar}) by generating a Java AST and compiling it
+ * to a class using Janino.
+ */
+public class JaninoRexCompiler implements Interpreter.ScalarCompiler {
+ private final RexBuilder rexBuilder;
+
+ public JaninoRexCompiler(RexBuilder rexBuilder) {
+ this.rexBuilder = rexBuilder;
+ }
+
+ public Scalar compile(List<RelNode> inputs, List<RexNode> nodes) {
+ final RelDataTypeFactory.FieldInfoBuilder fieldBuilder =
+ rexBuilder.getTypeFactory().builder();
+ for (RelNode input : inputs) {
+ fieldBuilder.addAll(input.getRowType().getFieldList());
+ }
+ final RelDataType inputRowType = fieldBuilder.build();
+ final RexProgramBuilder programBuilder =
+ new RexProgramBuilder(inputRowType, rexBuilder);
+ for (RexNode node : nodes) {
+ programBuilder.addProject(node, null);
+ }
+ final RexProgram program = programBuilder.getProgram();
+
+ final BlockBuilder builder = new BlockBuilder();
+ final ParameterExpression context_ =
+ Expressions.parameter(Context.class, "context");
+ final ParameterExpression outputValues_ =
+ Expressions.parameter(Object[].class, "outputValues");
+ final JavaTypeFactoryImpl javaTypeFactory =
+ new JavaTypeFactoryImpl(rexBuilder.getTypeFactory().getTypeSystem());
+
+ // public void execute(Context, Object[] outputValues)
+ final RexToLixTranslator.InputGetter inputGetter =
+ new RexToLixTranslator.InputGetterImpl(
+ ImmutableList.of(
+ Pair.<Expression, PhysType>of(
+ Expressions.field(context_,
+ BuiltInMethod.CONTEXT_VALUES.field),
+ PhysTypeImpl.of(javaTypeFactory, inputRowType,
+ JavaRowFormat.ARRAY, false))));
+ final Function1<String, RexToLixTranslator.InputGetter> correlates =
+ new Function1<String, RexToLixTranslator.InputGetter>() {
+ public RexToLixTranslator.InputGetter apply(String a0) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ final Expression root =
+ Expressions.field(context_, BuiltInMethod.CONTEXT_ROOT.field);
+ final List<Expression> list =
+ RexToLixTranslator.translateProjects(program, javaTypeFactory, builder,
+ null, root, inputGetter, correlates);
+ for (int i = 0; i < list.size(); i++) {
+ builder.add(
+ Expressions.statement(
+ Expressions.assign(
+ Expressions.arrayIndex(outputValues_,
+ Expressions.constant(i)),
+ list.get(i))));
+ }
+ return baz(context_, outputValues_, builder.toBlock());
+ }
+
+ /** Given a method that implements {@link Scalar#execute(Context, Object[])},
+ * adds a bridge method that implements {@link Scalar#execute(Context)}, and
+ * compiles. */
+ static Scalar baz(ParameterExpression context_,
+ ParameterExpression outputValues_, BlockStatement block) {
+ final List<MemberDeclaration> declarations = Lists.newArrayList();
+
+ // public void execute(Context, Object[] outputValues)
+ declarations.add(
+ Expressions.methodDecl(Modifier.PUBLIC, void.class,
+ BuiltInMethod.SCALAR_EXECUTE2.method.getName(),
+ ImmutableList.of(context_, outputValues_), block));
+
+ // public Object execute(Context)
+ final BlockBuilder builder = new BlockBuilder();
+ final Expression values_ = builder.append("values",
+ Expressions.newArrayBounds(Object.class, 1,
+ Expressions.constant(1)));
+ builder.add(
+ Expressions.statement(
+ Expressions.call(
+ Expressions.parameter(Scalar.class, "this"),
+ BuiltInMethod.SCALAR_EXECUTE2.method, context_, values_)));
+ builder.add(
+ Expressions.return_(null,
+ Expressions.arrayIndex(values_, Expressions.constant(0))));
+ declarations.add(
+ Expressions.methodDecl(Modifier.PUBLIC, Object.class,
+ BuiltInMethod.SCALAR_EXECUTE1.method.getName(),
+ ImmutableList.of(context_), builder.toBlock()));
+
+ final ClassDeclaration classDeclaration =
+ Expressions.classDecl(Modifier.PUBLIC, "Buzz", null,
+ ImmutableList.<Type>of(Scalar.class), declarations);
+ String s = Expressions.toString(declarations, "\n", false);
+ if (CalcitePrepareImpl.DEBUG) {
+ Util.debugCode(System.out, s);
+ }
+ try {
+ return getScalar(classDeclaration, s);
+ } catch (CompileException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static Scalar getScalar(ClassDeclaration expr, String s)
+ throws CompileException, IOException {
+ ICompilerFactory compilerFactory;
+ try {
+ compilerFactory = CompilerFactoryFactory.getDefaultCompilerFactory();
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Unable to instantiate java compiler", e);
+ }
+ IClassBodyEvaluator cbe = compilerFactory.newClassBodyEvaluator();
+ cbe.setClassName(expr.name);
+ cbe.setImplementedInterfaces(new Class[]{Scalar.class});
+ cbe.setParentClassLoader(JaninoRexCompiler.class.getClassLoader());
+ if (CalcitePrepareImpl.DEBUG) {
+ // Add line numbers to the generated janino class
+ cbe.setDebuggingInformation(true, true, true);
+ }
+ return (Scalar) cbe.createInstance(new StringReader(s));
+ }
+}
+
+// End JaninoRexCompiler.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/JoinNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/JoinNode.java b/core/src/main/java/org/apache/calcite/interpreter/JoinNode.java
new file mode 100644
index 0000000..498c8a3
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/JoinNode.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.interpreter;
+
+import org.apache.calcite.rel.core.Join;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Interpreter node that implements a
+ * {@link org.apache.calcite.rel.core.Join}.
+ */
+public class JoinNode implements Node {
+ private final Source leftSource;
+ private final Source rightSource;
+ private final Sink sink;
+ private final Join rel;
+ private final Scalar condition;
+ private final Context context;
+
+ public JoinNode(Interpreter interpreter, Join rel) {
+ this.leftSource = interpreter.source(rel, 0);
+ this.rightSource = interpreter.source(rel, 1);
+ this.sink = interpreter.sink(rel);
+ this.condition = interpreter.compile(ImmutableList.of(rel.getCondition()),
+ rel.getInputs());
+ this.rel = rel;
+ this.context = interpreter.createContext();
+
+ }
+
+ public void run() throws InterruptedException {
+ List<Row> rightList = null;
+ final int leftCount = rel.getLeft().getRowType().getFieldCount();
+ final int rightCount = rel.getRight().getRowType().getFieldCount();
+ context.values = new Object[rel.getRowType().getFieldCount()];
+ Row left;
+ Row right;
+ while ((left = leftSource.receive()) != null) {
+ System.arraycopy(left.getValues(), 0, context.values, 0, leftCount);
+ if (rightList == null) {
+ rightList = Lists.newArrayList();
+ while ((right = rightSource.receive()) != null) {
+ rightList.add(right);
+ }
+ }
+ for (Row right2 : rightList) {
+ System.arraycopy(right2.getValues(), 0, context.values, leftCount,
+ rightCount);
+ final Boolean execute = (Boolean) condition.execute(context);
+ if (execute != null && execute) {
+ sink.send(Row.asCopy(context.values));
+ }
+ }
+ }
+ }
+}
+
+// End JoinNode.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/Nodes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Nodes.java b/core/src/main/java/org/apache/calcite/interpreter/Nodes.java
index b09e7c3..1e067bb 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Nodes.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Nodes.java
@@ -24,10 +24,13 @@ import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.Calc;
import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.Sort;
import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rel.core.Union;
import org.apache.calcite.rel.core.Values;
+import org.apache.calcite.rel.core.Window;
import org.apache.calcite.rel.rules.FilterTableRule;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.schema.FilterableTable;
@@ -149,16 +152,29 @@ public class Nodes {
}
public void visit(TableScan scan) {
- node = new ScanNode(interpreter, scan, ImmutableList.<RexNode>of(), null);
+ node = new TableScanNode(interpreter, scan, ImmutableList.<RexNode>of(),
+ null);
}
public void visit(FilterScan scan) {
- node = new ScanNode(interpreter, scan, scan.filters, scan.projects);
+ node = new TableScanNode(interpreter, scan, scan.filters, scan.projects);
}
public void visit(Sort sort) {
node = new SortNode(interpreter, sort);
}
+
+ public void visit(Union union) {
+ node = new UnionNode(interpreter, union);
+ }
+
+ public void visit(Join join) {
+ node = new JoinNode(interpreter, join);
+ }
+
+ public void visit(Window window) {
+ node = new WindowNode(interpreter, window);
+ }
}
/** Table scan that applies filters and optionally projects. Only used in an
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/NoneToBindableConverterRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/NoneToBindableConverterRule.java b/core/src/main/java/org/apache/calcite/interpreter/NoneToBindableConverterRule.java
new file mode 100644
index 0000000..ab41cac
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/NoneToBindableConverterRule.java
@@ -0,0 +1,44 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.plan.Convention;
+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 org.apache.calcite.plan.Convention#NONE}
+ * to {@link org.apache.calcite.interpreter.BindableConvention}.
+ */
+public class NoneToBindableConverterRule extends ConverterRule {
+ public static final ConverterRule INSTANCE =
+ new NoneToBindableConverterRule();
+
+ private NoneToBindableConverterRule() {
+ super(RelNode.class, Convention.NONE, BindableConvention.INSTANCE,
+ "NoneToBindableConverterRule");
+ }
+
+ @Override public RelNode convert(RelNode rel) {
+ RelTraitSet newTraitSet = rel.getTraitSet().replace(getOutConvention());
+ return new InterpretableConverter(rel.getCluster(), newTraitSet, rel);
+ }
+}
+
+// End NoneToBindableConverterRule.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java b/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java
index bca464b..1737b8b 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/ProjectNode.java
@@ -17,28 +17,20 @@
package org.apache.calcite.interpreter;
import org.apache.calcite.rel.core.Project;
-import org.apache.calcite.rex.RexNode;
-
-import com.google.common.collect.ImmutableList;
/**
* Interpreter node that implements a
* {@link org.apache.calcite.rel.logical.LogicalFilter}.
*/
-public class ProjectNode implements Node {
- private final ImmutableList<Scalar> projects;
- private final Source source;
- private final Sink sink;
+public class ProjectNode extends AbstractSingleNode<Project> {
+ private final Scalar scalar;
private final Context context;
+ private final int projectCount;
public ProjectNode(Interpreter interpreter, Project rel) {
- ImmutableList.Builder<Scalar> builder = ImmutableList.builder();
- for (RexNode node : rel.getProjects()) {
- builder.add(interpreter.compile(node));
- }
- this.projects = builder.build();
- this.source = interpreter.source(rel, 0);
- this.sink = interpreter.sink(rel);
+ super(interpreter, rel);
+ this.projectCount = rel.getProjects().size();
+ this.scalar = interpreter.compile(rel.getProjects(), rel.getInputs());
this.context = interpreter.createContext();
}
@@ -46,11 +38,8 @@ public class ProjectNode implements Node {
Row row;
while ((row = source.receive()) != null) {
context.values = row.getValues();
- Object[] values = new Object[projects.size()];
- for (int i = 0; i < projects.size(); i++) {
- Scalar scalar = projects.get(i);
- values[i] = scalar.execute(context);
- }
+ Object[] values = new Object[projectCount];
+ scalar.execute(context, values);
sink.send(new Row(values));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/Scalar.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Scalar.java b/core/src/main/java/org/apache/calcite/interpreter/Scalar.java
index 2f7e923..795e9d4 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Scalar.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Scalar.java
@@ -21,6 +21,7 @@ package org.apache.calcite.interpreter;
*/
public interface Scalar {
Object execute(Context context);
+ void execute(Context context, Object[] results);
}
// End Scalar.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/ScanNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/ScanNode.java b/core/src/main/java/org/apache/calcite/interpreter/ScanNode.java
deleted file mode 100644
index 2688353..0000000
--- a/core/src/main/java/org/apache/calcite/interpreter/ScanNode.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.interpreter;
-
-import org.apache.calcite.DataContext;
-import org.apache.calcite.linq4j.Enumerable;
-import org.apache.calcite.linq4j.Enumerator;
-import org.apache.calcite.linq4j.Queryable;
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.rel.core.TableScan;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.runtime.Enumerables;
-import org.apache.calcite.schema.FilterableTable;
-import org.apache.calcite.schema.ProjectableFilterableTable;
-import org.apache.calcite.schema.QueryableTable;
-import org.apache.calcite.schema.ScannableTable;
-import org.apache.calcite.schema.SchemaPlus;
-import org.apache.calcite.schema.Schemas;
-import org.apache.calcite.util.ImmutableIntList;
-import org.apache.calcite.util.Util;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
-import java.util.List;
-
-/**
- * Interpreter node that implements a
- * {@link org.apache.calcite.rel.core.TableScan}.
- */
-public class ScanNode implements Node {
- private final Sink sink;
- private final TableScan rel;
- private final ImmutableList<RexNode> filters;
- private final DataContext root;
- private final int[] projects;
-
- public ScanNode(Interpreter interpreter, TableScan rel,
- ImmutableList<RexNode> filters, ImmutableIntList projects) {
- this.rel = rel;
- this.filters = Preconditions.checkNotNull(filters);
- this.projects = projects == null ? null : projects.toIntArray();
- this.sink = interpreter.sink(rel);
- this.root = interpreter.getDataContext();
- }
-
- public void run() throws InterruptedException {
- final Enumerable<Row> iterable = iterable();
- final Enumerator<Row> enumerator = iterable.enumerator();
- while (enumerator.moveNext()) {
- sink.send(enumerator.current());
- }
- enumerator.close();
- sink.end();
- }
-
- private Enumerable<Row> iterable() {
- final RelOptTable table = rel.getTable();
- final ProjectableFilterableTable pfTable =
- table.unwrap(ProjectableFilterableTable.class);
- if (pfTable != null) {
- final List<RexNode> filters1 = Lists.newArrayList(filters);
- final int[] projects1 =
- isIdentity(projects, rel.getRowType().getFieldCount())
- ? null : projects;
- final Enumerable<Object[]> enumerator =
- pfTable.scan(root, filters1, projects1);
- assert filters1.isEmpty()
- : "table could not handle a filter it earlier said it could";
- return Enumerables.toRow(enumerator);
- }
- if (projects != null) {
- throw new AssertionError("have projects, but table cannot handle them");
- }
- final FilterableTable filterableTable =
- table.unwrap(FilterableTable.class);
- if (filterableTable != null) {
- final List<RexNode> filters1 = Lists.newArrayList(filters);
- final Enumerable<Object[]> enumerator =
- filterableTable.scan(root, filters1);
- assert filters1.isEmpty()
- : "table could not handle a filter it earlier said it could";
- return Enumerables.toRow(enumerator);
- }
- if (!filters.isEmpty()) {
- throw new AssertionError("have filters, but table cannot handle them");
- }
- //noinspection unchecked
- Enumerable<Row> iterable = table.unwrap(Enumerable.class);
- if (iterable != null) {
- return iterable;
- }
- final QueryableTable queryableTable = table.unwrap(QueryableTable.class);
- if (queryableTable != null) {
- final Type elementType = queryableTable.getElementType();
- SchemaPlus schema = root.getRootSchema();
- for (String name : Util.skipLast(table.getQualifiedName())) {
- schema = schema.getSubSchema(name);
- }
- if (elementType instanceof Class) {
- //noinspection unchecked
- final Queryable<Object> queryable = Schemas.queryable(root,
- (Class) elementType, table.getQualifiedName());
- ImmutableList.Builder<Field> fieldBuilder = ImmutableList.builder();
- Class type = (Class) elementType;
- for (Field field : type.getFields()) {
- if (Modifier.isPublic(field.getModifiers())
- && !Modifier.isStatic(field.getModifiers())) {
- fieldBuilder.add(field);
- }
- }
- final List<Field> fields = fieldBuilder.build();
- return queryable.select(
- new Function1<Object, Row>() {
- public Row apply(Object o) {
- final Object[] values = new Object[fields.size()];
- for (int i = 0; i < fields.size(); i++) {
- Field field = fields.get(i);
- try {
- values[i] = field.get(o);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- }
- }
- return new Row(values);
- }
- });
- } else {
- return Schemas.queryable(root, Row.class,
- table.getQualifiedName());
- }
- }
- final ScannableTable scannableTable =
- table.unwrap(ScannableTable.class);
- if (scannableTable != null) {
- return Enumerables.toRow(scannableTable.scan(root));
- }
- throw new AssertionError("cannot convert table " + table + " to iterable");
- }
-
- private static boolean isIdentity(int[] is, int count) {
- if (is.length != count) {
- return false;
- }
- for (int i = 0; i < is.length; i++) {
- if (is[i] != i) {
- return false;
- }
- }
- return true;
- }
-}
-
-// End ScanNode.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/SortNode.java b/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
index e5fb91d..1e5f07b 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
@@ -34,15 +34,9 @@ import java.util.List;
* Interpreter node that implements a
* {@link org.apache.calcite.rel.core.Sort}.
*/
-public class SortNode implements Node {
- private final Source source;
- private final Sink sink;
- private final Sort rel;
-
+public class SortNode extends AbstractSingleNode<Sort> {
public SortNode(Interpreter interpreter, Sort rel) {
- this.rel = rel;
- this.source = interpreter.source(rel, 0);
- this.sink = interpreter.sink(rel);
+ super(interpreter, rel);
}
public void run() throws InterruptedException {
@@ -103,30 +97,55 @@ public class SortNode implements Node {
}));
}
+ private static int compare(Comparable c1, Comparable c2,
+ int nullComparison) {
+ if (c1 == c2) {
+ return 0;
+ } else if (c1 == null) {
+ return nullComparison;
+ } else if (c2 == null) {
+ return -nullComparison;
+ } else {
+ //noinspection unchecked
+ return c1.compareTo(c2);
+ }
+ }
+
private Comparator<Row> comparator(final RelFieldCollation fieldCollation) {
+ final int nullComparison = getNullComparison(fieldCollation.nullDirection);
switch (fieldCollation.direction) {
case ASCENDING:
return new Comparator<Row>() {
- final int x = fieldCollation.getFieldIndex();
public int compare(Row o1, Row o2) {
+ final int x = fieldCollation.getFieldIndex();
final Comparable c1 = (Comparable) o1.getValues()[x];
final Comparable c2 = (Comparable) o2.getValues()[x];
- //noinspection unchecked
- return c1.compareTo(c2);
+ return SortNode.compare(c1, c2, nullComparison);
}
};
default:
return new Comparator<Row>() {
- final int x = fieldCollation.getFieldIndex();
public int compare(Row o1, Row o2) {
+ final int x = fieldCollation.getFieldIndex();
final Comparable c1 = (Comparable) o1.getValues()[x];
final Comparable c2 = (Comparable) o2.getValues()[x];
- //noinspection unchecked
- return c2.compareTo(c1);
+ return SortNode.compare(c2, c1, -nullComparison);
}
};
}
}
+
+ private int getNullComparison(RelFieldCollation.NullDirection nullDirection) {
+ switch (nullDirection) {
+ case FIRST:
+ return -1;
+ case UNSPECIFIED:
+ case LAST:
+ return 1;
+ default:
+ throw new AssertionError(nullDirection);
+ }
+ }
}
// End SortNode.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
new file mode 100644
index 0000000..6f2c90f
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
@@ -0,0 +1,174 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.DataContext;
+import org.apache.calcite.linq4j.Enumerable;
+import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.linq4j.Queryable;
+import org.apache.calcite.linq4j.function.Function1;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.runtime.Enumerables;
+import org.apache.calcite.schema.FilterableTable;
+import org.apache.calcite.schema.ProjectableFilterableTable;
+import org.apache.calcite.schema.QueryableTable;
+import org.apache.calcite.schema.ScannableTable;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Schemas;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * Interpreter node that implements a
+ * {@link org.apache.calcite.rel.core.TableScan}.
+ */
+public class TableScanNode implements Node {
+ private final Sink sink;
+ private final TableScan rel;
+ private final ImmutableList<RexNode> filters;
+ private final DataContext root;
+ private final int[] projects;
+
+ TableScanNode(Interpreter interpreter, TableScan rel,
+ ImmutableList<RexNode> filters, ImmutableIntList projects) {
+ this.rel = rel;
+ this.filters = Preconditions.checkNotNull(filters);
+ this.projects = projects == null ? null : projects.toIntArray();
+ this.sink = interpreter.sink(rel);
+ this.root = interpreter.getDataContext();
+ }
+
+ public void run() throws InterruptedException {
+ final Enumerable<Row> iterable = iterable();
+ final Enumerator<Row> enumerator = iterable.enumerator();
+ while (enumerator.moveNext()) {
+ sink.send(enumerator.current());
+ }
+ enumerator.close();
+ sink.end();
+ }
+
+ private Enumerable<Row> iterable() {
+ final RelOptTable table = rel.getTable();
+ final ProjectableFilterableTable pfTable =
+ table.unwrap(ProjectableFilterableTable.class);
+ if (pfTable != null) {
+ final List<RexNode> filters1 = Lists.newArrayList(filters);
+ final int[] projects1 =
+ projects == null
+ || isIdentity(projects, rel.getRowType().getFieldCount())
+ ? null : projects;
+ final Enumerable<Object[]> enumerator =
+ pfTable.scan(root, filters1, projects1);
+ assert filters1.isEmpty()
+ : "table could not handle a filter it earlier said it could";
+ return Enumerables.toRow(enumerator);
+ }
+ if (projects != null) {
+ throw new AssertionError("have projects, but table cannot handle them");
+ }
+ final FilterableTable filterableTable =
+ table.unwrap(FilterableTable.class);
+ if (filterableTable != null) {
+ final List<RexNode> filters1 = Lists.newArrayList(filters);
+ final Enumerable<Object[]> enumerator =
+ filterableTable.scan(root, filters1);
+ assert filters1.isEmpty()
+ : "table could not handle a filter it earlier said it could";
+ return Enumerables.toRow(enumerator);
+ }
+ if (!filters.isEmpty()) {
+ throw new AssertionError("have filters, but table cannot handle them");
+ }
+ final ScannableTable scannableTable =
+ table.unwrap(ScannableTable.class);
+ if (scannableTable != null) {
+ return Enumerables.toRow(scannableTable.scan(root));
+ }
+ //noinspection unchecked
+ Enumerable<Row> iterable = table.unwrap(Enumerable.class);
+ if (iterable != null) {
+ return iterable;
+ }
+ final QueryableTable queryableTable = table.unwrap(QueryableTable.class);
+ if (queryableTable != null) {
+ final Type elementType = queryableTable.getElementType();
+ SchemaPlus schema = root.getRootSchema();
+ for (String name : Util.skipLast(table.getQualifiedName())) {
+ schema = schema.getSubSchema(name);
+ }
+ if (elementType instanceof Class) {
+ //noinspection unchecked
+ final Queryable<Object> queryable = Schemas.queryable(root,
+ (Class) elementType, table.getQualifiedName());
+ ImmutableList.Builder<Field> fieldBuilder = ImmutableList.builder();
+ Class type = (Class) elementType;
+ for (Field field : type.getFields()) {
+ if (Modifier.isPublic(field.getModifiers())
+ && !Modifier.isStatic(field.getModifiers())) {
+ fieldBuilder.add(field);
+ }
+ }
+ final List<Field> fields = fieldBuilder.build();
+ return queryable.select(
+ new Function1<Object, Row>() {
+ public Row apply(Object o) {
+ final Object[] values = new Object[fields.size()];
+ for (int i = 0; i < fields.size(); i++) {
+ Field field = fields.get(i);
+ try {
+ values[i] = field.get(o);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return new Row(values);
+ }
+ });
+ } else {
+ return Schemas.queryable(root, Row.class,
+ table.getQualifiedName());
+ }
+ }
+ throw new AssertionError("cannot convert table " + table + " to iterable");
+ }
+
+ private static boolean isIdentity(int[] is, int count) {
+ if (is.length != count) {
+ return false;
+ }
+ for (int i = 0; i < is.length; i++) {
+ if (is[i] != i) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+// End TableScanNode.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/UnionNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/UnionNode.java b/core/src/main/java/org/apache/calcite/interpreter/UnionNode.java
new file mode 100644
index 0000000..701dbc7
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/UnionNode.java
@@ -0,0 +1,58 @@
+/*
+ * 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.interpreter;
+
+import org.apache.calcite.rel.core.Union;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+/**
+ * Interpreter node that implements a
+ * {@link org.apache.calcite.rel.core.Union}.
+ */
+public class UnionNode implements Node {
+ private final ImmutableList<Source> sources;
+ private final Sink sink;
+ private final Union rel;
+
+ public UnionNode(Interpreter interpreter, Union rel) {
+ ImmutableList.Builder<Source> builder = ImmutableList.builder();
+ for (int i = 0; i < rel.getInputs().size(); i++) {
+ builder.add(interpreter.source(rel, i));
+ }
+ this.sources = builder.build();
+ this.sink = interpreter.sink(rel);
+ this.rel = rel;
+ }
+
+ public void run() throws InterruptedException {
+ final Set<Row> rows = rel.all ? null : Sets.<Row>newHashSet();
+ for (Source source : sources) {
+ Row row;
+ while ((row = source.receive()) != null) {
+ if (rows == null || rows.add(row)) {
+ sink.send(row);
+ }
+ }
+ }
+ }
+}
+
+// End UnionNode.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java b/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java
index fe68790..ff8c950 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java
@@ -16,8 +16,13 @@
*/
package org.apache.calcite.interpreter;
+import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Values;
import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import java.util.List;
@@ -27,23 +32,38 @@ import java.util.List;
*/
public class ValuesNode implements Node {
private final Sink sink;
- private final Values rel;
private final int fieldCount;
+ private final ImmutableList<Row> rows;
public ValuesNode(Interpreter interpreter, Values rel) {
- this.rel = rel;
this.sink = interpreter.sink(rel);
this.fieldCount = rel.getRowType().getFieldCount();
+ this.rows = createRows(interpreter, rel.getTuples());
+ }
+
+ private ImmutableList<Row> createRows(Interpreter interpreter,
+ ImmutableList<ImmutableList<RexLiteral>> tuples) {
+ final List<RexNode> nodes = Lists.newArrayList();
+ for (ImmutableList<RexLiteral> tuple : tuples) {
+ nodes.addAll(tuple);
+ }
+ final Scalar scalar =
+ interpreter.compile(nodes, ImmutableList.<RelNode>of());
+ final Object[] values = new Object[nodes.size()];
+ final Context context = interpreter.createContext();
+ scalar.execute(context, values);
+ final ImmutableList.Builder<Row> rows = ImmutableList.builder();
+ Object[] subValues = new Object[fieldCount];
+ for (int i = 0; i < values.length; i += fieldCount) {
+ System.arraycopy(values, i, subValues, 0, fieldCount);
+ rows.add(Row.asCopy(subValues));
+ }
+ return rows.build();
}
public void run() throws InterruptedException {
- for (List<RexLiteral> list : rel.getTuples()) {
- final Object[] values = new Object[fieldCount];
- for (int i = 0; i < list.size(); i++) {
- RexLiteral rexLiteral = list.get(i);
- values[i] = rexLiteral.getValue();
- }
- sink.send(new Row(values));
+ for (Row row : rows) {
+ sink.send(row);
}
sink.end();
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/interpreter/WindowNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/WindowNode.java b/core/src/main/java/org/apache/calcite/interpreter/WindowNode.java
new file mode 100644
index 0000000..a03608c
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/interpreter/WindowNode.java
@@ -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.
+ */
+package org.apache.calcite.interpreter;
+
+import org.apache.calcite.rel.core.Window;
+
+/**
+ * Interpreter node that implements a
+ * {@link org.apache.calcite.rel.core.Window}.
+ */
+public class WindowNode extends AbstractSingleNode<Window> {
+ WindowNode(Interpreter interpreter, Window rel) {
+ super(interpreter, rel);
+ }
+
+ public void run() throws InterruptedException {
+ Row row;
+ while ((row = source.receive()) != null) {
+ sink.send(row);
+ }
+ sink.end();
+ }
+}
+
+// End WindowNode.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/66cfb120/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
index 00e61b1..acbdfe9 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -33,6 +33,7 @@ import org.apache.calcite.prepare.CalcitePrepareImpl;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.runtime.ArrayBindable;
import org.apache.calcite.runtime.Bindable;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.validate.SqlValidator;
@@ -104,7 +105,7 @@ public interface CalcitePrepare {
boolean enabled();
- Bindable compile(ClassDeclaration expr, String s);
+ ArrayBindable compile(ClassDeclaration expr, String s);
Object sparkContext();
@@ -177,7 +178,7 @@ public interface CalcitePrepare {
return false;
}
- public Bindable compile(ClassDeclaration expr, String s) {
+ public ArrayBindable compile(ClassDeclaration expr, String s) {
throw new UnsupportedOperationException();
}