You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@drill.apache.org by ja...@apache.org on 2013/08/04 04:49:51 UTC

[2/2] git commit: Update to add additional Julian SQL work. Update to Parquet 0.4.9 OrderBy and Union (distinct) not currently working.

Update to add additional Julian SQL work.
Update to Parquet 0.4.9
OrderBy and Union (distinct) not currently working.


Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/d405c70d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/d405c70d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/d405c70d

Branch: refs/heads/master
Commit: d405c70df958629f70c6378241314876bcd1b7ab
Parents: 103072a
Author: Jacques Nadeau <ja...@apache.org>
Authored: Fri Aug 2 20:17:06 2013 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Sat Aug 3 19:40:26 2013 -0700

----------------------------------------------------------------------
 .../drill/common/logical/LogicalPlan.java       |   3 +-
 sandbox/prototype/sqlparser/pom.xml             | 167 +++----
 .../java/org/apache/drill/jdbc/DrillTable.java  | 156 +++---
 .../main/java/org/apache/drill/jdbc/Driver.java |   1 +
 .../apache/drill/optiq/DrillAggregateRel.java   | 119 +++++
 .../apache/drill/optiq/DrillAggregateRule.java  |  53 ++
 .../org/apache/drill/optiq/DrillFilterRel.java  |  30 +-
 .../org/apache/drill/optiq/DrillFilterRule.java |  16 +-
 .../apache/drill/optiq/DrillImplementor.java    |  33 +-
 .../org/apache/drill/optiq/DrillJoinRel.java    | 158 ++++++
 .../org/apache/drill/optiq/DrillJoinRule.java   |  57 +++
 .../java/org/apache/drill/optiq/DrillOptiq.java |  50 +-
 .../apache/drill/optiq/DrillPrepareImpl.java    |   3 -
 .../org/apache/drill/optiq/DrillProjectRel.java |  50 +-
 .../apache/drill/optiq/DrillProjectRule.java    |  29 +-
 .../java/org/apache/drill/optiq/DrillRel.java   |   4 +-
 .../java/org/apache/drill/optiq/DrillScan.java  |  11 +-
 .../org/apache/drill/optiq/DrillSortRel.java    |  88 ++++
 .../org/apache/drill/optiq/DrillSortRule.java   |  42 ++
 .../org/apache/drill/optiq/DrillUnionRel.java   |  70 +++
 .../org/apache/drill/optiq/DrillUnionRule.java  |  48 ++
 .../org/apache/drill/optiq/DrillValuesRel.java  |   9 +-
 .../org/apache/drill/optiq/DrillValuesRule.java |  17 +-
 .../org/apache/drill/optiq/EnumerableDrill.java | 250 ++++++++++
 .../drill/optiq/EnumerableDrillFullEngine.java  |   5 +-
 .../apache/drill/optiq/EnumerableDrillRel.java  |  71 ++-
 .../apache/drill/optiq/EnumerableDrillRule.java |   5 +-
 .../drill/sql/client/full/ResultEnumerator.java |   4 +
 .../drill/sql/client/ref/DrillRefImpl.java      |   5 +
 .../apache/drill/jdbc/test/FullEngineTest.java  |  37 ++
 .../org/apache/drill/jdbc/test/JdbcAssert.java  | 178 +++++--
 .../org/apache/drill/jdbc/test/JdbcTest.java    | 494 +++++++++++--------
 .../src/test/resources/donuts-output-data.txt   |   5 +
 .../src/test/resources/full-model.json          |  18 +
 .../src/test/resources/test-models.json         |  77 +++
 35 files changed, 1780 insertions(+), 583 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/common/src/main/java/org/apache/drill/common/logical/LogicalPlan.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/common/src/main/java/org/apache/drill/common/logical/LogicalPlan.java b/sandbox/prototype/common/src/main/java/org/apache/drill/common/logical/LogicalPlan.java
