You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@drill.apache.org by GitBox <gi...@apache.org> on 2018/07/04 10:39:36 UTC

[GitHub] arina-ielchiieva closed pull request #1346: DRILL-6546: Allow unnest function with nested columns and complex expressions

arina-ielchiieva closed pull request #1346: DRILL-6546: Allow unnest function with nested columns and complex expressions
URL: https://github.com/apache/drill/pull/1346
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java
index 519d5036e7..e5a3746a42 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java
@@ -37,6 +37,7 @@
 import org.apache.drill.exec.planner.logical.DrillJoinRule;
 import org.apache.drill.exec.planner.logical.DrillLimitRule;
 import org.apache.drill.exec.planner.logical.DrillMergeProjectRule;
+import org.apache.drill.exec.planner.logical.ProjectComplexRexNodeCorrelateTransposeRule;
 import org.apache.drill.exec.planner.logical.DrillProjectLateralJoinTransposeRule;
 import org.apache.drill.exec.planner.logical.DrillProjectPushIntoLateralJoinRule;
 import org.apache.drill.exec.planner.logical.DrillProjectRule;
@@ -311,6 +312,8 @@ static RuleSet getDrillUserConfigurableLogicalRules(OptimizerRulesContext optimi
       RuleInstance.PROJECT_WINDOW_TRANSPOSE_RULE,
       DrillPushProjectIntoScanRule.INSTANCE,
 
+      ProjectComplexRexNodeCorrelateTransposeRule.INSTANCE,
+
       /*
        Convert from Calcite Logical to Drill Logical Rules.
        */
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillLateralJoinRelBase.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillLateralJoinRelBase.java
index 28e5246b0e..2f895e2cd6 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillLateralJoinRelBase.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillLateralJoinRelBase.java
@@ -73,7 +73,7 @@ protected RelDataType deriveRowType() {
         return constructRowType(SqlValidatorUtil.deriveJoinRowType(left.getRowType(),
           right.getRowType(), joinType.toJoinType(),
           getCluster().getTypeFactory(), null,
-          ImmutableList.<RelDataTypeField>of()));
+          ImmutableList.of()));
       case ANTI:
       case SEMI:
         return constructRowType(left.getRowType());
@@ -82,12 +82,19 @@ protected RelDataType deriveRowType() {
     }
   }
 