index cf15f48..05fbd1f 100644
--- a/sandbox/prototype/common/src/main/java/org/apache/drill/common/logical/LogicalPlan.java
+++ b/sandbox/prototype/common/src/main/java/org/apache/drill/common/logical/LogicalPlan.java
@@ -93,7 +93,8 @@ public class LogicalPlan {
       LogicalPlan plan = mapper.readValue(planString, LogicalPlan.class);
       return plan;
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      
+      throw new RuntimeException(String.format("Failure while parsing plan: \n %s}", planString), e);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/pom.xml
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/pom.xml b/sandbox/prototype/sqlparser/pom.xml
index 9be576e..f30944c 100644
--- a/sandbox/prototype/sqlparser/pom.xml
+++ b/sandbox/prototype/sqlparser/pom.xml
@@ -1,94 +1,95 @@
 <?xml version="1.0"?>
 <project
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<artifactId>prototype-parent</artifactId>
-		<groupId>org.apache.drill</groupId>
-		<version>1.0-SNAPSHOT</version>
-	</parent>
-	<artifactId>sqlparser</artifactId>
-	<name>sqlparser</name>
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>prototype-parent</artifactId>
+    <groupId>org.apache.drill</groupId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>sqlparser</artifactId>
+  <name>sqlparser</name>
 
-	<repositories>
-		<repository>
-			<releases>
-				<enabled>true</enabled>
-				<updatePolicy>always</updatePolicy>
-				<checksumPolicy>warn</checksumPolicy>
-			</releases>
-			<id>conjars</id>
-			<name>Conjars</name>
-			<url>http://conjars.org/repo</url>
-			<layout>default</layout>
-		</repository>
-	</repositories>
+  <repositories>
+    <repository>
+      <releases>
+        <enabled>true</enabled>
+        <updatePolicy>always</updatePolicy>
+        <checksumPolicy>warn</checksumPolicy>
+      </releases>
+      <id>conjars</id>
+      <name>Conjars</name>
+      <url>http://conjars.org/repo</url>
+      <layout>default</layout>
+    </repository>
+  </repositories>
 
-	<dependencies>
-    	<dependency>
-			<groupId>net.hydromatic</groupId>
-			<artifactId>optiq</artifactId>
-			<version>0.4.2</version>
-		</dependency>
-		<dependency>
-			<groupId>net.hydromatic</groupId>
-			<artifactId>linq4j</artifactId>
-			<version>0.1.2</version>
-		</dependency>
-        <dependency>
-			<groupId>org.apache.drill</groupId>
-			<artifactId>common</artifactId>
-			<version>1.0-SNAPSHOT</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.drill.exec</groupId>
-			<artifactId>ref</artifactId>
+  <dependencies>
+    <dependency>
+      <groupId>net.hydromatic</groupId>
+      <artifactId>optiq</artifactId>
+      <version>0.4.9</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.drill</groupId>
+      <artifactId>common</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.drill.exec</groupId>
+      <artifactId>ref</artifactId>
       <version>${project.version}</version>
-      </dependency>
-      <dependency>
-    	<groupId>org.apache.drill.exec</groupId>
-			<artifactId>java-exec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.drill.exec</groupId>
+      <artifactId>java-exec</artifactId>
       <version>${project.version}</version>
-		</dependency>
-      <dependency>
-    	<groupId>org.apache.drill.exec</groupId>
-			<artifactId>java-exec</artifactId>
-            <version>${project.version}</version>
-			<classifier>tests</classifier>
-			<scope>test</scope>
-		</dependency>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.drill.exec</groupId>
+      <artifactId>java-exec</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>pentaho</groupId>
+      <artifactId>mondrian-data-foodmart-queries</artifactId>
+      <version>0.3</version>
+      <scope>test</scope>
+    </dependency>
 
 
-		<dependency>
-			<groupId>org.apache.drill.exec</groupId>
-			<artifactId>ref</artifactId>
+    <dependency>
+      <groupId>org.apache.drill.exec</groupId>
+      <artifactId>ref</artifactId>
       <version>${project.version}</version>
-			<classifier>tests</classifier>
-			<scope>test</scope>
-		</dependency>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
 
-		<dependency>
-			<groupId>org.codehaus.janino</groupId>
-			<artifactId>janino</artifactId>
-			<version>2.6.1</version>
-		</dependency>
-		<dependency>
-			<groupId>sqlline</groupId>
-			<artifactId>sqlline</artifactId>
-			<version>1.1.0</version>
-			<scope>test</scope>
-		</dependency>
-		<!-- Specify xalan and xerces versions to avoid setXIncludeAware error. -->
-		<dependency>
-			<groupId>xerces</groupId>
-			<artifactId>xercesImpl</artifactId>
-			<version>2.9.1</version>
-		</dependency>
-		<dependency>
-			<groupId>xalan</groupId>
-			<artifactId>xalan</artifactId>
-			<version>2.7.1</version>
-		</dependency>
-	</dependencies>
+    <dependency>
+      <groupId>org.codehaus.janino</groupId>
+      <artifactId>janino</artifactId>
+      <version>2.6.1</version>
+    </dependency>
+    <dependency>
+      <groupId>sqlline</groupId>
+      <artifactId>sqlline</artifactId>
+      <version>1.1.0</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- Specify xalan and xerces versions to avoid setXIncludeAware error. -->
+    <dependency>
+      <groupId>xerces</groupId>
+      <artifactId>xercesImpl</artifactId>
+      <version>2.9.1</version>
+    </dependency>
+    <dependency>
+      <groupId>xalan</groupId>
+      <artifactId>xalan</artifactId>
+      <version>2.7.1</version>
+    </dependency>
+  </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/DrillTable.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/DrillTable.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/DrillTable.java
index 602a55d..dd86372 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/DrillTable.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/DrillTable.java
@@ -19,7 +19,9 @@ package org.apache.drill.jdbc;
 
 import java.io.IOException;
 import java.lang.reflect.Type;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 import net.hydromatic.linq4j.BaseQueryable;
@@ -28,8 +30,15 @@ import net.hydromatic.linq4j.Linq4j;
 import net.hydromatic.linq4j.expressions.Expression;
 import net.hydromatic.linq4j.expressions.Expressions;
 import net.hydromatic.linq4j.expressions.MethodCallExpression;
-
-import net.hydromatic.optiq.*;
+import net.hydromatic.optiq.BuiltinMethod;
+import net.hydromatic.optiq.DataContext;
+import net.hydromatic.optiq.MutableSchema;
+import net.hydromatic.optiq.Schema;
+import net.hydromatic.optiq.Statistic;
+import net.hydromatic.optiq.Statistics;
+import net.hydromatic.optiq.TableFactory;
+import net.hydromatic.optiq.TranslatableTable;
+import net.hydromatic.optiq.impl.java.JavaTypeFactory;
 
 import org.apache.drill.common.config.DrillConfig;
 import org.apache.drill.common.logical.StorageEngineConfig;
@@ -37,7 +46,6 @@ import org.apache.drill.exec.client.DrillClient;
 import org.apache.drill.exec.ref.rops.DataWriter;
 import org.apache.drill.exec.ref.rse.ClasspathRSE;
 import org.apache.drill.exec.ref.rse.ClasspathRSE.ClasspathInputConfig;
-
 import org.apache.drill.exec.server.Drillbit;
 import org.apache.drill.exec.server.RemoteServiceSet;
 import org.apache.drill.optiq.DrillRel;
@@ -48,38 +56,42 @@ import org.eigenbase.reltype.RelDataType;
 import org.eigenbase.reltype.RelDataTypeFactory;
 import org.eigenbase.sql.type.SqlTypeName;
 
-/**
- * Optiq Table used by Drill.
- */
+/** Optiq Table used by Drill. */
 public class DrillTable extends BaseQueryable<Object>
-    implements TranslatableTable<Object> {
+    implements TranslatableTable<Object>
+{
   private final Schema schema;
   private final String name;
-  private final String storageEngineName;
+  private final String storageEngineName;  
   private final RelDataType rowType;
   public final StorageEngineConfig storageEngineConfig;
   public final Object selection;
   private boolean useReferenceInterpreter;
-
   // full engine connection information
   public Drillbit bit;
   public DrillClient client;
 
-  /**
-   * Creates a DrillTable.
-   */
+  /** Creates a DrillTable. */
   public DrillTable(Schema schema,
-                    Type elementType,
-                    Expression expression,
-                    RelDataType rowType,
-                    String name,
-                    StorageEngineConfig storageEngineConfig,
-                    Object selection,
-                    String storageEngineName,
-                    boolean useReferenceInterpreter
-  ) {
-
+      Type elementType,
+      Expression expression,
+      RelDataType rowType,
+      String name,
+      StorageEngineConfig storageEngineConfig,
+      Object selection,
+      String storageEngineName,
+      boolean useReferenceInterpreter     
+      ) {
     super(schema.getQueryProvider(), elementType, expression);
+    this.schema = schema;
+    this.name = name;
+    this.rowType = rowType;
+    this.storageEngineConfig = storageEngineConfig;
+    this.selection = selection;
+    this.storageEngineName = storageEngineName;
+    this.useReferenceInterpreter = useReferenceInterpreter;
+
+    
     DrillConfig config = DrillConfig.create();
     RemoteServiceSet serviceSet = RemoteServiceSet.getLocalServiceSet();
     try {
@@ -91,13 +103,7 @@ public class DrillTable extends BaseQueryable<Object>
     } catch (Exception e) {
       System.out.println("Error creating drill client or connecting to drillbit.");
     }
-    this.schema = schema;
-    this.name = name;
-    this.rowType = rowType;
-    this.storageEngineConfig = storageEngineConfig;
-    this.selection = selection;
-    this.storageEngineName = storageEngineName;
-    this.useReferenceInterpreter = useReferenceInterpreter;
+
   }
 
   private static DrillTable createTable(
@@ -108,7 +114,7 @@ public class DrillTable extends BaseQueryable<Object>
       Object selection,
       String storageEngineName,
       boolean useReferenceInterpreter
-  ) {
+      ) {
     final MethodCallExpression call = Expressions.call(schema.getExpression(),
         BuiltinMethod.DATA_CONTEXT_GET_TABLE.method,
         Expressions.constant(name),
@@ -120,8 +126,8 @@ public class DrillTable extends BaseQueryable<Object>
                     typeFactory.createSqlType(SqlTypeName.VARCHAR),
                     typeFactory.createSqlType(SqlTypeName.ANY))),
             Collections.singletonList("_MAP"));
-    return new DrillTable(schema, Object.class, call, rowType, name,
-        storageEngineConfig, selection, storageEngineName, useReferenceInterpreter);
+      return new DrillTable(schema, Object.class, call, rowType, name,
+          storageEngineConfig, selection, storageEngineName, useReferenceInterpreter);
   }
 
   @Override
@@ -129,6 +135,15 @@ public class DrillTable extends BaseQueryable<Object>
     return schema;
   }
 
+  
+  public String getStorageEngineName() {
+    return storageEngineName;
+  }
+
+  public boolean useReferenceInterpreter() {
+    return useReferenceInterpreter;
+  }
+
   @Override
   public RelDataType getRowType() {
     return rowType;
@@ -139,10 +154,6 @@ public class DrillTable extends BaseQueryable<Object>
     return Statistics.UNKNOWN;
   }
 
-  public String getStorageEngineName() {
-    return storageEngineName;
-  }
-
   @Override
   public Enumerator<Object> enumerator() {
     return Linq4j.emptyEnumerator();
@@ -154,36 +165,69 @@ public class DrillTable extends BaseQueryable<Object>
         table);
   }
 
-  private static <T> T last(T t0, T t1) {
-    return t0 != null ? t0 : t1;
-  }
-
-  public boolean useReferenceInterpreter() {
-    return useReferenceInterpreter;
-  }
-
-  /**
-   * Factory for custom tables in Optiq schema.
-   */
+  /** Factory for custom tables in Optiq schema. */
   @SuppressWarnings("UnusedDeclaration")
   public static class Factory implements TableFactory<DrillTable> {
+
+    private static final List<String> DONUTS_TABLES = Arrays.asList(
+        "DONUTS");
+
+    private static final List<String> HR_TABLES = Arrays.asList(
+        "EMPLOYEES", "DEPARTMENTS");
+
+    private static final List<String> FOODMART_TABLES = Arrays.asList(
+        "ACCOUNT", "CATEGORY", "CURRENCY", "CUSTOMER", "DAYS", "DEPARTMENT",
+        "EMPLOYEE_CLOSURE", "EMPLOYEE", "EXPENSE_FACT", "INVENTORY_FACT_1997",
+        "INVENTORY_FACT_1998", "POSITION", "PRODUCT_CLASS", "PRODUCT",
+        "PROMOTION", "REGION", "RESERVE_EMPLOYEE", "SALARY", "SALES_FACT_1997",
+        "SALES_FACT_1998", "SALES_FACT_DEC_1998", "STORE", "STORE_RAGGED",
+        "TIME_BY_DAY", "WAREHOUSE", "WAREHOUSE_CLASS");
+
+//    public DrillTable create(
+//        JavaTypeFactory typeFactory,
+//        Schema schema,
+//        String name,
+//        Map<String, Object> operand, 
+//        RelDataType rowType) {
+//      final ClasspathRSE.ClasspathRSEConfig rseConfig = new ClasspathRSE.ClasspathRSEConfig();
+//      final ClasspathInputConfig inputConfig = new ClasspathInputConfig();
+//      assert DONUTS_TABLES.contains(name)
+//          || HR_TABLES.contains(name)
+//          || FOODMART_TABLES.contains(name)
+//          : name;
+//      inputConfig.path = "/" + name.toLowerCase() + ".json";
+//      inputConfig.type = DataWriter.ConverterType.JSON;
+//      boolean useReferenceInterpreter;
+//      if (operand.get("useReferenceInterpreter") != null){
+//        useReferenceInterpreter = operand.get("useReferenceInterpreter").equals("true") ? true : false;
+//      }
+//      else{
+//        useReferenceInterpreter = false;
+//      }      
+//      return createTable(typeFactory, (MutableSchema) schema, name, rseConfig,
+//          inputConfig, "donuts-json", useReferenceInterpreter);
+//    }
+//
     @Override
-    public DrillTable create(Schema schema, String name,
-                             Map<String, Object> operand, RelDataType rowType) {
-      final ClasspathRSE.ClasspathRSEConfig rseConfig =
-          new ClasspathRSE.ClasspathRSEConfig();
+    public DrillTable create(Schema schema, String name, Map<String, Object> operand, RelDataType rowType) {
+      
+      final ClasspathRSE.ClasspathRSEConfig rseConfig = new ClasspathRSE.ClasspathRSEConfig();
       final ClasspathInputConfig inputConfig = new ClasspathInputConfig();
-      inputConfig.path = last((String) operand.get("path"), "/donuts.json");
+      assert DONUTS_TABLES.contains(name)
+          || HR_TABLES.contains(name)
+          || FOODMART_TABLES.contains(name)
+          : name;
+      inputConfig.path = "/" + name.toLowerCase() + ".json";
+      inputConfig.type = DataWriter.ConverterType.JSON;
       boolean useReferenceInterpreter;
       if (operand.get("useReferenceInterpreter") != null){
         useReferenceInterpreter = operand.get("useReferenceInterpreter").equals("true") ? true : false;
       }
       else{
         useReferenceInterpreter = false;
-      }
-      inputConfig.type = DataWriter.ConverterType.JSON;
-      return createTable(schema.getTypeFactory(), (MutableSchema) schema, name,
-          rseConfig, inputConfig, "donuts-json", useReferenceInterpreter);
+      }      
+      return createTable(schema.getTypeFactory(), (MutableSchema) schema, name, rseConfig,
+          inputConfig, "donuts-json", useReferenceInterpreter);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/Driver.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/Driver.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/Driver.java
index 33a7294..dba2162 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/Driver.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/jdbc/Driver.java
@@ -64,6 +64,7 @@ public class Driver extends UnregisteredDriver {
     {
       super.onConnectionInit(connection);
 
+      
       final String model = connection.getProperties().getProperty("model");
       if (model != null) {
         try {

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillAggregateRel.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillAggregateRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillAggregateRel.java
new file mode 100644
index 0000000..6670933
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillAggregateRel.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * 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.drill.optiq;
+
+import java.util.BitSet;
+import java.util.List;
+
+import net.hydromatic.linq4j.Ord;
+
+import org.eigenbase.rel.AggregateCall;
+import org.eigenbase.rel.AggregateRelBase;
+import org.eigenbase.rel.InvalidRelException;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.RelOptCluster;
+import org.eigenbase.relopt.RelTraitSet;
+import org.eigenbase.util.Util;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Aggregation implemented in Drill.
+ */
+public class DrillAggregateRel extends AggregateRelBase implements DrillRel {
+  /** Creates a DrillAggregateRel. */
+  public DrillAggregateRel(RelOptCluster cluster, RelTraitSet traits, RelNode child, BitSet groupSet,
+      List<AggregateCall> aggCalls) throws InvalidRelException {
+    super(cluster, traits, child, groupSet, aggCalls);
+    for (AggregateCall aggCall : aggCalls) {
+      if (aggCall.isDistinct()) {
+        throw new InvalidRelException("DrillAggregateRel does not support DISTINCT aggregates");
+      }
+    }
+  }
+
+  @Override
+  public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+    try {
+      return new DrillAggregateRel(getCluster(), traitSet, sole(inputs), getGroupSet(), aggCalls);
+    } catch (InvalidRelException e) {
+      throw new AssertionError(e);
+    }
+  }
+
+  @Override
+  public int implement(DrillImplementor implementor) {
+    int inputId = implementor.visitChild(this, 0, getChild());
+    final List<String> childFields = getChild().getRowType().getFieldNames();
+    final List<String> fields = getRowType().getFieldNames();
+    /*
+     * E.g. { op: "segment", ref: "segment", exprs: ["deptId"] }, { op: "collapsingaggregate", within: "segment",
+     * carryovers: ["deptId"], aggregations: [ {ref: "c", expr: "count(1)"} ] }
+     */
+    final ObjectNode segment = implementor.mapper.createObjectNode();
+    segment.put("op", "segment");
+    segment.put("input", inputId);
+    // TODO: choose different name for field if there is already a field
+    // called "segment"
+    segment.put("ref", "segment");
+    final ArrayNode exprs = implementor.mapper.createArrayNode();
+    segment.put("exprs", exprs);
+    for (int group : Util.toIter(groupSet)) {
+      exprs.add(childFields.get(group));
+    }
+
+    final int segmentId = implementor.add(segment);
+
+    final ObjectNode aggregate = implementor.mapper.createObjectNode();
+    aggregate.put("op", "collapsingaggregate");
+    aggregate.put("input", segmentId);
+    aggregate.put("within", "segment");
+    final ArrayNode carryovers = implementor.mapper.createArrayNode();
+    aggregate.put("carryovers", carryovers);
+    for (int group : Util.toIter(groupSet)) {
+      carryovers.add(childFields.get(group));
+    }
+    final ArrayNode aggregations = implementor.mapper.createArrayNode();
+    aggregate.put("aggregations", aggregations);
+    for (Ord<AggregateCall> aggCall : Ord.zip(aggCalls)) {
+      final ObjectNode aggregation = implementor.mapper.createObjectNode();
+      aggregation.put("ref", fields.get(groupSet.cardinality() + aggCall.i));
+      aggregation.put("expr", toDrill(aggCall.e, childFields));
+      aggregations.add(aggregation);
+    }
+
+    return implementor.add(aggregate);
+  }
+
+  private String toDrill(AggregateCall call, List<String> fn) {
+    final StringBuilder buf = new StringBuilder();
+    buf.append(call.getAggregation().getName().toLowerCase()).append("(");
+    for (Ord<Integer> arg : Ord.zip(call.getArgList())) {
+      if (arg.i > 0) {
+        buf.append(", ");
+      }
+      buf.append(fn.get(arg.e));
+    }
+    if (call.getArgList().isEmpty()) {
+      buf.append("1"); // dummy arg to implement COUNT(*)
+    }
+    buf.append(")");
+    return buf.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillAggregateRule.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillAggregateRule.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillAggregateRule.java
new file mode 100644
index 0000000..3267917
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillAggregateRule.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.drill.optiq;
+
+import org.eigenbase.rel.AggregateRel;
+import org.eigenbase.rel.InvalidRelException;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.*;
+import org.eigenbase.trace.EigenbaseTrace;
+
+import java.util.logging.Logger;
+
+/**
+ * Rule that converts an {@link AggregateRel} to a {@link DrillAggregateRel}, implemented by a Drill "segment" operation
+ * followed by a "collapseaggregate" operation.
+ */
+public class DrillAggregateRule extends RelOptRule {
+  public static final RelOptRule INSTANCE = new DrillAggregateRule();
+  protected static final Logger tracer = EigenbaseTrace.getPlannerTracer();
+
+  private DrillAggregateRule() {
+    super(RelOptRule.some(AggregateRel.class, Convention.NONE, RelOptRule.any(RelNode.class)), "DrillAggregateRule");
+  }
+
+  @Override
+  public void onMatch(RelOptRuleCall call) {
+    final AggregateRel aggregate = (AggregateRel) call.rel(0);
+    final RelNode input = call.rel(1);
+    final RelTraitSet traits = aggregate.getTraitSet().plus(DrillRel.CONVENTION);
+    final RelNode convertedInput = convert(input, traits);
+    try {
+      call.transformTo(new DrillAggregateRel(aggregate.getCluster(), traits, convertedInput, aggregate.getGroupSet(),
+          aggregate.getAggCallList()));
+    } catch (InvalidRelException e) {
+      tracer.warning(e.toString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java
index b29bcb5..cd6b1c9 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java
@@ -30,16 +30,14 @@ import java.util.List;
  * Filter implemented in Drill.
  */
 public class DrillFilterRel extends FilterRelBase implements DrillRel {
-  protected DrillFilterRel(RelOptCluster cluster, RelTraitSet traits,
-      RelNode child, RexNode condition) {
+  protected DrillFilterRel(RelOptCluster cluster, RelTraitSet traits, RelNode child, RexNode condition) {
     super(cluster, traits, child, condition);
     assert getConvention() == CONVENTION;
   }
 
   @Override
   public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
-    return new DrillFilterRel(getCluster(), traitSet, sole(inputs),
-        getCondition());
+    return new DrillFilterRel(getCluster(), traitSet, sole(inputs), getCondition());
   }
 
   @Override
@@ -48,19 +46,15 @@ public class DrillFilterRel extends FilterRelBase implements DrillRel {
   }
 
   @Override
-  public void implement(DrillImplementor implementor) {
-    implementor.visitChild(this, 0, getChild());
-    final ObjectNode node = implementor.mapper.createObjectNode();
-/*
-      E.g. {
-	      op: "filter",
-	      expr: "donuts.ppu < 1.00"
-	    }
-*/
-    node.put("op", "filter");
-    node.put("expr", DrillOptiq.toDrill(getChild(), getCondition()));
-    implementor.add(node);
+  public int implement(DrillImplementor implementor) {
+    final int inputId = implementor.visitChild(this, 0, getChild());
+    final ObjectNode filter = implementor.mapper.createObjectNode();
+    /*
+     * E.g. { op: "filter", expr: "donuts.ppu < 1.00" }
+     */
+    filter.put("op", "filter");
+    filter.put("input", inputId);
+    filter.put("expr", DrillOptiq.toDrill(getChild(), getCondition()));
+    return implementor.add(filter);
   }
 }
-
-// End DrillFilterRel.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRule.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRule.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRule.java
index 8687304..4fdbed2 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRule.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRule.java
@@ -22,19 +22,13 @@ import org.eigenbase.rel.RelNode;
 import org.eigenbase.relopt.*;
 
 /**
- * Rule that converts a {@link org.eigenbase.rel.FilterRel} to a Drill
- * "filter" operation.
+ * Rule that converts a {@link org.eigenbase.rel.FilterRel} to a Drill "filter" operation.
  */
 public class DrillFilterRule extends RelOptRule {
   public static final RelOptRule INSTANCE = new DrillFilterRule();
 
   private DrillFilterRule() {
-    super(
-        new RelOptRuleOperand(
-            FilterRel.class,
-            Convention.NONE,
-            new RelOptRuleOperand(RelNode.class, ANY)),
-        "DrillFilterRule");
+    super(RelOptRule.some(FilterRel.class, Convention.NONE, RelOptRule.any(RelNode.class)), "DrillFilterRule");
   }
 
   @Override
@@ -43,10 +37,6 @@ public class DrillFilterRule extends RelOptRule {
     final RelNode input = call.getRels()[1];
     final RelTraitSet traits = filter.getTraitSet().plus(DrillRel.CONVENTION);
     final RelNode convertedInput = convert(input, traits);
-    call.transformTo(
-        new DrillFilterRel(filter.getCluster(), traits, convertedInput,
-            filter.getCondition()));
+    call.transformTo(new DrillFilterRel(filter.getCluster(), traits, convertedInput, filter.getCondition()));
   }
 }
-
-// End DrillFilterRule.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillImplementor.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillImplementor.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillImplementor.java
index cbeed5f..57091c8 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillImplementor.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillImplementor.java
@@ -28,8 +28,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.eigenbase.rel.RelNode;
 
 /**
- * Context for converting a tree of {@link DrillRel} nodes into a Drill logical
- * plan.
+ * Context for converting a tree of {@link DrillRel} nodes into a Drill logical plan.
  */
 public class DrillImplementor {
   final ObjectMapper mapper = new ObjectMapper();
@@ -49,14 +48,14 @@ public class DrillImplementor {
 
     final ObjectNode generatorNode = mapper.createObjectNode();
     headNode.put("generator", generatorNode);
-    generatorNode.put("type", "manual");
+    generatorNode.put("type", "optiq");
     generatorNode.put("info", "na");
 
     // TODO: populate sources based on the sources of scans that occur in
     // the query
     final ObjectNode sourcesNode = mapper.createObjectNode();
     rootNode.put("storage", sourcesNode);
-    
+
     // input file source
     {
       final ObjectNode sourceNode = mapper.createObjectNode();
@@ -68,36 +67,33 @@ public class DrillImplementor {
       sourceNode.put("type", "queue");
       sourcesNode.put("queue", sourceNode);
     }
-    
 
-    
     final ArrayNode queryNode = mapper.createArrayNode();
     rootNode.put("query", queryNode);
 
-    final ObjectNode sequenceOpNode = mapper.createObjectNode();
-    queryNode.add(sequenceOpNode);
-    sequenceOpNode.put("op", "sequence");
-
-    this.operatorsNode = mapper.createArrayNode();
-    sequenceOpNode.put("do", operatorsNode);
+    this.operatorsNode = queryNode;
   }
 
-  public void go(DrillRel root) {
-    root.implement(this);
+  public int go(DrillRel root) {
+    int inputId = root.implement(this);
 
     // Add a last node, to write to the output queue.
     final ObjectNode writeOp = mapper.createObjectNode();
     writeOp.put("op", "store");
+    writeOp.put("input", inputId);
     writeOp.put("storageengine", "queue");
     writeOp.put("memo", "output sink");
     QueueOutputInfo output = new QueueOutputInfo();
     output.number = 0;
     writeOp.put("target", mapper.convertValue(output, JsonNode.class));
-    add(writeOp);
+    return add(writeOp);
   }
 
-  public void add(ObjectNode operator) {
+  public int add(ObjectNode operator) {
     operatorsNode.add(operator);
+    final int id = operatorsNode.size();
+    operator.put("@id", id);
+    return id;
   }
 
   /** Returns the generated plan. */
@@ -107,9 +103,8 @@ public class DrillImplementor {
     return s;
   }
 
-  public void visitChild(DrillRel parent, int ordinal, RelNode child) {
+  public int visitChild(DrillRel parent, int ordinal, RelNode child) {
     ((DrillRel) child).implement(this);
+    return operatorsNode.size();
   }
 }
-
-// End DrillImplementor.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillJoinRel.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillJoinRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillJoinRel.java
new file mode 100644
index 0000000..79e2da9
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillJoinRel.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * 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.drill.optiq;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+import org.eigenbase.rel.InvalidRelException;
+import org.eigenbase.rel.JoinRelBase;
+import org.eigenbase.rel.JoinRelType;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.RelOptCluster;
+import org.eigenbase.relopt.RelOptUtil;
+import org.eigenbase.relopt.RelTraitSet;
+import org.eigenbase.reltype.RelDataType;
+import org.eigenbase.rex.RexNode;
+import org.eigenbase.util.Pair;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Join implemented in Drill.
+ */
+public class DrillJoinRel extends JoinRelBase implements DrillRel {
+  private final List<Integer> leftKeys = new ArrayList<>();
+  private final List<Integer> rightKeys = new ArrayList<>();
+
+  /** Creates a DrillJoinRel. */
+  public DrillJoinRel(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode right, RexNode condition,
+      JoinRelType joinType) throws InvalidRelException {
+    super(cluster, traits, left, right, condition, joinType, Collections.<String> emptySet());
+    switch (joinType) {
+    case RIGHT:
+      throw new InvalidRelException("DrillJoinRel does not support RIGHT join");
+    }
+    RexNode remaining = RelOptUtil.splitJoinCondition(left, right, condition, leftKeys, rightKeys);
+    if (!remaining.isAlwaysTrue()) {
+      throw new InvalidRelException("DrillJoinRel only supports equi-join");
+    }
+  }
+
+  @Override
+  public DrillJoinRel copy(RelTraitSet traitSet, RexNode condition, RelNode left, RelNode right) {
+    try {
+      return new DrillJoinRel(getCluster(), traitSet, left, right, condition, joinType);
+    } catch (InvalidRelException e) {
+      throw new AssertionError(e);
+    }
+  }
+
+  @Override
+  public int implement(DrillImplementor implementor) {
+    final List<String> fields = getRowType().getFieldNames();
+    assert isUnique(fields);
+    final int leftCount = left.getRowType().getFieldCount();
+    final List<String> leftFields = fields.subList(0, leftCount);
+    final List<String> rightFields = fields.subList(leftCount, fields.size());
+
+    final int leftId = implementInput(implementor, 0, 0, left);
+    final int rightId = implementInput(implementor, 1, leftCount, right);
+
+    /*
+     * E.g. { op: "join", left: 2, right: 4, conditions: [ {relationship: "==", left: "deptId", right: "deptId"} ] }
+     */
+    final ObjectNode join = implementor.mapper.createObjectNode();
+    join.put("op", "join");
+    join.put("left", leftId);
+    join.put("right", rightId);
+    join.put("type", toDrill(joinType));
+    final ArrayNode conditions = implementor.mapper.createArrayNode();
+    join.put("conditions", conditions);
+    for (Pair<Integer, Integer> pair : Pair.zip(leftKeys, rightKeys)) {
+      final ObjectNode condition = implementor.mapper.createObjectNode();
+      condition.put("relationship", "==");
+      condition.put("left", leftFields.get(pair.left));
+      condition.put("right", rightFields.get(pair.left));
+      conditions.add(condition);
+    }
+    return implementor.add(join);
+  }
+
+  private int implementInput(DrillImplementor implementor, int i, int offset, RelNode input) {
+    final int inputId = implementor.visitChild(this, i, input);
+    assert uniqueFieldNames(input.getRowType());
+    final List<String> fields = getRowType().getFieldNames();
+    final List<String> inputFields = input.getRowType().getFieldNames();
+    final List<String> outputFields = fields.subList(offset, offset + inputFields.size());
+    if (!outputFields.equals(inputFields)) {
+      // Ensure that input field names are the same as output field names.
+      // If there are duplicate field names on left and right, fields will get
+      // lost.
+      return rename(implementor, inputId, inputFields, outputFields);
+    } else {
+      return inputId;
+    }
+  }
+
+  private int rename(DrillImplementor implementor, int inputId, List<String> inputFields, List<String> outputFields) {
+    final ObjectNode project = implementor.mapper.createObjectNode();
+    project.put("op", "project");
+    project.put("input", inputId);
+    final ArrayNode transforms = implementor.mapper.createArrayNode();
+    project.put("projections", transforms);
+    for (Pair<String, String> pair : Pair.zip(inputFields, outputFields)) {
+      final ObjectNode objectNode = implementor.mapper.createObjectNode();
+      transforms.add(objectNode);
+      objectNode.put("expr", pair.left);
+      objectNode.put("ref", "output." + pair.right);
+    }
+    return implementor.add(project);
+  }
+
+  /**
+   * Returns whether there are any elements in common between left and right.
+   */
+  private static <T> boolean intersects(List<T> left, List<T> right) {
+    return new HashSet<>(left).removeAll(right);
+  }
+
+  private boolean uniqueFieldNames(RelDataType rowType) {
+    return isUnique(rowType.getFieldNames());
+  }
+
+  private static <T> boolean isUnique(List<T> list) {
+    return new HashSet<>(list).size() == list.size();
+  }
+
+  private static String toDrill(JoinRelType joinType) {
+    switch (joinType) {
+    case LEFT:
+      return "left";
+    case INNER:
+      return "inner";
+    case FULL:
+      return "outer";
+    default:
+      throw new AssertionError(joinType);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillJoinRule.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillJoinRule.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillJoinRule.java
new file mode 100644
index 0000000..ad858e2
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillJoinRule.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.drill.optiq;
+
+import org.eigenbase.rel.InvalidRelException;
+import org.eigenbase.rel.JoinRel;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.*;
+import org.eigenbase.trace.EigenbaseTrace;
+
+import java.util.logging.Logger;
+
+/**
+ * Rule that converts a {@link JoinRel} to a {@link DrillJoinRel}, which is implemented by Drill "join" operation.
+ */
+public class DrillJoinRule extends RelOptRule {
+  public static final RelOptRule INSTANCE = new DrillJoinRule();
+  protected static final Logger tracer = EigenbaseTrace.getPlannerTracer();
+
+  private DrillJoinRule() {
+    super(
+        RelOptRule.some(JoinRel.class, Convention.NONE, RelOptRule.any(RelNode.class), RelOptRule.any(RelNode.class)),
+        "DrillJoinRule");
+  }
+
+  @Override
+  public void onMatch(RelOptRuleCall call) {
+    final JoinRel join = (JoinRel) call.rel(0);
+    final RelNode left = call.rel(1);
+    final RelNode right = call.rel(2);
+    final RelTraitSet traits = join.getTraitSet().plus(DrillRel.CONVENTION);
+
+    final RelNode convertedLeft = convert(left, traits);
+    final RelNode convertedRight = convert(right, traits);
+    try {
+      call.transformTo(new DrillJoinRel(join.getCluster(), traits, convertedLeft, convertedRight, join.getCondition(),
+          join.getJoinType()));
+    } catch (InvalidRelException e) {
+      tracer.warning(e.toString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java
index 73391b3..1a66c0c 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java
@@ -17,6 +17,7 @@
  ******************************************************************************/
 package org.apache.drill.optiq;
 
+import net.hydromatic.linq4j.Ord;
 import org.eigenbase.rel.RelNode;
 import org.eigenbase.relopt.RelOptPlanner;
 import org.eigenbase.reltype.RelDataTypeField;
@@ -30,25 +31,25 @@ import org.eigenbase.sql.fun.SqlStdOperatorTable;
 public class DrillOptiq {
   static void registerStandardPlannerRules(RelOptPlanner planner) {
     planner.addRule(EnumerableDrillRule.ARRAY_INSTANCE);
-    planner.addRule(EnumerableDrillRule.CUSTOM_INSTANCE);
 
-//    planner.addRule(DrillTableModificationConverterRule.INSTANCE);
-//    planner.addRule(DrillAggregateConverterRule.INSTANCE);
-//    planner.addRule(DrillCalcConverterRule.INSTANCE);
+    // planner.addRule(DrillTableModificationConverterRule.INSTANCE);
+    // planner.addRule(DrillCalcConverterRule.INSTANCE);
 
     planner.addRule(DrillFilterRule.INSTANCE);
     planner.addRule(DrillProjectRule.INSTANCE);
+    planner.addRule(DrillAggregateRule.INSTANCE);
 
     // Enable when https://issues.apache.org/jira/browse/DRILL-57 fixed
     if (false) planner.addRule(DrillValuesRule.INSTANCE);
-//    planner.addRule(DrillSortRule.INSTANCE);
-//    planner.addRule(DrillJoinRule.INSTANCE);
-//    planner.addRule(DrillUnionRule.INSTANCE);
-//    planner.addRule(AbstractConverter.ExpandConversionRule.instance);
+    planner.addRule(DrillSortRule.INSTANCE);
+    planner.addRule(DrillJoinRule.INSTANCE);
+    planner.addRule(DrillUnionRule.INSTANCE);
+    // planner.addRule(AbstractConverter.ExpandConversionRule.instance);
   }
 
-  /** Converts a tree of {@link RexNode} operators into a scalar expression in
-   * Drill syntax. */
+  /**
+   * Converts a tree of {@link RexNode} operators into a scalar expression in Drill syntax.
+   */
   static String toDrill(RelNode input, RexNode expr) {
     final RexToDrill visitor = new RexToDrill(input);
     expr.accept(visitor);
@@ -70,21 +71,24 @@ public class DrillOptiq {
       switch (syntax) {
       case Binary:
         buf.append("(");
-        call.getOperandList().get(0).accept(this)
-            .append(" ")
-            .append(call.getOperator().getName())
-            .append(" ");
-        return call.getOperandList().get(1).accept(this)
-            .append(")");
+        call.getOperands().get(0).accept(this).append(" ").append(call.getOperator().getName()).append(" ");
+        return call.getOperands().get(1).accept(this).append(")");
+      case Function:
+        buf.append(call.getOperator().getName().toLowerCase()).append("(");
+        for (Ord<RexNode> operand : Ord.zip(call.getOperands())) {
+          buf.append(operand.i > 0 ? ", " : "");
+          operand.e.accept(this);
+        }
+        return buf.append(")");
       case Special:
         switch (call.getKind()) {
         case Cast:
           // Ignore casts. Drill is type-less.
-          return call.getOperandList().get(0).accept(this);
+          return call.getOperands().get(0).accept(this);
         }
         if (call.getOperator() == SqlStdOperatorTable.itemOp) {
-          final RexNode left = call.getOperandList().get(0);
-          final RexLiteral literal = (RexLiteral) call.getOperandList().get(1);
+          final RexNode left = call.getOperands().get(0);
+          final RexLiteral literal = (RexLiteral) call.getOperands().get(1);
           final String field = (String) literal.getValue2();
           final int length = buf.length();
           left.accept(this);
@@ -96,16 +100,14 @@ public class DrillOptiq {
         }
         // fall through
       default:
-        throw new AssertionError("todo: implement syntax " + syntax + "(" + call
-            + ")");
+        throw new AssertionError("todo: implement syntax " + syntax + "(" + call + ")");
       }
     }
 
     @Override
     public StringBuilder visitInputRef(RexInputRef inputRef) {
       final int index = inputRef.getIndex();
-      final RelDataTypeField field =
-          input.getRowType().getFieldList().get(index);
+      final RelDataTypeField field = input.getRowType().getFieldList().get(index);
       return buf.append(field.getName());
     }
 
@@ -115,5 +117,3 @@ public class DrillOptiq {
     }
   }
 }
-
-// End DrillOptiq.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillPrepareImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillPrepareImpl.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillPrepareImpl.java
index 0b1136a..f5dce0a 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillPrepareImpl.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillPrepareImpl.java
@@ -33,7 +33,6 @@ public class DrillPrepareImpl extends OptiqPrepareImpl {
   protected RelOptPlanner createPlanner() {
     final RelOptPlanner planner = super.createPlanner();
     planner.addRule(EnumerableDrillRule.ARRAY_INSTANCE);
-    planner.addRule(EnumerableDrillRule.CUSTOM_INSTANCE);
 
     // Enable when https://issues.apache.org/jira/browse/DRILL-57 fixed
     if (false) {
@@ -43,5 +42,3 @@ public class DrillPrepareImpl extends OptiqPrepareImpl {
     return planner;
   }
 }
-
-// End DrillPrepareImpl.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java
index e3a88a1..e2f1c28 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java
@@ -23,9 +23,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.eigenbase.rel.*;
 import org.eigenbase.relopt.*;
 import org.eigenbase.reltype.RelDataType;
-import org.eigenbase.reltype.RelDataTypeField;
 import org.eigenbase.rex.RexNode;
-import org.eigenbase.sql.type.SqlTypeName;
 import org.eigenbase.util.Pair;
 
 import java.util.*;
@@ -34,17 +32,21 @@ import java.util.*;
  * Project implemented in Drill.
  */
 public class DrillProjectRel extends ProjectRelBase implements DrillRel {
-  protected DrillProjectRel(RelOptCluster cluster, RelTraitSet traits,
-      RelNode child, RexNode[] exps, RelDataType rowType) {
-    super(cluster, traits, child, exps, rowType, Flags.Boxed,
-        Collections.<RelCollation>emptyList());
+  protected DrillProjectRel(RelOptCluster cluster, RelTraitSet traits, RelNode child, List<RexNode> exps,
+      RelDataType rowType) {
+    super(cluster, traits, child, exps, rowType, Flags.Boxed, Collections.<RelCollation> emptyList());
     assert getConvention() == CONVENTION;
   }
 
+  public DrillProjectRel(RelOptCluster cluster, RelTraitSet traits, RelNode child, List<RexNode> exps,
+      RelDataType rowType, int flags, List<RelCollation> collationList) {
+    super(cluster, traits, child, exps, rowType, flags, collationList);
+
+  }
+
   @Override
   public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
-    return new DrillProjectRel(getCluster(), traitSet, sole(inputs),
-        exps.clone(), rowType);
+    return new DrillProjectRel(getCluster(), traitSet, sole(inputs), new ArrayList<RexNode>(exps), rowType);
   }
 
   @Override
@@ -53,36 +55,28 @@ public class DrillProjectRel extends ProjectRelBase implements DrillRel {
   }
 
   private List<Pair<RexNode, String>> projects() {
-    return Pair.zip(
-        Arrays.asList(exps),
-        RelOptUtil.getFieldNameList(getRowType()));
+    return Pair.zip(exps, getRowType().getFieldNames());
   }
 
   @Override
-  public void implement(DrillImplementor implementor) {
-    implementor.visitChild(this, 0, getChild());
-    final ObjectNode node = implementor.mapper.createObjectNode();
-/*
-    E.g. {
-      op: "project",
-	    projections: [
-	      { ref: "output.quantity", expr: "donuts.sales"}
-	    ]
-*/
-    node.put("op", "project");
+  public int implement(DrillImplementor implementor) {
+    int inputId = implementor.visitChild(this, 0, getChild());
+    final ObjectNode project = implementor.mapper.createObjectNode();
+    /*
+     * E.g. { op: "project", projections: [ { ref: "output.quantity", expr: "donuts.sales"} ]
+     */
+    project.put("op", "project");
+    project.put("input", inputId);
     final ArrayNode transforms = implementor.mapper.createArrayNode();
-    node.put("projections", transforms);
-    final String prefix = "output.";
+    project.put("projections", transforms);
     for (Pair<RexNode, String> pair : projects()) {
       final ObjectNode objectNode = implementor.mapper.createObjectNode();
       transforms.add(objectNode);
       String expr = DrillOptiq.toDrill(getChild(), pair.left);
       objectNode.put("expr", expr);
-      String ref = prefix + pair.right;
+      String ref = "output." + pair.right;
       objectNode.put("ref", ref);
     }
-    implementor.add(node);
+    return implementor.add(project);
   }
 }
-
-// End DrillProjectRel.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRule.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRule.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRule.java
index c0e983e..b294ad0 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRule.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRule.java
@@ -17,35 +17,30 @@
  ******************************************************************************/
 package org.apache.drill.optiq;
 
-import org.eigenbase.rel.*;
-import org.eigenbase.relopt.*;
+import org.eigenbase.rel.ProjectRel;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.Convention;
+import org.eigenbase.relopt.RelOptRule;
+import org.eigenbase.relopt.RelOptRuleCall;
+import org.eigenbase.relopt.RelTraitSet;
 
 /**
- * Rule that converts a {@link org.eigenbase.rel.ProjectRel} to a Drill
- * "project" operation.
+ * Rule that converts a {@link org.eigenbase.rel.ProjectRel} to a Drill "project" operation.
  */
 public class DrillProjectRule extends RelOptRule {
   public static final RelOptRule INSTANCE = new DrillProjectRule();
 
   private DrillProjectRule() {
-    super(
-        new RelOptRuleOperand(
-            ProjectRel.class,
-            Convention.NONE,
-            new RelOptRuleOperand(RelNode.class, ANY)),
-        "DrillProjectRule");
+    super(RelOptRule.some(ProjectRel.class, Convention.NONE, RelOptRule.any(RelNode.class)), "DrillProjectRule");
   }
 
   @Override
   public void onMatch(RelOptRuleCall call) {
-    final ProjectRel project = (ProjectRel) call.getRels()[0];
-    final RelNode input = call.getRels()[1];
+    final ProjectRel project = (ProjectRel) call.rel(0);
+    final RelNode input = call.rel(1);
     final RelTraitSet traits = project.getTraitSet().plus(DrillRel.CONVENTION);
     final RelNode convertedInput = convert(input, traits);
-    call.transformTo(
-        new DrillProjectRel(project.getCluster(), traits, convertedInput,
-            project.getProjectExps(), project.getRowType()));
+    call.transformTo(new DrillProjectRel(project.getCluster(), traits, convertedInput, project.getProjects(), project
+        .getRowType()));
   }
 }
-
-// End DrillProjectRule.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java
index b6dae18..aa6d3e0 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java
@@ -28,7 +28,5 @@ public interface DrillRel extends RelNode {
    * generating Drill logical plans. */
   Convention CONVENTION = new Convention.Impl("DRILL", DrillRel.class);
 
-  void implement(DrillImplementor implementor);
+  int implement(DrillImplementor implementor);
 }
-
-// End DrillRel.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java
index 11897d5..ab622b1 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java
@@ -17,10 +17,7 @@ public class DrillScan extends TableAccessRelBase implements DrillRel {
   private final DrillTable drillTable;
 
   /** Creates a DrillScan. */
-  public DrillScan(RelOptCluster cluster,
-      RelTraitSet traits,
-      RelOptTable table)
-  {
+  public DrillScan(RelOptCluster cluster, RelTraitSet traits, RelOptTable table) {
     super(cluster, traits, table);
     assert getConvention() == CONVENTION;
     this.drillTable = table.unwrap(DrillTable.class);
@@ -33,15 +30,13 @@ public class DrillScan extends TableAccessRelBase implements DrillRel {
     DrillOptiq.registerStandardPlannerRules(planner);
   }
 
-  public void implement(DrillImplementor implementor) {
+  public int implement(DrillImplementor implementor) {
     final ObjectNode node = implementor.mapper.createObjectNode();
     node.put("op", "scan");
     node.put("memo", "initial_scan");
     node.put("ref", "_MAP"); // output is a record with a single field, '_MAP'
     node.put("storageengine", drillTable.getStorageEngineName());
     node.put("selection", implementor.mapper.convertValue(drillTable.selection, JsonNode.class));
-    implementor.add(node);
+    return implementor.add(node);
   }
 }
-
-// End DrillScan.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillSortRel.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillSortRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillSortRel.java
new file mode 100644
index 0000000..64995c5
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillSortRel.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.drill.optiq;
+
+import java.util.List;
+
+import net.hydromatic.linq4j.Ord;
+
+import org.eigenbase.rel.RelCollation;
+import org.eigenbase.rel.RelFieldCollation;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.rel.SortRel;
+import org.eigenbase.relopt.RelOptCluster;
+import org.eigenbase.relopt.RelTraitSet;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Sort implemented in Drill.
+ */
+public class DrillSortRel extends SortRel implements DrillRel {
+  /** Creates a DrillSortRel. */
+  public DrillSortRel(RelOptCluster cluster, RelTraitSet traits, RelNode input, RelCollation collation) {
+    super(cluster, traits, input, collation);
+  }
+
+  @Override
+  public DrillSortRel copy(RelTraitSet traitSet, RelNode input, RelCollation collation) {
+    return new DrillSortRel(getCluster(), traitSet, input, collation);
+  }
+
+  @Override
+  public int implement(DrillImplementor implementor) {
+    int inputId = implementor.visitChild(this, 0, getChild());
+    final List<String> childFields = getChild().getRowType().getFieldNames();
+    /*
+     * E.g. { op: "order", input: 4, ordering: [ {order: "asc", expr: "deptId"} ] }
+     */
+    final ObjectNode order = implementor.mapper.createObjectNode();
+    order.put("op", "order");
+    order.put("input", inputId);
+    final ArrayNode orderings = implementor.mapper.createArrayNode();
+    order.put("orderings", orderings);
+    for (Ord<RelFieldCollation> fieldCollation : Ord.zip(this.collation.getFieldCollations())) {
+      final ObjectNode ordering = implementor.mapper.createObjectNode();
+      ordering.put("order", toDrill(fieldCollation.e));
+      ordering.put("expr", childFields.get(fieldCollation.e.getFieldIndex()));
+      switch (fieldCollation.e.nullDirection) {
+      case FIRST:
+        ordering.put("nullCollation", "first");
+        break;
+      default:
+        ordering.put("nullCollation", "last");
+        break;
+      }
+      orderings.add(ordering);
+    }
+
+    return implementor.add(order);
+  }
+
+  private static String toDrill(RelFieldCollation collation) {
+    switch (collation.getDirection()) {
+    case Ascending:
+      return "asc";
+    case Descending:
+      return "desc";
+    default:
+      throw new AssertionError(collation.getDirection());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillSortRule.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillSortRule.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillSortRule.java
new file mode 100644
index 0000000..469d8bb
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillSortRule.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * 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.drill.optiq;
+
+import org.eigenbase.rel.SortRel;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.*;
+
+/**
+ * Rule that converts an {@link SortRel} to a {@link DrillSortRel}, implemented by a Drill "order" operation.
+ */
+public class DrillSortRule extends RelOptRule {
+  public static final RelOptRule INSTANCE = new DrillSortRule();
+
+  private DrillSortRule() {
+    super(RelOptRule.some(SortRel.class, Convention.NONE, RelOptRule.any(RelNode.class)), "DrillSortRule");
+  }
+
+  @Override
+  public void onMatch(RelOptRuleCall call) {
+    final SortRel sort = (SortRel) call.rel(0);
+    final RelNode input = call.rel(1);
+    final RelTraitSet traits = sort.getTraitSet().plus(DrillRel.CONVENTION);
+    final RelNode convertedInput = convert(input, traits);
+    call.transformTo(new DrillSortRel(sort.getCluster(), traits, convertedInput, sort.getCollation()));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillUnionRel.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillUnionRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillUnionRel.java
new file mode 100644
index 0000000..e8b35a6
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillUnionRel.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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.drill.optiq;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import net.hydromatic.linq4j.Ord;
+import org.eigenbase.rel.UnionRelBase;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.RelOptCluster;
+import org.eigenbase.relopt.RelTraitSet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Union implemented in Drill.
+ */
+public class DrillUnionRel extends UnionRelBase implements DrillRel {
+  /** Creates a DrillUnionRel. */
+  public DrillUnionRel(RelOptCluster cluster, RelTraitSet traits,
+      List<RelNode> inputs, boolean all) {
+    super(cluster, traits, inputs, all);
+  }
+
+  @Override
+  public DrillUnionRel copy(RelTraitSet traitSet, List<RelNode> inputs,
+      boolean all) {
+    return new DrillUnionRel(getCluster(), traitSet, inputs, all);
+  }
+
+  @Override
+  public int implement(DrillImplementor implementor) {
+    List<Integer> inputIds = new ArrayList<>();
+    for (Ord<RelNode> input : Ord.zip(inputs)) {
+      inputIds.add(implementor.visitChild(this, input.i, input.e));
+    }
+/*
+    E.g. {
+      op: "union",
+      distinct: true,
+	    inputs: [2, 4]
+	  }
+*/
+    final ObjectNode union = implementor.mapper.createObjectNode();
+    union.put("op", "union");
+    union.put("distinct", !all);
+    final ArrayNode inputs = implementor.mapper.createArrayNode();
+    union.put("inputs", inputs);
+    for (Integer inputId : inputIds) {
+      inputs.add(inputId);
+    }
+    return implementor.add(union);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillUnionRule.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillUnionRule.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillUnionRule.java
new file mode 100644
index 0000000..f65b276
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillUnionRule.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.drill.optiq;
+
+import org.eigenbase.rel.UnionRel;
+import org.eigenbase.rel.RelNode;
+import org.eigenbase.relopt.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Rule that converts a {@link UnionRel} to a {@link DrillUnionRel}, implemented by a "union" operation.
+ */
+public class DrillUnionRule extends RelOptRule {
+  public static final RelOptRule INSTANCE = new DrillUnionRule();
+
+  private DrillUnionRule() {
+    super(RelOptRule.any(UnionRel.class, Convention.NONE), "DrillUnionRule");
+  }
+
+  @Override
+  public void onMatch(RelOptRuleCall call) {
+    final UnionRel union = (UnionRel) call.rel(0);
+    final RelTraitSet traits = union.getTraitSet().plus(DrillRel.CONVENTION);
+    final List<RelNode> convertedInputs = new ArrayList<>();
+    for (RelNode input : union.getInputs()) {
+      final RelNode convertedInput = convert(input, traits);
+      convertedInputs.add(convertedInput);
+    }
+    call.transformTo(new DrillUnionRel(union.getCluster(), traits, convertedInputs, union.all));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRel.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRel.java
index eb9fc72..b8a723a 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRel.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRel.java
@@ -29,10 +29,7 @@ import java.util.List;
  * Values implemented in Drill.
  */
 public class DrillValuesRel extends ValuesRelBase implements DrillRel {
-  protected DrillValuesRel(RelOptCluster cluster,
-      RelDataType rowType,
-      List<List<RexLiteral>> tuples,
-      RelTraitSet traits) {
+  protected DrillValuesRel(RelOptCluster cluster, RelDataType rowType, List<List<RexLiteral>> tuples, RelTraitSet traits) {
     super(cluster, rowType, tuples, traits);
     assert getConvention() == CONVENTION;
   }
@@ -49,10 +46,8 @@ public class DrillValuesRel extends ValuesRelBase implements DrillRel {
   }
 
   @Override
-  public void implement(DrillImplementor implementor) {
+  public int implement(DrillImplementor implementor) {
     // Update when https://issues.apache.org/jira/browse/DRILL-57 fixed
     throw new UnsupportedOperationException();
   }
 }
-
-// End DrillValuesRel.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRule.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRule.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRule.java
index faa93ee..280dc7f 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRule.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillValuesRule.java
@@ -21,28 +21,19 @@ import org.eigenbase.rel.ValuesRel;
 import org.eigenbase.relopt.*;
 
 /**
- * Rule that converts a {@link ValuesRel} to a Drill
- * "values" operation.
+ * Rule that converts a {@link ValuesRel} to a Drill "values" operation.
  */
 public class DrillValuesRule extends RelOptRule {
   public static final RelOptRule INSTANCE = new DrillValuesRule();
 
   private DrillValuesRule() {
-    super(
-        new RelOptRuleOperand(
-            ValuesRel.class,
-            Convention.NONE),
-        "DrillValuesRule");
+    super(RelOptRule.any(ValuesRel.class, Convention.NONE), "DrillValuesRule");
   }
 
   @Override
   public void onMatch(RelOptRuleCall call) {
-    final ValuesRel values = (ValuesRel) call.getRels()[0];
+    final ValuesRel values = (ValuesRel) call.rel(0);
     final RelTraitSet traits = values.getTraitSet().plus(DrillRel.CONVENTION);
-    call.transformTo(
-        new DrillValuesRel(values.getCluster(), values.getRowType(),
-            values.getTuples(), traits));
+    call.transformTo(new DrillValuesRel(values.getCluster(), values.getRowType(), values.getTuples(), traits));
   }
 }
-
-// End DrillValuesRule.java

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java
new file mode 100644
index 0000000..c522b29
--- /dev/null
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * 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.drill.optiq;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.*;
+
+import net.hydromatic.linq4j.AbstractEnumerable;
+import net.hydromatic.linq4j.Enumerable;
+import net.hydromatic.linq4j.Enumerator;
+
+import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.logical.LogicalPlan;
+import org.apache.drill.exec.ref.IteratorRegistry;
+import org.apache.drill.exec.ref.ReferenceInterpreter;
+import org.apache.drill.exec.ref.RunOutcome;
+import org.apache.drill.exec.ref.eval.BasicEvaluatorFactory;
+import org.apache.drill.exec.ref.rse.RSERegistry;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Runtime helper that executes a Drill query and converts it into an {@link Enumerable}.
+ */
+public class EnumerableDrill<E> extends AbstractEnumerable<E> implements Enumerable<E> {
+  private final LogicalPlan plan;
+  final BlockingQueue<Object> queue = new ArrayBlockingQueue<>(100);
+  final DrillConfig config;
+  private final String holder;
+  private final List<String> fields;
+
+  private static final ObjectMapper mapper = createMapper();
+
+  /**
+   * Creates a DrillEnumerable.
+   * 
+   * @param plan
+   *          Logical plan
+   * @param clazz
+   *          Type of elements returned from enumerable
+   * @param fields
+   *          Names of fields, or null to return the whole blob
+   */
+  public EnumerableDrill(DrillConfig config, LogicalPlan plan, Class<E> clazz, List<String> fields) {
+    this.plan = plan;
+    this.config = config;
+    this.holder = null;
+    this.fields = fields;
+    config.setSinkQueues(0, queue);
+  }
+
+  /**
+   * Creates a DrillEnumerable from a plan represented as a string. Each record returned is a {@link JsonNode}.
+   */
+  public static <E> EnumerableDrill<E> of(String plan, final List<String> fieldNames, Class<E> clazz) {
+    DrillConfig config = DrillConfig.create();
+    final LogicalPlan parse = LogicalPlan.parse(config, plan);
+    return new EnumerableDrill<>(config, parse, clazz, fieldNames);
+  }
+
+  /** Runs the plan as a background task. */
+  Future<Collection<RunOutcome>> runPlan(CompletionService<Collection<RunOutcome>> service) {
+    IteratorRegistry ir = new IteratorRegistry();
+    DrillConfig config = DrillConfig.create();
+    config.setSinkQueues(0, queue);
+    final ReferenceInterpreter i = new ReferenceInterpreter(plan, ir, new BasicEvaluatorFactory(ir), new RSERegistry(
+        config));
+    try {
+      i.setup();
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+    return service.submit(new Callable<Collection<RunOutcome>>() {
+      @Override
+      public Collection<RunOutcome> call() throws Exception {
+        Collection<RunOutcome> outcomes = i.run();
+
+        for (RunOutcome outcome : outcomes) {
+          System.out.println("============");
+          System.out.println(outcome);
+          if (outcome.outcome == RunOutcome.OutcomeType.FAILED && outcome.exception != null) {
+            outcome.exception.printStackTrace();
+          }
+        }
+        return outcomes;
+      }
+    });
+  }
+
+  @Override
+  public Enumerator<E> enumerator() {
+    // TODO: use a completion service from the container
+    final ExecutorCompletionService<Collection<RunOutcome>> service = new ExecutorCompletionService<Collection<RunOutcome>>(
+        new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(10)));
+
+    // Run the plan using an executor. It runs in a different thread, writing
+    // results to our queue.
+    //
+    // TODO: use the result of task, and check for exceptions
+    final Future<Collection<RunOutcome>> task = runPlan(service);
+
+    return new JsonEnumerator(queue, fields);
+  }
+
+  private static ObjectMapper createMapper() {
+    return new ObjectMapper();
+  }
+
+  /**
+   * Converts a JSON document, represented as an array of bytes, into a Java object (consisting of Map, List, String,
+   * Integer, Double, Boolean).
+   */
+  static Object parseJson(byte[] bytes) {
+    try {
+      return wrapper(mapper.readTree(bytes));
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Converts a JSON node to Java objects ({@link List}, {@link Map}, {@link String}, {@link Integer}, {@link Double},
+   * {@link Boolean}.
+   */
+  static Object wrapper(JsonNode node) {
+    switch (node.asToken()) {
+    case START_OBJECT:
+      return map((ObjectNode) node);
+    case START_ARRAY:
+      return array((ArrayNode) node);
+    case VALUE_STRING:
+      return node.asText();
+    case VALUE_NUMBER_INT:
+      return node.asInt();
+    case VALUE_NUMBER_FLOAT:
+      return node.asDouble();
+    case VALUE_TRUE:
+      return Boolean.TRUE;
+    case VALUE_FALSE:
+      return Boolean.FALSE;
+    case VALUE_NULL:
+      return null;
+    default:
+      throw new AssertionError("unexpected: " + node + ": " + node.asToken());
+    }
+  }
+
+  private static List<Object> array(ArrayNode node) {
+    final List<Object> list = new ArrayList<>();
+    for (JsonNode jsonNode : node) {
+      list.add(wrapper(jsonNode));
+    }
+    return Collections.unmodifiableList(list);
+  }
+
+  private static SortedMap<String, Object> map(ObjectNode node) {
+    // TreeMap makes the results deterministic.
+    final TreeMap<String, Object> map = new TreeMap<>();
+    final Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
+    while (fields.hasNext()) {
+      Map.Entry<String, JsonNode> next = fields.next();
+      map.put(next.getKey(), wrapper(next.getValue()));
+    }
+    return Collections.unmodifiableSortedMap(map);
+  }
+
+  private static class JsonEnumerator implements Enumerator {
+    private final BlockingQueue<Object> queue;
+    private final String holder;
+    private final List<String> fields;
+    private Object current;
+
+    public JsonEnumerator(BlockingQueue<Object> queue, List<String> fields) {
+      this.queue = queue;
+      this.holder = null;
+      this.fields = fields;
+    }
+
+    public Object current() {
+      return current;
+    }
+
+    public void close() {
+
+    }
+
+    public boolean moveNext() {
+      try {
+        Object o = queue.take();
+        if (o instanceof RunOutcome.OutcomeType) {
+          switch ((RunOutcome.OutcomeType) o) {
+          case SUCCESS:
+            return false; // end of data
+          case CANCELED:
+            throw new RuntimeException("canceled");
+          case FAILED:
+          default:
+            throw new RuntimeException("failed");
+          }
+        } else {
+          Object o1 = parseJson((byte[]) o);
+          if (holder != null) {
+            o1 = ((Map<String, Object>) o1).get(holder);
+          }
+          if (fields == null) {
+            current = o1;
+          } else {
+            final Map<String, Object> map = (Map<String, Object>) o1;
+            if (fields.size() == 1) {
+              current = map.get(fields.get(0));
+            } else {
+              Object[] os = new Object[fields.size()];
+              for (int i = 0; i < os.length; i++) {
+                os[i] = map.get(fields.get(i));
+              }
+              current = os;
+            }
+          }
+          return true;
+        }
+      } catch (InterruptedException e) {
+        Thread.interrupted();
+        throw new RuntimeException(e);
+      }
+    }
+
+    public void reset() {
+      throw new UnsupportedOperationException();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/d405c70d/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillFullEngine.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillFullEngine.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillFullEngine.java
index 8c41b99..7cd1082 100644
--- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillFullEngine.java
+++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillFullEngine.java
@@ -53,7 +53,8 @@ public class EnumerableDrillFullEngine<E> extends AbstractEnumerable<E> implemen
    * @param fields
    *          Names of fields, or null to return the whole blob
    */
-  public EnumerableDrillFullEngine(DrillConfig config, String plan, Class<E> clazz, List<String> fields, DataContext drillConnectionDataContext) {
+  public EnumerableDrillFullEngine(DrillConfig config, String plan, Class<E> clazz, List<String> fields,
+      DataContext drillConnectionDataContext) {
     this.plan = plan;
     this.config = config;
     this.fields = fields;
@@ -73,7 +74,7 @@ public class EnumerableDrillFullEngine<E> extends AbstractEnumerable<E> implemen
   @Override
   public Enumerator<E> enumerator() {
     DrillTable table = (DrillTable) drillConnectionDataContext.getSubSchema("DONUTS").getTable("DONUTS", Object.class);
-    if(table.useReferenceInterpreter()){
+    if (table.useReferenceInterpreter()) {
       DrillRefImpl<E> impl = new DrillRefImpl<E>(plan, config, fields, queue);
       return impl.enumerator(table);
     } else {