-  public int getInputSize(int offset, RelNode input) {
-    if (this.excludeCorrelateColumn &&
-      offset == 0) {
-      return input.getRowType().getFieldList().size() - 1;
+  /**
+   * Returns number of fields in {@link RelDataType} for
+   * input rel node with specified ordinal considering value of
+   * {@code excludeCorrelateColumn}.
+   *
+   * @param ordinal ordinal of input rel node
+   * @return number of fields in input's {@link RelDataType}
+   */
+  public int getInputSize(int ordinal) {
+    if (this.excludeCorrelateColumn && ordinal == 0) {
+      return getInput(ordinal).getRowType().getFieldList().size() - 1;
     }
-    return input.getRowType().getFieldList().size();
+    return getInput(ordinal).getRowType().getFieldList().size();
   }
 
   public RelDataType constructRowType(RelDataType inputRowType) {
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillLateralJoinRel.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillLateralJoinRel.java
index aa6ccb051b..4356d49104 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillLateralJoinRel.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillLateralJoinRel.java
@@ -50,7 +50,7 @@ public Correlate copy(RelTraitSet traitSet,
   public LogicalOperator implement(DrillImplementor implementor) {
     final List<String> fields = getRowType().getFieldNames();
     assert DrillJoinRel.isUnique(fields);
-    final int leftCount = getInputSize(0,left);
+    final int leftCount = getInputSize(0);
 
     final LogicalOperator leftOp = DrillJoinRel.implementInput(implementor, 0, 0, left, this);
     final LogicalOperator rightOp = DrillJoinRel.implementInput(implementor, 1, leftCount, right, this);
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillUnnestRule.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillUnnestRule.java
index 762eb46f31..ce0cd3c1aa 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillUnnestRule.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillUnnestRule.java
@@ -24,6 +24,8 @@
 import org.apache.calcite.rel.core.Uncollect;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.logical.LogicalValues;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.sql.SqlKind;
 
 public class DrillUnnestRule extends RelOptRule {
   public static final RelOptRule INSTANCE = new DrillUnnestRule();
@@ -38,11 +40,14 @@ private DrillUnnestRule() {
   public void onMatch(RelOptRuleCall call) {
     final Uncollect uncollect = call.rel(0);
     final LogicalProject project = call.rel(1);
-    final LogicalValues values = call.rel(2);
 
+    RexNode projectedNode = project.getProjects().iterator().next();
+    if (projectedNode.getKind() != SqlKind.FIELD_ACCESS) {
+      return;
+    }
     final RelTraitSet traits = uncollect.getTraitSet().plus(DrillRel.DRILL_LOGICAL);
-    DrillUnnestRel unnest = new DrillUnnestRel(uncollect.getCluster(), traits, uncollect.getRowType(),
-        project.getProjects().iterator().next());
+    DrillUnnestRel unnest = new DrillUnnestRel(uncollect.getCluster(),
+        traits, uncollect.getRowType(), projectedNode);
     call.transformTo(unnest);
   }
 }
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/ProjectComplexRexNodeCorrelateTransposeRule.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/ProjectComplexRexNodeCorrelateTransposeRule.java
new file mode 100644
index 0000000000..a979d5be05
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/ProjectComplexRexNodeCorrelateTransposeRule.java
@@ -0,0 +1,154 @@
+/*
+ * 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.exec.planner.logical;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Correlate;
+import org.apache.calcite.rel.core.CorrelationId;
+import org.apache.calcite.rel.core.Uncollect;
+import org.apache.calcite.rel.logical.LogicalCorrelate;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexCorrelVariable;
+import org.apache.calcite.rex.RexFieldAccess;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.trace.CalciteTrace;
+import org.apache.drill.common.exceptions.UserException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Rule that moves non-{@link RexFieldAccess} rex node from project below {@link Uncollect}
+ * to the left side of the {@link Correlate}.
+ */
+public class ProjectComplexRexNodeCorrelateTransposeRule extends RelOptRule {
+
+  public static final RelOptRule INSTANCE = new ProjectComplexRexNodeCorrelateTransposeRule();
+
+  public ProjectComplexRexNodeCorrelateTransposeRule() {
+    super(operand(LogicalCorrelate.class,
+        operand(RelNode.class, any()),
+        operand(Uncollect.class, operand(LogicalProject.class, any()))),
+        DrillRelFactories.LOGICAL_BUILDER,
+        "ProjectComplexRexNodeCorrelateTransposeRule");
+  }
+
+  @Override
+  public void onMatch(RelOptRuleCall call) {
+    final Correlate correlate = call.rel(0);
+    final Uncollect uncollect = call.rel(2);
+    final LogicalProject project = call.rel(3);
+
+    // uncollect requires project with single expression
+    RexNode projectedNode = project.getProjects().iterator().next();
+
+    // check that the expression is complex call
+    if (!(projectedNode instanceof RexFieldAccess)) {
+      RelBuilder builder = call.builder();
+      RexBuilder rexBuilder = builder.getRexBuilder();
+
+      builder.push(correlate.getLeft());
+
+      // creates project with complex expr on top of the left side
+      List<RexNode> leftProjExprs = new ArrayList<>();
+
+      String complexFieldName = correlate.getRowType().getFieldNames()
+            .get(correlate.getRowType().getFieldNames().size() - 1);
+
+      List<String> fieldNames = new ArrayList<>();
+      for (RelDataTypeField field : correlate.getLeft().getRowType().getFieldList()) {
+        leftProjExprs.add(rexBuilder.makeInputRef(correlate.getLeft(), field.getIndex()));
+        fieldNames.add(field.getName());
+      }
+      fieldNames.add(complexFieldName);
+      List<RexNode> topProjectExpressions = new ArrayList<>(leftProjExprs);
+
+      // adds complex expression with replaced correlation
+      // to the projected list from the left
+      leftProjExprs.add(projectedNode.accept(new RexFieldAccessReplacer(builder)));
+
+      RelNode leftProject = builder.project(leftProjExprs, fieldNames)
+          .build();
+
+      CorrelationId correlationId = correlate.getCluster().createCorrel();
+      RexCorrelVariable rexCorrel =
+          (RexCorrelVariable) rexBuilder.makeCorrel(
+              leftProject.getRowType(),
+              correlationId);
+      builder.push(project.getInput());
+      RelNode rightProject = builder.project(
+              ImmutableList.of(rexBuilder.makeFieldAccess(rexCorrel, leftProjExprs.size() - 1)),
+              ImmutableList.of(complexFieldName))
+          .build();
+
+      int requiredColumnsCount = correlate.getRequiredColumns().cardinality();
+      if (requiredColumnsCount != 1) {
+        throw UserException.planError()
+            .message("Required columns count for Correlate operator " +
+                "differs from the expected value:\n" +
+                "Expected columns count is %s, but actual is %s",
+                1, requiredColumnsCount)
+            .build(CalciteTrace.getPlannerTracer());
+      }
+
+      RelNode newUncollect = uncollect.copy(uncollect.getTraitSet(), rightProject);
+      Correlate newCorrelate = correlate.copy(uncollect.getTraitSet(), leftProject, newUncollect,
+          correlationId, ImmutableBitSet.of(leftProjExprs.size() - 1), correlate.getJoinType());
+      builder.push(newCorrelate);
+
+      switch(correlate.getJoinType()) {
+        case LEFT:
+        case INNER:
+          // adds field from the right input of correlate to the top project
+          topProjectExpressions.add(
+              rexBuilder.makeInputRef(newCorrelate, topProjectExpressions.size() + 1));
+          // fall through
+        case ANTI:
+        case SEMI:
+          builder.project(topProjectExpressions, correlate.getRowType().getFieldNames());
+      }
+
+      call.transformTo(builder.build());
+    }
+  }
+
+  /**
+   * Visitor for RexNode which replaces {@link RexFieldAccess}
+   * with a reference to the field used in {@link RexFieldAccess}.
+   */
+  private static class RexFieldAccessReplacer extends RexShuttle {
+    private final RelBuilder builder;
+
+    public RexFieldAccessReplacer(RelBuilder builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public RexNode visitFieldAccess(RexFieldAccess fieldAccess) {
+      return builder.field(fieldAccess.getField().getName());
+    }
+  }
+}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/LateralJoinPrel.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/LateralJoinPrel.java
index b55076bd02..b10eff000d 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/LateralJoinPrel.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/LateralJoinPrel.java
@@ -88,11 +88,12 @@ private SchemaPath getColumn() {
    * Check to make sure that the fields of the inputs are the same as the output field names.
    * If not, insert a project renaming them.
    */
-  public RelNode getLateralInput(int offset, RelNode input) {
+  public RelNode getLateralInput(int ordinal, RelNode input) {
+    int offset = ordinal == 0 ? 0 : getInputSize(0);
     Preconditions.checkArgument(DrillJoinRelBase.uniqueFieldNames(input.getRowType()));
     final List<String> fields = getRowType().getFieldNames();
     final List<String> inputFields = input.getRowType().getFieldNames();
-    final List<String> outputFields = fields.subList(offset, offset + getInputSize(offset, input));
+    final List<String> outputFields = fields.subList(offset, offset + getInputSize(ordinal));
     if (ListUtils.subtract(outputFields, inputFields).size() != 0) {
       // 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
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/UnnestPrule.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/UnnestPrule.java
index 48f4ea964e..544a628d4d 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/UnnestPrule.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/UnnestPrule.java
@@ -19,7 +19,6 @@
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rex.RexFieldAccess;
 import org.apache.calcite.rex.RexNode;
 import org.apache.drill.exec.planner.logical.DrillUnnestRel;
 import org.apache.drill.exec.planner.logical.RelOptHelper;
@@ -34,10 +33,6 @@ private UnnestPrule() {
   public void onMatch(RelOptRuleCall call) {
     final DrillUnnestRel unnest = call.rel(0);
     RexNode ref = unnest.getRef();
-    if (ref instanceof RexFieldAccess) {
-      final RexFieldAccess field = (RexFieldAccess)ref;
-      field.getField().getName();
-    }
 
     UnnestPrel unnestPrel = new UnnestPrel(unnest.getCluster(),
         unnest.getTraitSet().plus(Prel.DRILL_PHYSICAL), unnest.getRowType(), ref);
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/JoinPrelRenameVisitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/JoinPrelRenameVisitor.java
index 850f0bdf08..3a2529b2ff 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/JoinPrelRenameVisitor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/JoinPrelRenameVisitor.java
@@ -17,6 +17,7 @@
  */
 package org.apache.drill.exec.planner.physical.visitor;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.drill.exec.planner.physical.JoinPrel;
@@ -75,16 +76,11 @@ public Prel visitJoin(JoinPrel prel, Void value) throws RuntimeException {
   public Prel visitLateral(LateralJoinPrel prel, Void value) throws RuntimeException {
 
     List<RelNode> children = getChildren(prel);
+    List<RelNode> reNamedChildren = new ArrayList<>();
 
-    final int leftCount = prel.getInputSize(0,children.get(0));
-
-    List<RelNode> reNamedChildren = Lists.newArrayList();
-
-    RelNode left = prel.getLateralInput(0, children.get(0));
-    RelNode right = prel.getLateralInput(leftCount, children.get(1));
-
-    reNamedChildren.add(left);
-    reNamedChildren.add(right);
+    for (int i = 0; i < children.size(); i++) {
+      reNamedChildren.add(prel.getLateralInput(i, children.get(i)));
+    }
 
     return preparePrel(prel, reNamedChildren);
   }
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/CompoundIdentifierConverter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/CompoundIdentifierConverter.java
index 4d0f34c089..ded85c53e6 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/CompoundIdentifierConverter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/CompoundIdentifierConverter.java
@@ -23,6 +23,7 @@
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlJoin;
+import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOrderBy;
 import org.apache.calcite.sql.SqlSelect;
@@ -31,30 +32,68 @@
 import org.apache.calcite.sql.util.SqlVisitor;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
 
 /**
- * Implementation of {@link SqlVisitor} that converts bracketed compound {@link SqlIdentifier} to bracket-less compound
- * {@link SqlIdentifier} (also known as {@link DrillCompoundIdentifier}) to provide ease of use while querying complex
- * types.
+ * Implementation of {@link SqlVisitor} that converts bracketed compound {@link SqlIdentifier}
+ * to bracket-less compound {@link SqlIdentifier} (also known as {@link DrillCompoundIdentifier})
+ * to provide ease of use while querying complex types.
  * <p/>
  * For example, this visitor converts {@code a['b'][4]['c']} to {@code a.b[4].c}
  */
 public class CompoundIdentifierConverter extends SqlShuttle {
-//  private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CompoundIdentifierConverter.class);
+  /**
+   * This map stores the rules that instruct each SqlCall class which data field needs
+   * to be rewritten if that data field is a {@link DrillCompoundIdentifier}.
+   * <p/>
+   * <ul>
+   * <li>Key  : Each rule corresponds to a {@link SqlCall} class;
+   * <li>Value: It is an array of {@link RewriteType}, each being associated with a data field
+   * in that class.
+   * </ul>
+   * <p/>
+   * For example, there are four data fields (query, orderList, offset, fetch)
+   * in {@link SqlOrderBy}. Since only orderList needs to be written,
+   * {@link RewriteType[]} should be {@code arrayOf(D, E, D, D)}.
+   */
+  private static final Map<Class<? extends SqlCall>, RewriteType[]> REWRITE_RULES;
+
+  static {
+    final RewriteType E = RewriteType.ENABLE;
+    final RewriteType D = RewriteType.DISABLE;
+
+    // Every element of the array corresponds to the item in the list
+    // returned by getOperandList() method for concrete SqlCall implementation.
+    REWRITE_RULES = ImmutableMap.<Class<? extends SqlCall>, RewriteType[]>builder()
+        .put(SqlSelect.class, arrayOf(D, E, D, E, E, E, E, E, D, D))
+        .put(SqlCreateTable.class, arrayOf(D, D, D, E, D, D))
+        .put(SqlCreateView.class, arrayOf(D, E, E, D))
+        .put(DrillSqlDescribeTable.class, arrayOf(D, D, E))
+        .put(SqlDropView.class, arrayOf(D, D))
+        .put(SqlShowFiles.class, arrayOf(D))
+        .put(SqlShowSchemas.class, arrayOf(D, D))
+        .put(SqlUseSchema.class, arrayOf(D))
+        .put(SqlJoin.class, arrayOf(D, D, D, D, D, E))
+        .put(SqlOrderBy.class, arrayOf(D, E, D, D))
+        .put(SqlDropTable.class, arrayOf(D, D))
+        .put(SqlRefreshMetadata.class, arrayOf(D))
+        .put(SqlSetOption.class, arrayOf(D, D, D))
+        .put(SqlCreateFunction.class, arrayOf(D))
+        .put(SqlDropFunction.class, arrayOf(D))
+        .build();
+  }
 
   private boolean enableComplex = true;
 
   @Override
   public SqlNode visit(SqlIdentifier id) {
-    if(id instanceof DrillCompoundIdentifier){
-      if(enableComplex){
-        return ((DrillCompoundIdentifier) id).getAsSqlNode();
-      }else{
-        return ((DrillCompoundIdentifier) id).getAsCompoundIdentifier();
+    if (id instanceof DrillCompoundIdentifier) {
+      DrillCompoundIdentifier compoundIdentifier = (DrillCompoundIdentifier) id;
+      if (enableComplex) {
+        return compoundIdentifier.getAsSqlNode();
+      } else {
+        return compoundIdentifier.getAsCompoundIdentifier();
       }
-
-    }else{
+    } else {
       return id;
     }
   }
@@ -64,22 +103,46 @@ public SqlNode visit(final SqlCall call) {
     // Handler creates a new copy of 'call' only if one or more operands
     // change.
     ArgHandler<SqlNode> argHandler = new ComplexExpressionAware(call);
+    boolean localEnableComplex = enableComplex;
+    // for the case of UNNEST call set enableComplex to true
+    // to convert DrillCompoundIdentifier to the item call.
+    if (call.getKind() == SqlKind.UNNEST) {
+      enableComplex = true;
+    }
     call.getOperator().acceptCall(this, call, false, argHandler);
+    enableComplex = localEnableComplex;
     return argHandler.result();
   }
 
+  /**
+   * Constructs array which contains specified parameters.
+   */
+  private static RewriteType[] arrayOf(RewriteType... types) {
+    return types;
+  }
+
+  enum RewriteType {
+    UNCHANGED, DISABLE, ENABLE
+  }
+
+  /**
+   * Argument handler which accepts {@link CompoundIdentifierConverter}
+   * for every operand of {@link SqlCall} and constructs new {@link SqlCall}
+   * if one or more operands changed.
+   */
+  private class ComplexExpressionAware implements ArgHandler<SqlNode> {
 
-  private class ComplexExpressionAware implements ArgHandler<SqlNode>  {
-    boolean update;
-    SqlNode[] clonedOperands;
-    RewriteType[] rewriteTypes;
     private final SqlCall call;
+    private final SqlNode[] clonedOperands;
+    private final RewriteType[] rewriteTypes;
+
+    private boolean update;
 
     public ComplexExpressionAware(SqlCall call) {
       this.call = call;
       this.update = false;
       final List<SqlNode> operands = call.getOperandList();
-      this.clonedOperands = operands.toArray(new SqlNode[operands.size()]);
+      this.clonedOperands = operands.toArray(new SqlNode[0]);
       rewriteTypes = REWRITE_RULES.get(call.getClass());
     }
 
@@ -106,13 +169,13 @@ public SqlNode visitChild(
       }
 
       boolean localEnableComplex = enableComplex;
-      if(rewriteTypes != null){
-        switch(rewriteTypes[i]){
-        case DISABLE:
-          enableComplex = false;
-          break;
-        case ENABLE:
-          enableComplex = true;
+      if (rewriteTypes != null) {
+        switch (rewriteTypes[i]) {
+          case DISABLE:
+            enableComplex = false;
+            break;
+          case ENABLE:
+            enableComplex = true;
         }
       }
       SqlNode newOperand = operand.accept(CompoundIdentifierConverter.this);
@@ -124,64 +187,4 @@ public SqlNode visitChild(
       return newOperand;
     }
   }
-
-  static final Map<Class<? extends SqlCall>, RewriteType[]> REWRITE_RULES;
-
-  enum RewriteType {
-    UNCHANGED, DISABLE, ENABLE;
-  }
-
-  static {
-    final RewriteType E =RewriteType.ENABLE;
-    final RewriteType D =RewriteType.DISABLE;
-    final RewriteType U =RewriteType.UNCHANGED;
-
-    /*
-    This map stores the rules that instruct each SqlCall class which data field needs
-    to be rewritten if that data field is a CompoundIdentifier
-
-    Key  : Each rule corresponds to a SqlCall class;
-    value: It is an array of RewriteType, each being associated with a data field
-           in that class.
-
-           For example, there are four data fields (query, orderList, offset, fetch)
-           in org.eigenbase.sql.SqlOrderBy. Since only orderList needs to be written,
-           RewriteType[] should be R(D, E, D, D).
-    */
-    Map<Class<? extends SqlCall>, RewriteType[]> rules = Maps.newHashMap();
-
-  //SqlNodeList keywordList,
-  //SqlNodeList selectList,
-  //SqlNode fromClause,
-  //SqlNode whereClause,
-  //SqlNodeList groupBy,
-  //SqlNode having,
-  //SqlNodeList windowDecls,
-  //SqlNodeList orderBy,
-  //SqlNode offset,
-  //SqlNode fetch,
-    rules.put(SqlSelect.class, R(D, E, D, E, E, E, E, E, D, D));
-    rules.put(SqlCreateTable.class, R(D, D, D, E, D, D));
-    rules.put(SqlCreateView.class, R(D, E, E, D));
-    rules.put(DrillSqlDescribeTable.class, R(D, D, E));
-    rules.put(SqlDropView.class, R(D, D));
-    rules.put(SqlShowFiles.class, R(D));
-    rules.put(SqlShowSchemas.class, R(D, D));
-    rules.put(SqlUseSchema.class, R(D));
-    rules.put(SqlJoin.class, R(D, D, D, D, D, E));
-    rules.put(SqlOrderBy.class, R(D, E, D, D));
-    rules.put(SqlDropTable.class, R(D, D));
-    rules.put(SqlRefreshMetadata.class, R(D));
-    rules.put(SqlSetOption.class, R(D, D, D));
-    rules.put(SqlCreateFunction.class, R(D));
-    rules.put(SqlDropFunction.class, R(D));
-    REWRITE_RULES = ImmutableMap.copyOf(rules);
-  }
-
-  // Each type in the input arguments refers to
-  // each data field in the class
-  private static RewriteType[] R(RewriteType... types){
-    return types;
-  }
-
 }
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/lateraljoin/TestE2EUnnestAndLateral.java b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/lateraljoin/TestE2EUnnestAndLateral.java
index 6bf3f9af08..98f051e470 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/lateraljoin/TestE2EUnnestAndLateral.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/lateraljoin/TestE2EUnnestAndLateral.java
@@ -21,6 +21,7 @@
 import org.apache.drill.exec.planner.physical.PlannerSettings;
 import org.apache.drill.test.ClusterFixture;
 import org.apache.drill.test.ClusterTest;
+import org.apache.drill.test.TestBuilder;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -166,6 +167,93 @@ public void testMultiUnnestAtSameLevel() throws Exception {
     test(Sql);
   }
 
+  @Test
+  public void testUnnestWithItem() throws Exception {
+    String sql = "select u.item from\n" +
+        "cp.`lateraljoin/nested-customer.parquet` c," +
+        "unnest(c.orders['items']) as u(item)\n" +
+        "limit 1";
+
+    testBuilder()
+        .sqlQuery(sql)
+        .unOrdered()
+        .baselineColumns("item")
+        .baselineValues(
+            TestBuilder.mapOf("i_name", "paper towel",
+                "i_number", 2.0,
+                "i_supplier", "oregan"))
+        .go();
+  }
+
+  @Test
+  public void testUnnestWithFunctionCall() throws Exception {
+    String sql = "select u.ord.o_amount o_amount from\n" +
+        "cp.`lateraljoin/nested-customer.parquet` c," +
+        "unnest(convert_fromjson(convert_tojson(c.orders))) as u(ord)\n" +
+        "limit 1";
+
+    testBuilder()
+        .sqlQuery(sql)
+        .unOrdered()
+        .baselineColumns("o_amount")
+        .baselineValues(4.5)
+        .go();
+  }
+
+  @Test
+  public void testUnnestWithMap() throws Exception {
+    String sql = "select u.item from\n" +
+        "cp.`lateraljoin/nested-customer.parquet` c," +
+        "unnest(c.orders.items) as u(item)\n" +
+        "limit 1";
+
+    testBuilder()
+        .sqlQuery(sql)
+        .unOrdered()
+        .baselineColumns("item")
+        .baselineValues(
+            TestBuilder.mapOf("i_name", "paper towel",
+                "i_number", 2.0,
+                "i_supplier", "oregan"))
+        .go();
+  }
+
+  @Test
+  public void testMultiUnnestWithMap() throws Exception {
+    String sql = "select u.item from\n" +
+        "cp.`lateraljoin/nested-customer.parquet` c," +
+        "unnest(c.orders.items) as u(item)," +
+        "unnest(c.orders.items) as u1(item1)\n" +
+        "limit 1";
+
+    testBuilder()
+        .sqlQuery(sql)
+        .unOrdered()
+        .baselineColumns("item")
+        .baselineValues(
+            TestBuilder.mapOf("i_name", "paper towel",
+                "i_number", 2.0,
+                "i_supplier", "oregan"))
+        .go();
+  }
+
+  @Test
+  public void testSingleUnnestCol() throws Exception {
+    String sql =
+      "select t.orders.o_id as id " +
+      "from (select u.orders from\n" +
+            "cp.`lateraljoin/nested-customer.parquet` c," +
+            "unnest(c.orders) as u(orders)\n" +
+            "limit 1) t";
+
+    testBuilder()
+        .sqlQuery(sql)
+        .unOrdered()
+        .baselineColumns("id")
+        .baselineValues(1.0)
+        .go();
+  }
+
   @Test
   public void testNestedUnnest() throws Exception {
     String Sql = "select * from (select customer.orders as orders from cp.`lateraljoin/nested-customer.parquet` customer ) t1," +


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services