http://git-wip-us.apache.org/repos/asf/lens/blob/2aaf6e0a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTableResolver.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTableResolver.java
 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTableResolver.java
index 2ab7f4b..97a73a8 100644
--- 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTableResolver.java
+++ 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTableResolver.java
@@ -51,9 +51,6 @@ class CandidateTableResolver implements ContextRewriter {
 
   private boolean checkForQueriedColumns = true;
 
-  public CandidateTableResolver(Configuration ignored) {
-  }
-
   @Override
   public void rewriteContext(CubeQueryContext cubeql) throws LensException {
     if (checkForQueriedColumns) {
@@ -87,27 +84,20 @@ class CandidateTableResolver implements ContextRewriter {
   }
 
   private void populateCandidateTables(CubeQueryContext cubeql) throws 
LensException {
-    int aliasCounter = 0;
     if (cubeql.getCube() != null) {
       List<CubeFactTable> factTables = 
cubeql.getMetastoreClient().getAllFacts(cubeql.getCube());
-      // TODO union : Check for cube table partially valid, else remove it.
       if (factTables.isEmpty()) {
         throw new 
LensException(LensCubeErrorCode.NO_CANDIDATE_FACT_AVAILABLE.getLensErrorInfo(),
             cubeql.getCube().getName() + " does not have any facts");
       }
       for (CubeFactTable fact : factTables) {
-        Iterator<String> it = fact.getStorages().iterator();
-        //TODO union : Add MISSING_STORAGES pruning message
-        /* Moved this from StorageTableResolver
         if (fact.getUpdatePeriods().isEmpty()) {
-          cubeql.addFactPruningMsgs(fact, new 
CandidateTablePruneCause(CandidateTablePruneCode.MISSING_STORAGES));
-          i.remove();
-          continue;
-        }
-        */
-        while(it.hasNext()) {
-          StorageCandidate sc = new StorageCandidate(cubeql.getCube(), fact, 
it.next(), cubeql);
-          cubeql.getCandidates().add(sc);
+          log.info("Not considering fact: {} as it has no update periods", 
fact.getName());
+        } else {
+          for (String s : fact.getStorages()) {
+            StorageCandidate sc = new StorageCandidate(cubeql.getCube(), fact, 
s, cubeql);
+            cubeql.getCandidates().add(sc);
+          }
         }
       }
       log.info("Populated storage candidates: {}", cubeql.getCandidates());
@@ -284,7 +274,7 @@ class CandidateTableResolver implements ContextRewriter {
             if (!qur.isEvaluable(cubeql, sc)) {
               log.info("Not considering storage candidate:{} as columns {} are 
not available", sc, qur.getColumns());
               cubeql.addStoragePruningMsg(sc, 
CandidateTablePruneCause.columnNotFound(
-                  CandidateTablePruneCode.COLUMN_NOT_FOUND, qur.getColumns()));
+                qur.getColumns()));
               toRemove = true;
               break;
             }
@@ -297,7 +287,7 @@ class CandidateTableResolver implements ContextRewriter {
             Set<String> columns = getColumns(queriedMsrs);
             log.info("Not considering storage candidate:{} as columns {} is 
not available", sc, columns);
             cubeql.addStoragePruningMsg(sc, 
CandidateTablePruneCause.columnNotFound(
-                CandidateTablePruneCode.COLUMN_NOT_FOUND, columns));
+              columns));
             toRemove = true;
           }
 
@@ -311,7 +301,7 @@ class CandidateTableResolver implements ContextRewriter {
                 log.info("Not considering storage candidate:{} as columns {} 
are not available", sc,
                     chain.getSourceColumns());
                 cubeql.addStoragePruningMsg(sc, 
CandidateTablePruneCause.columnNotFound(
-                    CandidateTablePruneCode.COLUMN_NOT_FOUND, 
chain.getSourceColumns()));
+                  chain.getSourceColumns()));
                 toRemove = true;
                 break;
               }
@@ -539,7 +529,7 @@ class CandidateTableResolver implements ContextRewriter {
                   log.info("Not considering Storage:{} as its required 
optional dims are not reachable", candidate);
                   cubeql.getCandidates().remove(candidate);
                   cubeql.addStoragePruningMsg((StorageCandidate) candidate,
-                      
CandidateTablePruneCause.columnNotFound(CandidateTablePruneCode.COLUMN_NOT_FOUND,
 col));
+                      CandidateTablePruneCause.columnNotFound(col));
                   Collection<Candidate> prunedCandidates = CandidateUtil.
                       filterCandidates(cubeql.getCandidates(), 
(StorageCandidate) candidate);
                   cubeql.addCandidatePruningMsg(prunedCandidates,
@@ -550,7 +540,7 @@ class CandidateTableResolver implements ContextRewriter {
                 cubeql.getCandidateDimTables().get(((CandidateDim) 
candidate).getBaseTable()).remove(candidate);
                 cubeql.addDimPruningMsgs((Dimension) candidate.getBaseTable(),
                   (CubeDimensionTable) candidate.getTable(),
-                  
CandidateTablePruneCause.columnNotFound(CandidateTablePruneCode.COLUMN_NOT_FOUND,
 col));
+                  CandidateTablePruneCause.columnNotFound(col));
               }
             }
           }
@@ -645,12 +635,12 @@ class CandidateTableResolver implements ContextRewriter {
                     i.remove();
                     break;
                   }
-                } else if (!cubeql.getDeNormCtx().addRefUsage(cdim, col, 
dim.getName())) {
+                } else if (!cubeql.getDeNormCtx().addRefUsage(cubeql, cdim, 
col, dim.getName())) {
                   // check if it available as reference, if not remove the
                   // candidate
                   log.info("Not considering dimtable: {} as column {} is not 
available", cdim, col);
                   cubeql.addDimPruningMsgs(dim, cdim.getTable(), 
CandidateTablePruneCause.columnNotFound(
-                      CandidateTablePruneCode.COLUMN_NOT_FOUND, col));
+                    col));
                   i.remove();
                   break;
                 }

http://git-wip-us.apache.org/repos/asf/lens/blob/2aaf6e0a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateUtil.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateUtil.java 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateUtil.java
index bdde27c..68449f6 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateUtil.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateUtil.java
@@ -43,20 +43,6 @@ import com.google.common.collect.TreeRangeSet;
 public class CandidateUtil {
 
   /**
-   * Is calculated measure expression answerable by the Candidate
-   * @param exprNode
-   * @param candidate
-   * @param context
-   * @return
-   * @throws LensException
-   */
-  public static boolean isMeasureExpressionAnswerable(ASTNode exprNode, 
Candidate candidate, CubeQueryContext context)
-    throws LensException {
-    return candidate.getColumns().containsAll(HQLParser.getColsInExpr(
-      context.getAliasForTableName(context.getCube()), exprNode));
-  }
-
-  /**
    * Returns true if the Candidate is valid for all the timeranges based on 
its start and end times.
    * @param candidate
    * @param timeRanges
@@ -72,39 +58,10 @@ public class CandidateUtil {
     return true;
   }
 
-  public static boolean isPartiallyValidForTimeRanges(Candidate cand, 
List<TimeRange> timeRanges) {
-    for (TimeRange timeRange : timeRanges) {
-      if ((cand.getStartTime().before(timeRange.getFromDate()) && 
cand.getEndTime().after(timeRange.getFromDate()))
-          || (cand.getStartTime().before(timeRange.getToDate()) && 
cand.getEndTime().after(timeRange.getToDate()))) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Gets the time partition columns for a storage candidate
-   * TODO decide is this needs to be supported for all Candidate types.
-   *
-   * @param candidate : Stoarge Candidate
-   * @param metastoreClient : Cube metastore client
-   * @return
-   * @throws LensException
-   */
-  public Set<String> getTimePartitionCols(StorageCandidate candidate, 
CubeMetastoreClient metastoreClient)
-    throws LensException {
-    Set<String> cubeTimeDimensions = candidate.getCube().getTimedDimensions();
-    Set<String> timePartDimensions = new HashSet<String>();
-    String singleStorageTable = candidate.getStorageName();
-    List<FieldSchema> partitionKeys = null;
-    partitionKeys = 
metastoreClient.getTable(singleStorageTable).getPartitionKeys();
-    for (FieldSchema fs : partitionKeys) {
-      if 
(cubeTimeDimensions.contains(CubeQueryContext.getTimeDimOfPartitionColumn(candidate.getCube(),
-        fs.getName()))) {
-        timePartDimensions.add(fs.getName());
-      }
-    }
-    return timePartDimensions;
+  static boolean isPartiallyValidForTimeRanges(Candidate cand, List<TimeRange> 
timeRanges) {
+    return timeRanges.stream().anyMatch(timeRange ->
+      (cand.getStartTime().before(timeRange.getFromDate()) && 
cand.getEndTime().after(timeRange.getFromDate()))
+      || (cand.getStartTime().before(timeRange.getToDate()) && 
cand.getEndTime().after(timeRange.getToDate())));
   }
 
   /**
@@ -114,7 +71,7 @@ public class CandidateUtil {
    * @param targetAst
    * @throws LensException
    */
-  public static void copyASTs(QueryAST sourceAst, QueryAST targetAst) throws 
LensException {
+  static void copyASTs(QueryAST sourceAst, QueryAST targetAst) throws 
LensException {
     targetAst.setSelectAST(MetastoreUtil.copyAST(sourceAst.getSelectAST()));
     targetAst.setWhereAST(MetastoreUtil.copyAST(sourceAst.getWhereAST()));
     if (sourceAst.getJoinAST() != null) {
@@ -132,9 +89,10 @@ public class CandidateUtil {
     return getStorageCandidates(new HashSet<Candidate>(1) {{ add(candidate); 
}});
   }
 
-
-  public static Set<QueriedPhraseContext> coveredMeasures(Candidate candSet, 
Collection<QueriedPhraseContext> msrs,
-      CubeQueryContext cubeql) throws LensException {
+  // this function should only be used for union candidates and never for join 
candidates.
+  // future scope of improvement: move the data model to use polymorphism
+  static Set<QueriedPhraseContext> coveredMeasures(Candidate candSet, 
Collection<QueriedPhraseContext> msrs,
+    CubeQueryContext cubeql) throws LensException {
     Set<QueriedPhraseContext> coveringSet = new HashSet<>();
     for (QueriedPhraseContext msr : msrs) {
       if (candSet.getChildren() == null) {
@@ -142,12 +100,16 @@ public class CandidateUtil {
           coveringSet.add(msr);
         }
       } else {
-        // TODO union : all candidates should answer
+        boolean allCanAnswer = true;
         for (Candidate cand : candSet.getChildren()) {
-          if (msr.isEvaluable(cubeql, (StorageCandidate) cand)) {
-            coveringSet.add(msr);
+          if (!msr.isEvaluable(cubeql, (StorageCandidate) cand)) {
+            allCanAnswer = false;
+            break;
           }
         }
+        if (allCanAnswer) {
+          coveringSet.add(msr);
+        }
       }
     }
     return coveringSet;
@@ -235,7 +197,7 @@ public class CandidateUtil {
   public static class ChildrenSizeBasedCandidateComparator<T> implements 
Comparator<Candidate> {
     @Override
     public int compare(Candidate o1, Candidate o2) {
-      return Integer.valueOf(o1.getChildren().size() - 
o2.getChildren().size());
+      return o1.getChildren().size() - o2.getChildren().size();
     }
   }
 
@@ -279,7 +241,7 @@ public class CandidateUtil {
     if (limit != null) {
       queryFormat.append(" LIMIT %s");
     }
-    return String.format(queryFormat.toString(), qstrs.toArray(new String[0]));
+    return String.format(queryFormat.toString(), qstrs.toArray(new 
String[qstrs.size()]));
   }
 
   /**
@@ -312,15 +274,4 @@ public class CandidateUtil {
     }
   }
 
-  public static boolean containsAny(Set<String> srcSet, Set<String> colSet) {
-    if (colSet == null || colSet.isEmpty()) {
-      return true;
-    }
-    for (String column : colSet) {
-      if (srcSet.contains(column)) {
-        return true;
-      }
-    }
-    return false;
-  }
 }

http://git-wip-us.apache.org/repos/asf/lens/blob/2aaf6e0a/lens-cube/src/main/java/org/apache/lens/cube/parse/CheckTableNames.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CheckTableNames.java 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CheckTableNames.java
index 8586262..df35a42 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/parse/CheckTableNames.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/CheckTableNames.java
@@ -30,7 +30,6 @@ public class CheckTableNames extends ValidationRule {
 
   @Override
   public boolean validate(CubeQueryContext ctx) throws LensException {
-    // TODO
     return true;
   }
 

http://git-wip-us.apache.org/repos/asf/lens/blob/2aaf6e0a/lens-cube/src/main/java/org/apache/lens/cube/parse/ColumnLifetimeChecker.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/ColumnLifetimeChecker.java 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/ColumnLifetimeChecker.java
new file mode 100644
index 0000000..24eb8f0
--- /dev/null
+++ 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/ColumnLifetimeChecker.java
@@ -0,0 +1,131 @@
+/**
+ * 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.lens.cube.parse;
+
+import static org.apache.hadoop.hive.ql.parse.HiveParser.*;
+
+import java.util.*;
+
+import org.apache.lens.cube.error.ColUnAvailableInTimeRange;
+import org.apache.lens.cube.error.ColUnAvailableInTimeRangeException;
+import org.apache.lens.cube.error.LensCubeErrorCode;
+import org.apache.lens.cube.metadata.*;
+import org.apache.lens.cube.metadata.join.JoinPath;
+import org.apache.lens.cube.parse.join.AutoJoinContext;
+import org.apache.lens.server.api.LensConfConstants;
+import org.apache.lens.server.api.error.LensException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.ql.parse.ASTNode;
+import org.apache.hadoop.hive.ql.plan.PlanUtils;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class ColumnLifetimeChecker implements ContextRewriter {
+  @Override
+  public void rewriteContext(CubeQueryContext cubeql) throws LensException {
+    if (cubeql.getCube() == null) {
+      return;
+    }
+    doColLifeValidation(cubeql);
+  }
+
+  private void doColLifeValidation(CubeQueryContext cubeql) throws 
LensException,
+      ColUnAvailableInTimeRangeException {
+    Set<String> cubeColumns = 
cubeql.getColumnsQueriedForTable(cubeql.getCube().getName());
+    if (cubeColumns == null || cubeColumns.isEmpty()) {
+      // Query doesn't have any columns from cube
+      return;
+    }
+
+    for (String col : 
cubeql.getColumnsQueriedForTable(cubeql.getCube().getName())) {
+      CubeColumn column = cubeql.getCube().getColumnByName(col);
+      for (TimeRange range : cubeql.getTimeRanges()) {
+        if (column == null) {
+          if (!cubeql.getCube().getTimedDimensions().contains(col)) {
+            throw new 
LensException(LensCubeErrorCode.NOT_A_CUBE_COLUMN.getLensErrorInfo(), col);
+          }
+          continue;
+        }
+        if (!column.isColumnAvailableInTimeRange(range)) {
+          throwException(column);
+        }
+      }
+    }
+
+    // Remove join paths that have columns with invalid life span
+    AutoJoinContext joinContext = cubeql.getAutoJoinCtx();
+    if (joinContext == null) {
+      return;
+    }
+    // Get cube columns which are part of join chain
+    Set<String> joinColumns = 
joinContext.getAllJoinPathColumnsOfTable((AbstractCubeTable) cubeql.getCube());
+    if (joinColumns == null || joinColumns.isEmpty()) {
+      return;
+    }
+
+    // Loop over all cube columns part of join paths
+    for (String col : joinColumns) {
+      CubeColumn column = cubeql.getCube().getColumnByName(col);
+      for (TimeRange range : cubeql.getTimeRanges()) {
+        if (!column.isColumnAvailableInTimeRange(range)) {
+          log.info("Timerange queried is not in column life for {}, Removing 
join paths containing the column", column);
+          // Remove join paths containing this column
+          Map<Aliased<Dimension>, List<JoinPath>> allPaths = 
joinContext.getAllPaths();
+
+          for (Aliased<Dimension> dimension : allPaths.keySet()) {
+            List<JoinPath> joinPaths = allPaths.get(dimension);
+            Iterator<JoinPath> joinPathIterator = joinPaths.iterator();
+
+            while (joinPathIterator.hasNext()) {
+              JoinPath path = joinPathIterator.next();
+              if (path.containsColumnOfTable(col, (AbstractCubeTable) 
cubeql.getCube())) {
+                log.info("Removing join path: {} as columns :{} is not 
available in the range", path, col);
+                joinPathIterator.remove();
+                if (joinPaths.isEmpty()) {
+                  // This dimension doesn't have any paths left
+                  throw new 
LensException(LensCubeErrorCode.NO_JOIN_PATH.getLensErrorInfo(),
+                      "No valid join path available for dimension " + 
dimension + " which would satisfy time range "
+                          + range.getFromDate() + "-" + range.getToDate());
+                }
+              }
+            } // End loop to remove path
+
+          } // End loop for all paths
+        }
+      } // End time range loop
+    } // End column loop
+  }
+
+  private void throwException(CubeColumn column) throws 
ColUnAvailableInTimeRangeException {
+
+    final Long availabilityStartTime = 
(column.getStartTimeMillisSinceEpoch().isPresent())
+        ? column.getStartTimeMillisSinceEpoch().get() : null;
+
+    final Long availabilityEndTime = 
column.getEndTimeMillisSinceEpoch().isPresent()
+        ? column.getEndTimeMillisSinceEpoch().get() : null;
+
+    ColUnAvailableInTimeRange col = new 
ColUnAvailableInTimeRange(column.getName(), availabilityStartTime,
+        availabilityEndTime);
+
+    throw new ColUnAvailableInTimeRangeException(col);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/2aaf6e0a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java
index e56193c..76031ec 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -19,22 +19,44 @@
 
 package org.apache.lens.cube.parse;
 
-import static org.apache.lens.cube.parse.CubeQueryConfUtil.*;
-
-import static org.apache.hadoop.hive.ql.parse.HiveParser.*;
-
 import static com.google.common.base.Preconditions.checkArgument;
-
-
+import static java.util.stream.Collectors.toSet;
+import static org.apache.hadoop.hive.ql.parse.HiveParser.Identifier;
+import static org.apache.hadoop.hive.ql.parse.HiveParser.TOK_TABLE_OR_COL;
+import static org.apache.hadoop.hive.ql.parse.HiveParser.TOK_TMP_FILE;
+import static 
org.apache.lens.cube.parse.CubeQueryConfUtil.DEFAULT_REPLACE_TIMEDIM_WITH_PART_COL;
+import static 
org.apache.lens.cube.parse.CubeQueryConfUtil.DEFAULT_REWRITE_DIM_FILTER_TO_FACT_FILTER;
+import static 
org.apache.lens.cube.parse.CubeQueryConfUtil.NON_EXISTING_PARTITIONS;
+import static 
org.apache.lens.cube.parse.CubeQueryConfUtil.REPLACE_TIMEDIM_WITH_PART_COL;
+import static 
org.apache.lens.cube.parse.CubeQueryConfUtil.REWRITE_DIM_FILTER_TO_FACT_FILTER;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.Predicate;
 
 import org.apache.lens.cube.error.LensCubeErrorCode;
 import org.apache.lens.cube.error.NoCandidateDimAvailableException;
 import org.apache.lens.cube.error.NoCandidateFactAvailableException;
-import org.apache.lens.cube.metadata.*;
+import org.apache.lens.cube.metadata.AbstractCubeTable;
+import org.apache.lens.cube.metadata.Cube;
+import org.apache.lens.cube.metadata.CubeDimensionTable;
+import org.apache.lens.cube.metadata.CubeInterface;
+import org.apache.lens.cube.metadata.CubeMetastoreClient;
+import org.apache.lens.cube.metadata.DerivedCube;
+import org.apache.lens.cube.metadata.Dimension;
+import org.apache.lens.cube.metadata.JoinChain;
+import org.apache.lens.cube.metadata.Named;
+import org.apache.lens.cube.metadata.TimeRange;
 import org.apache.lens.cube.metadata.join.TableRelationship;
 import org.apache.lens.cube.parse.join.AutoJoinContext;
 import org.apache.lens.cube.parse.join.JoinClause;
@@ -47,21 +69,33 @@ import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hive.conf.HiveConf;
 import org.apache.hadoop.hive.ql.Context;
 import org.apache.hadoop.hive.ql.metadata.HiveException;
-import org.apache.hadoop.hive.ql.parse.*;
+import org.apache.hadoop.hive.ql.parse.ASTNode;
+import org.apache.hadoop.hive.ql.parse.HiveParser;
+import org.apache.hadoop.hive.ql.parse.JoinCond;
+import org.apache.hadoop.hive.ql.parse.ParseDriver;
+import org.apache.hadoop.hive.ql.parse.ParseException;
+import org.apache.hadoop.hive.ql.parse.ParseUtils;
+import org.apache.hadoop.hive.ql.parse.QB;
+import org.apache.hadoop.hive.ql.parse.QBJoinTree;
+import org.apache.hadoop.hive.ql.parse.QBParseInfo;
 
 import org.codehaus.jackson.map.ObjectMapper;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
-import lombok.*;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-public class CubeQueryContext extends TracksQueriedColumns implements QueryAST 
{
-  public static final String TIME_RANGE_FUNC = "time_range_in";
+public class CubeQueryContext extends TracksQueriedColumns implements 
QueryAST, TrackDenormContext {
+  static final String TIME_RANGE_FUNC = "time_range_in";
   public static final String NOW = "now";
-  public static final String DEFAULT_TABLE = "_default_";
+  static final String DEFAULT_TABLE = "_default_";
   private final ASTNode ast;
   @Getter
   private final QB qb;
@@ -124,12 +158,7 @@ public class CubeQueryContext extends TracksQueriedColumns 
implements QueryAST {
   }
 
   boolean isColumnAnAlias(String col) {
-    for (SelectPhraseContext sel : selectPhrases) {
-      if (col.equals(sel.getActualAlias())) {
-        return true;
-      }
-    }
-    return false;
+    return 
selectPhrases.stream().map(SelectPhraseContext::getActualAlias).anyMatch(Predicate.isEqual(col));
   }
 
   void addQueriedPhrase(QueriedPhraseContext qur) {
@@ -145,9 +174,9 @@ public class CubeQueryContext extends TracksQueriedColumns 
implements QueryAST {
 
   // Join conditions used in all join expressions
   @Getter
-  private final Map<QBJoinTree, String> joinConds = new HashMap<QBJoinTree, 
String>();
+  private final Map<QBJoinTree, String> joinConds = new HashMap<>();
   @Getter
-  protected final Map<Dimension, Set<CandidateDim>> candidateDims = new 
HashMap<Dimension, Set<CandidateDim>>();
+  protected final Map<Dimension, Set<CandidateDim>> candidateDims = new 
HashMap<>();
   // query trees
   @Getter
   @Setter
@@ -192,7 +221,7 @@ public class CubeQueryContext extends TracksQueriedColumns 
implements QueryAST {
     this.qb = qb;
     this.conf = queryConf;
     this.clauseName = getClause();
-    this.timeRanges = new ArrayList<TimeRange>();
+    this.timeRanges = new ArrayList<>();
     try {
       metastoreClient = CubeMetastoreClient.getInstance(metastoreConf);
     } catch (HiveException e) {
@@ -217,14 +246,10 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     extractMetaTables();
   }
 
-  public boolean hasCubeInQuery() {
+  boolean hasCubeInQuery() {
     return cube != null;
   }
 
-  public boolean hasDimensionInQuery() {
-    return dimensions != null && !dimensions.isEmpty();
-  }
-
   private void extractMetaTables() throws LensException {
     List<String> tabAliases = new ArrayList<String>(qb.getTabAliases());
     Set<String> missing = new HashSet<String>();
@@ -280,10 +305,10 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
       return true;
     }
 
-    return retVal;
+    return false;
   }
 
-  public boolean addQueriedTable(String alias) throws LensException {
+  boolean addQueriedTable(String alias) throws LensException {
     return addQueriedTable(alias, false);
   }
 
@@ -346,36 +371,24 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return true;
   }
 
-  public boolean isAutoJoinResolved() {
+  boolean isAutoJoinResolved() {
     return autoJoinCtx != null && autoJoinCtx.isJoinsResolved();
   }
 
-  public Cube getBaseCube() {
-    if (cube instanceof Cube) {
-      return (Cube) cube;
-    }
-    return ((DerivedCube) cube).getParent();
+  Cube getBaseCube() {
+    return cube instanceof Cube ? (Cube) cube : ((DerivedCube) 
cube).getParent();
   }
 
-  public Set<String> getPartitionColumnsQueried() {
-    Set<String> partsQueried = Sets.newHashSet();
-    for (TimeRange range : getTimeRanges()) {
-      partsQueried.add(range.getPartitionColumn());
-    }
-    return partsQueried;
+  Set<String> getPartitionColumnsQueried() {
+    return 
getTimeRanges().stream().map(TimeRange::getPartitionColumn).collect(toSet());
   }
 
   // map of ref column in query to set of Dimension that have the column - 
which are added as optional dims
   @Getter
   private Map<String, Set<Aliased<Dimension>>> refColToDim = Maps.newHashMap();
 
-  public void updateRefColDim(String col, Aliased<Dimension> dim) {
-    Set<Aliased<Dimension>> refDims = refColToDim.get(col.toLowerCase());
-    if (refDims == null) {
-      refDims = Sets.newHashSet();
-      refColToDim.put(col.toLowerCase(), refDims);
-    }
-    refDims.add(dim);
+  private void updateRefColDim(String col, Aliased<Dimension> dim) {
+    refColToDim.computeIfAbsent(col.toLowerCase(), k -> 
Sets.newHashSet()).add(dim);
   }
 
   @Data
@@ -390,15 +403,8 @@ public class CubeQueryContext extends TracksQueriedColumns 
implements QueryAST {
   @Getter
   private Map<QueriedExprColumn, Set<Aliased<Dimension>>> exprColToDim = 
Maps.newHashMap();
 
-  public void updateExprColDim(String tblAlias, String col, Aliased<Dimension> 
dim) {
-
-    QueriedExprColumn qexpr = new QueriedExprColumn(col, tblAlias);
-    Set<Aliased<Dimension>> exprDims = exprColToDim.get(qexpr);
-    if (exprDims == null) {
-      exprDims = Sets.newHashSet();
-      exprColToDim.put(qexpr, exprDims);
-    }
-    exprDims.add(dim);
+  private void updateExprColDim(String tblAlias, String col, 
Aliased<Dimension> dim) {
+    exprColToDim.computeIfAbsent(new QueriedExprColumn(col, tblAlias), k -> 
Sets.newHashSet()).add(dim);
   }
 
   // Holds the context of optional dimension
@@ -406,7 +412,7 @@ public class CubeQueryContext extends TracksQueriedColumns 
implements QueryAST {
   // required by a candidate table to get a denormalized field from reference
   // or required in a join chain
   @ToString
-  public static class OptionalDimCtx {
+  static class OptionalDimCtx {
     OptionalDimCtx() {
     }
 
@@ -415,16 +421,16 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     boolean isRequiredInJoinChain = false;
   }
 
-  public void addOptionalJoinDimTable(String alias, boolean isRequired) throws 
LensException {
+  void addOptionalJoinDimTable(String alias, boolean isRequired) throws 
LensException {
     addOptionalDimTable(alias, null, isRequired, null, false, (String[]) null);
   }
 
-  public void addOptionalExprDimTable(String dimAlias, String queriedExpr, 
String srcTableAlias,
+  void addOptionalExprDimTable(String dimAlias, String queriedExpr, String 
srcTableAlias,
     CandidateTable candidate, String... cols) throws LensException {
     addOptionalDimTable(dimAlias, candidate, false, queriedExpr, false, 
srcTableAlias, cols);
   }
 
-  public void addOptionalDimTable(String alias, CandidateTable candidate, 
boolean isRequiredInJoin, String cubeCol,
+  void addOptionalDimTable(String alias, CandidateTable candidate, boolean 
isRequiredInJoin, String cubeCol,
     boolean isRef, String... cols) throws LensException {
     addOptionalDimTable(alias, candidate, isRequiredInJoin, cubeCol, isRef, 
null, cols);
   }
@@ -437,15 +443,9 @@ public class CubeQueryContext extends TracksQueriedColumns 
implements QueryAST {
     }
     Dimension dim = (Dimension) cubeTbls.get(alias);
     Aliased<Dimension> aliasedDim = Aliased.create(dim, alias);
-    OptionalDimCtx optDim = optionalDimensionMap.get(aliasedDim);
-    if (optDim == null) {
-      optDim = new OptionalDimCtx();
-      optionalDimensionMap.put(aliasedDim, optDim);
-    }
+    OptionalDimCtx optDim = optionalDimensionMap.computeIfAbsent(aliasedDim, k 
-> new OptionalDimCtx());
     if (cols != null && candidate != null) {
-      for (String col : cols) {
-        optDim.colQueried.add(col);
-      }
+      optDim.colQueried.addAll(Arrays.asList(cols));
       optDim.requiredForCandidates.add(candidate);
     }
     if (cubeCol != null) {
@@ -480,32 +480,28 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return candidateDims;
   }
 
-  public void addCandidatePruningMsg(Collection<Candidate> 
candidateCollection, CandidateTablePruneCause pruneCause) {
+  void addCandidatePruningMsg(Collection<Candidate> candidateCollection, 
CandidateTablePruneCause pruneCause) {
     for (Candidate c : candidateCollection){
       addCandidatePruningMsg(c, pruneCause);
     }
-
   }
 
-  public void addCandidatePruningMsg(Candidate cand, CandidateTablePruneCause 
pruneCause) {
+  void addCandidatePruningMsg(Candidate cand, CandidateTablePruneCause 
pruneCause) {
     Set<StorageCandidate> scs = CandidateUtil.getStorageCandidates(cand);
     for (StorageCandidate sc : scs) {
       addStoragePruningMsg(sc, pruneCause);
     }
   }
 
-  public void addStoragePruningMsg(StorageCandidate sc, 
CandidateTablePruneCause factPruningMsg) {
-    log.info("Pruning Storage {} with cause: {}", sc, factPruningMsg);
-    storagePruningMsgs.addPruningMsg(sc, factPruningMsg);
+  void addStoragePruningMsg(StorageCandidate sc, CandidateTablePruneCause... 
factPruningMsgs) {
+    for (CandidateTablePruneCause factPruningMsg: factPruningMsgs) {
+      log.info("Pruning Storage {} with cause: {}", sc, factPruningMsg);
+      storagePruningMsgs.addPruningMsg(sc, factPruningMsg);
+    }
   }
 
   public void addDimPruningMsgs(Dimension dim, CubeDimensionTable dimtable, 
CandidateTablePruneCause msg) {
-    PruneCauses<CubeDimensionTable> dimMsgs = dimPruningMsgs.get(dim);
-    if (dimMsgs == null) {
-      dimMsgs = new PruneCauses<CubeDimensionTable>();
-      dimPruningMsgs.put(dim, dimMsgs);
-    }
-    dimMsgs.addPruningMsg(dimtable, msg);
+    dimPruningMsgs.computeIfAbsent(dim, k -> new 
PruneCauses<>()).addPruningMsg(dimtable, msg);
   }
 
   public String getAliasForTableName(Named named) {
@@ -532,73 +528,75 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     if (!log.isDebugEnabled()) {
       return;
     }
-    StringBuilder builder = new StringBuilder();
-    builder.append("ASTNode:" + ast.dump() + "\n");
-    builder.append("QB:");
-    builder.append("\n numJoins:" + qb.getNumJoins());
-    builder.append("\n numGbys:" + qb.getNumGbys());
-    builder.append("\n numSels:" + qb.getNumSels());
-    builder.append("\n numSelDis:" + qb.getNumSelDi());
-    builder.append("\n aliasToTabs:");
+    StringBuilder builder = new StringBuilder()
+      .append("ASTNode:").append(ast.dump()).append("\n")
+      .append("QB:")
+      .append("\n numJoins:").append(qb.getNumJoins())
+      .append("\n numGbys:").append(qb.getNumGbys())
+      .append("\n numSels:").append(qb.getNumSels())
+      .append("\n numSelDis:").append(qb.getNumSelDi())
+      .append("\n aliasToTabs:");
     Set<String> tabAliases = qb.getTabAliases();
     for (String alias : tabAliases) {
-      builder.append("\n\t" + alias + ":" + qb.getTabNameForAlias(alias));
+      
builder.append("\n\t").append(alias).append(":").append(qb.getTabNameForAlias(alias));
     }
     builder.append("\n aliases:");
     for (String alias : qb.getAliases()) {
       builder.append(alias);
       builder.append(", ");
     }
-    builder.append("id:" + qb.getId());
-    builder.append("isQuery:" + qb.getIsQuery());
-    builder.append("\n QBParseInfo");
+    builder
+      .append("id:").append(qb.getId())
+      .append("isQuery:").append(qb.getIsQuery())
+      .append("\n QBParseInfo");
     QBParseInfo parseInfo = qb.getParseInfo();
-    builder.append("\n isSubQ: " + parseInfo.getIsSubQ());
-    builder.append("\n alias: " + parseInfo.getAlias());
+    builder
+      .append("\n isSubQ: ").append(parseInfo.getIsSubQ())
+      .append("\n alias: ").append(parseInfo.getAlias());
     if (parseInfo.getJoinExpr() != null) {
-      builder.append("\n joinExpr: " + parseInfo.getJoinExpr().dump());
+      builder.append("\n joinExpr: ").append(parseInfo.getJoinExpr().dump());
     }
-    builder.append("\n hints: " + parseInfo.getHints());
+    builder.append("\n hints: ").append(parseInfo.getHints());
     builder.append("\n aliasToSrc: ");
     for (String alias : tabAliases) {
-      builder.append("\n\t" + alias + ": " + 
parseInfo.getSrcForAlias(alias).dump());
+      builder.append("\n\t").append(alias).append(": 
").append(parseInfo.getSrcForAlias(alias).dump());
     }
     TreeSet<String> clauses = new TreeSet<String>(parseInfo.getClauseNames());
     for (String clause : clauses) {
-      builder.append("\n\t" + clause + ": " + 
parseInfo.getClauseNamesForDest());
+      builder.append("\n\t").append(clause).append(": 
").append(parseInfo.getClauseNamesForDest());
     }
     String clause = clauses.first();
     if (parseInfo.getWhrForClause(clause) != null) {
-      builder.append("\n whereexpr: " + 
parseInfo.getWhrForClause(clause).dump());
+      builder.append("\n whereexpr: 
").append(parseInfo.getWhrForClause(clause).dump());
     }
     if (parseInfo.getGroupByForClause(clause) != null) {
-      builder.append("\n groupby expr: " + 
parseInfo.getGroupByForClause(clause).dump());
+      builder.append("\n groupby expr: 
").append(parseInfo.getGroupByForClause(clause).dump());
     }
     if (parseInfo.getSelForClause(clause) != null) {
-      builder.append("\n sel expr: " + 
parseInfo.getSelForClause(clause).dump());
+      builder.append("\n sel expr: 
").append(parseInfo.getSelForClause(clause).dump());
     }
     if (parseInfo.getHavingForClause(clause) != null) {
-      builder.append("\n having expr: " + 
parseInfo.getHavingForClause(clause).dump());
+      builder.append("\n having expr: 
").append(parseInfo.getHavingForClause(clause).dump());
     }
     if (parseInfo.getDestLimit(clause) != null) {
-      builder.append("\n limit: " + parseInfo.getDestLimit(clause));
+      builder.append("\n limit: ").append(parseInfo.getDestLimit(clause));
     }
     if (parseInfo.getAllExprToColumnAlias() != null && 
!parseInfo.getAllExprToColumnAlias().isEmpty()) {
       builder.append("\n exprToColumnAlias:");
       for (Map.Entry<ASTNode, String> entry : 
parseInfo.getAllExprToColumnAlias().entrySet()) {
-        builder.append("\n\t expr: " + entry.getKey().dump() + " ColumnAlias: 
" + entry.getValue());
+        builder.append("\n\t expr: ").append(entry.getKey().dump()).append(" 
ColumnAlias: ").append(entry.getValue());
       }
     }
     if (parseInfo.getAggregationExprsForClause(clause) != null) {
       builder.append("\n aggregateexprs:");
       for (Map.Entry<String, ASTNode> entry : 
parseInfo.getAggregationExprsForClause(clause).entrySet()) {
-        builder.append("\n\t key: " + entry.getKey() + " expr: " + 
entry.getValue().dump());
+        builder.append("\n\t key: ").append(entry.getKey()).append(" expr: 
").append(entry.getValue().dump());
       }
     }
     if (parseInfo.getDistinctFuncExprsForClause(clause) != null) {
       builder.append("\n distinctFuncExprs:");
       for (ASTNode entry : parseInfo.getDistinctFuncExprsForClause(clause)) {
-        builder.append("\n\t expr: " + entry.dump());
+        builder.append("\n\t expr: ").append(entry.dump());
       }
     }
 
@@ -609,24 +607,24 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     }
 
     if (qb.getParseInfo().getDestForClause(clause) != null) {
-      builder.append("\n Destination:");
-      builder.append("\n\t dest expr:" + 
qb.getParseInfo().getDestForClause(clause).dump());
+      builder.append("\n Destination:")
+        .append("\n\t dest 
expr:").append(qb.getParseInfo().getDestForClause(clause).dump());
     }
     log.debug(builder.toString());
   }
 
-  void printJoinTree(QBJoinTree joinTree, StringBuilder builder) {
-    builder.append("leftAlias:" + joinTree.getLeftAlias());
+  private void printJoinTree(QBJoinTree joinTree, StringBuilder builder) {
+    builder.append("leftAlias:").append(joinTree.getLeftAlias());
     if (joinTree.getLeftAliases() != null) {
       builder.append("\n leftAliases:");
       for (String alias : joinTree.getLeftAliases()) {
-        builder.append("\n\t " + alias);
+        builder.append("\n\t ").append(alias);
       }
     }
     if (joinTree.getRightAliases() != null) {
       builder.append("\n rightAliases:");
       for (String alias : joinTree.getRightAliases()) {
-        builder.append("\n\t " + alias);
+        builder.append("\n\t ").append(alias);
       }
     }
     if (joinTree.getJoinSrc() != null) {
@@ -637,22 +635,24 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     if (joinTree.getBaseSrc() != null) {
       builder.append("\n baseSrcs:");
       for (String src : joinTree.getBaseSrc()) {
-        builder.append("\n\t " + src);
+        builder.append("\n\t ").append(src);
       }
     }
-    builder.append("\n noOuterJoin: " + joinTree.getNoOuterJoin());
-    builder.append("\n noSemiJoin: " + joinTree.getNoSemiJoin());
-    builder.append("\n mapSideJoin: " + joinTree.isMapSideJoin());
+    builder.append("\n noOuterJoin: ").append(joinTree.getNoOuterJoin());
+    builder.append("\n noSemiJoin: ").append(joinTree.getNoSemiJoin());
+    builder.append("\n mapSideJoin: ").append(joinTree.isMapSideJoin());
     if (joinTree.getJoinCond() != null) {
       builder.append("\n joinConds:");
       for (JoinCond cond : joinTree.getJoinCond()) {
-        builder.append("\n\t left: " + cond.getLeft() + " right: " + 
cond.getRight() + " type:" + cond.getJoinType()
-          + " preserved:" + cond.getPreserved());
+        builder.append("\n\t left: ").append(cond.getLeft())
+          .append(" right: ").append(cond.getRight())
+          .append(" type:").append(cond.getJoinType())
+          .append(" preserved:").append(cond.getPreserved());
       }
     }
   }
 
-  void updateFromString(StorageCandidate sc, Map<Dimension, CandidateDim> 
dimsToQuery) throws LensException {
+  private void updateFromString(StorageCandidate sc, Map<Dimension, 
CandidateDim> dimsToQuery) throws LensException {
     fromString = "%s"; // storage string is updated later
     if (isAutoJoinResolved()) {
       fromString =
@@ -816,7 +816,7 @@ public class CubeQueryContext extends TracksQueriedColumns 
implements QueryAST {
     }
   }
 
-  public String getNonExistingParts() {
+  String getNonExistingParts() {
     return conf.get(NON_EXISTING_PARTITIONS);
   }
 
@@ -830,24 +830,13 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
             cdim.dimtable);
           dimsToQuery.put(dim, cdim);
         } else {
-          String reason = "";
           if (dimPruningMsgs.get(dim) != null && 
!dimPruningMsgs.get(dim).isEmpty()) {
-            ByteArrayOutputStream out = null;
-            try {
+            try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
               ObjectMapper mapper = new ObjectMapper();
-              out = new ByteArrayOutputStream();
               mapper.writeValue(out, dimPruningMsgs.get(dim).getJsonObject());
-              reason = out.toString("UTF-8");
+              log.info("No candidate dim found because: {}", 
out.toString("UTF-8"));
             } catch (Exception e) {
               throw new LensException("Error writing dim pruning messages", e);
-            } finally {
-              if (out != null) {
-                try {
-                  out.close();
-                } catch (IOException e) {
-                  throw new LensException(e);
-                }
-              }
             }
           }
           log.error("Query rewrite failed due to NO_CANDIDATE_DIM_AVAILABLE, 
Cause {}",
@@ -866,24 +855,13 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
         cand = candidates.iterator().next();
         log.info("Available Candidates:{}, picking up Candaidate: {} for 
querying", candidates, cand);
       } else {
-        String reason = "";
         if (!storagePruningMsgs.isEmpty()) {
-          ByteArrayOutputStream out = null;
-          try {
+          try(ByteArrayOutputStream out = new ByteArrayOutputStream()) {
             ObjectMapper mapper = new ObjectMapper();
-            out = new ByteArrayOutputStream();
             mapper.writeValue(out, storagePruningMsgs.getJsonObject());
-            reason = out.toString("UTF-8");
+            log.info("No candidate found because: {}", out.toString("UTF-8"));
           } catch (Exception e) {
             throw new LensException("Error writing fact pruning messages", e);
-          } finally {
-            if (out != null) {
-              try {
-                out.close();
-              } catch (IOException e) {
-                throw new LensException(e);
-              }
-            }
           }
         }
         log.error("Query rewrite failed due to NO_CANDIDATE_FACT_AVAILABLE, 
Cause {}",
@@ -946,13 +924,13 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     Set<Dimension> exprDimensions = new HashSet<>();
     if (!scSet.isEmpty()) {
       for (StorageCandidate sc : scSet) {
-        Set<Dimension> factExprDimTables = exprCtx.rewriteExprCtx(sc, 
dimsToQuery, sc.getQueryAst());
+        Set<Dimension> factExprDimTables = exprCtx.rewriteExprCtx(this, sc, 
dimsToQuery, sc.getQueryAst());
         exprDimensions.addAll(factExprDimTables);
         factDimMap.get(sc).addAll(factExprDimTables);
       }
     } else {
       // dim only query
-      exprDimensions.addAll(exprCtx.rewriteExprCtx(null, dimsToQuery, this));
+      exprDimensions.addAll(exprCtx.rewriteExprCtx(this, null, dimsToQuery, 
this));
     }
     dimsToQuery.putAll(pickCandidateDimsToQuery(exprDimensions));
     log.info("StorageCandidates: {}, DimsToQuery: {}", scSet, dimsToQuery);
@@ -961,12 +939,12 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     Set<Dimension> denormTables = new HashSet<>();
     if (!scSet.isEmpty()) {
       for (StorageCandidate sc : scSet) {
-        Set<Dimension> factDenormTables = deNormCtx.rewriteDenormctx(sc, 
dimsToQuery, !scSet.isEmpty());
+        Set<Dimension> factDenormTables = deNormCtx.rewriteDenormctx(this, sc, 
dimsToQuery, !scSet.isEmpty());
         denormTables.addAll(factDenormTables);
         factDimMap.get(sc).addAll(factDenormTables);
       }
     } else {
-      denormTables.addAll(deNormCtx.rewriteDenormctx(null, dimsToQuery, 
false));
+      denormTables.addAll(deNormCtx.rewriteDenormctx(this, null, dimsToQuery, 
false));
     }
     dimsToQuery.putAll(pickCandidateDimsToQuery(denormTables));
     log.info("StorageCandidates: {}, DimsToQuery: {}", scSet, dimsToQuery);
@@ -1000,7 +978,7 @@ public class CubeQueryContext extends TracksQueriedColumns 
implements QueryAST {
       updateFromString(null, dimsToQuery);
     }
     //update dim filter with fact filter
-    if (scSet != null && scSet.size() > 0) {
+    if (scSet.size() > 0) {
       for (StorageCandidate sc : scSet) {
         if (!sc.getStorageName().isEmpty()) {
           String qualifiedStorageTable = sc.getStorageName();
@@ -1039,18 +1017,18 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return ParseUtils.findRootNonNullToken(tree);
   }
 
-  public Set<String> getColumnsQueriedForTable(String tblName) {
+  Set<String> getColumnsQueriedForTable(String tblName) {
     return getColumnsQueried(getAliasForTableName(tblName));
   }
 
-  public void addColumnsQueriedWithTimeDimCheck(QueriedPhraseContext qur, 
String alias, String timeDimColumn) {
+  void addColumnsQueriedWithTimeDimCheck(QueriedPhraseContext qur, String 
alias, String timeDimColumn) {
 
     if (!shouldReplaceTimeDimWithPart()) {
       qur.addColumnsQueried(alias, timeDimColumn);
     }
   }
 
-  public boolean isCubeMeasure(String col) {
+  boolean isCubeMeasure(String col) {
     if (col == null) {
       return false;
     }
@@ -1100,6 +1078,7 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
       ASTNode colIdent = (ASTNode) node.getChild(1);
 
       colname = colIdent.getText();
+      assert tabident != null;
       tabname = tabident.getText();
     }
 
@@ -1108,7 +1087,7 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return isCubeMeasure(msrname);
   }
 
-  public boolean hasAggregates() {
+  boolean hasAggregates() {
     if (getExprCtx().hasAggregates()) {
       return true;
     }
@@ -1120,7 +1099,7 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return false;
   }
 
-  public void setJoinCond(QBJoinTree qb, String cond) {
+  void setJoinCond(QBJoinTree qb, String cond) {
     joinConds.put(qb, cond);
   }
 
@@ -1136,7 +1115,7 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return null;
   }
 
-  public String getInsertClause() {
+  String getInsertClause() {
     ASTNode destTree = qb.getParseInfo().getDestForClause(clauseName);
     if (destTree != null && ((ASTNode) 
(destTree.getChild(0))).getToken().getType() != TOK_TMP_FILE) {
       return "INSERT OVERWRITE " + HQLParser.getString(destTree) + " ";
@@ -1144,14 +1123,14 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return "";
   }
 
-  public Set<Aliased<Dimension>> getOptionalDimensions() {
+  Set<Aliased<Dimension>> getOptionalDimensions() {
     return optionalDimensionMap.keySet();
   }
 
   /**
    * @return the hqlContext
    */
-  public HQLContextInterface getHqlContext() {
+  HQLContextInterface getHqlContext() {
     return hqlContext;
   }
 
@@ -1159,15 +1138,15 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return getConf().getBoolean(REPLACE_TIMEDIM_WITH_PART_COL, 
DEFAULT_REPLACE_TIMEDIM_WITH_PART_COL);
   }
 
-  public boolean shouldReplaceDimFilterWithFactFilter() {
+  private boolean shouldReplaceDimFilterWithFactFilter() {
     return getConf().getBoolean(REWRITE_DIM_FILTER_TO_FACT_FILTER, 
DEFAULT_REWRITE_DIM_FILTER_TO_FACT_FILTER);
   }
 
-  public String getPartitionColumnOfTimeDim(String timeDimName) {
+  String getPartitionColumnOfTimeDim(String timeDimName) {
     return getPartitionColumnOfTimeDim(cube, timeDimName);
   }
 
-  public static String getPartitionColumnOfTimeDim(CubeInterface cube, String 
timeDimName) {
+  private static String getPartitionColumnOfTimeDim(CubeInterface cube, String 
timeDimName) {
     if (cube == null) {
       return timeDimName;
     }
@@ -1178,11 +1157,11 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     }
   }
 
-  public String getTimeDimOfPartitionColumn(String partCol) {
+  String getTimeDimOfPartitionColumn(String partCol) {
     return getTimeDimOfPartitionColumn(cube, partCol);
   }
 
-  public static String getTimeDimOfPartitionColumn(CubeInterface cube, String 
partCol) {
+  private static String getTimeDimOfPartitionColumn(CubeInterface cube, String 
partCol) {
     if (cube == null) {
       return partCol;
     }
@@ -1193,25 +1172,25 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     }
   }
 
-  public void addQueriedMsrs(Set<String> msrs) {
+  void addQueriedMsrs(Set<String> msrs) {
     queriedMsrs.addAll(msrs);
   }
 
-  public void addQueriedExprs(Set<String> exprs) {
+  void addQueriedExprs(Set<String> exprs) {
     queriedExprs.addAll(exprs);
   }
 
-  public void addQueriedExprsWithMeasures(Set<String> exprs) {
+  void addQueriedExprsWithMeasures(Set<String> exprs) {
     queriedExprsWithMeasures.addAll(exprs);
   }
 
-  public void addQueriedTimeDimensionCols(final String timeDimColName) {
+  void addQueriedTimeDimensionCols(final String timeDimColName) {
 
     checkArgument(StringUtils.isNotBlank(timeDimColName));
     this.queriedTimeDimCols.add(timeDimColName);
   }
 
-  public ImmutableSet<String> getQueriedTimeDimCols() {
+  ImmutableSet<String> getQueriedTimeDimCols() {
     return ImmutableSet.copyOf(this.queriedTimeDimCols);
   }
 
@@ -1230,7 +1209,7 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
     return whereString;
   }
 
-  private List<String> getAllFilters(ASTNode node, String cubeAlias, 
List<String> allFilters,
+  private void getAllFilters(ASTNode node, String cubeAlias, List<String> 
allFilters,
                                     JoinClause joinClause,  Map<Dimension, 
CandidateDim> dimToQuery)
     throws LensException {
 
@@ -1255,7 +1234,6 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
       ASTNode child = (ASTNode) node.getChild(i);
       getAllFilters(child, cubeAlias, allFilters, joinClause, dimToQuery);
     }
-    return allFilters;
   }
 
   private String getFilter(String table, String cubeAlias, ASTNode node,  
JoinClause joinClause,
@@ -1273,7 +1251,6 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
   }
 
   private TableRelationship getStarJoin(JoinClause joinClause, String table) {
-    TableRelationship rel;
     for (Map.Entry<TableRelationship, JoinTree>  entry : 
joinClause.getJoinTree().getSubtrees().entrySet()) {
       if (entry.getValue().getDepthFromRoot() == 1 && 
table.equals(entry.getValue().getAlias())) {
         return entry.getKey();
@@ -1285,8 +1262,9 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
   private String getTableFromFilterAST(ASTNode node) {
 
     if (node.getToken().getType() == HiveParser.DOT) {
-      return HQLParser.findNodeByPath((ASTNode) node,
-          TOK_TABLE_OR_COL, Identifier).getText();
+      ASTNode n = HQLParser.findNodeByPath(node, TOK_TABLE_OR_COL, Identifier);
+      assert n != null;
+      return n.getText();
     } else {
       // recurse down
       for (int i = 0; i < node.getChildCount(); i++) {
@@ -1305,7 +1283,8 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
                                                 String cubeAlias)
     throws LensException {
     StringBuilder builder = new StringBuilder();
-    String storageClause = 
dimToQuery.get(tabRelation.getToTable()).getWhereClause();
+    CandidateDim dim = dimToQuery.get(tabRelation.getToTable());
+    String storageClause = dim.getWhereClause();
 
     builder.append(cubeAlias)
         .append(".")
@@ -1314,9 +1293,9 @@ public class CubeQueryContext extends 
TracksQueriedColumns implements QueryAST {
         .append("select ")
         .append(tabRelation.getToColumn())
         .append(" from ")
-        
.append(dimToQuery.get(tabRelation.getToTable()).getStorageString(dimAlias))
+        .append(dim.getStorageString(dimAlias))
         .append(" where ")
-        .append(HQLParser.getString((ASTNode) dimFilter));
+        .append(HQLParser.getString(dimFilter));
     if (storageClause != null) {
       builder.append(" and ")
           .append(String.format(storageClause, dimAlias))

http://git-wip-us.apache.org/repos/asf/lens/blob/2aaf6e0a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryRewriter.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryRewriter.java 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryRewriter.java
index f052a2f..5713069 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryRewriter.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryRewriter.java
@@ -139,9 +139,9 @@ public class CubeQueryRewriter {
     // Rewrite base trees (groupby, having, orderby, limit) using aliases
     rewriters.add(new AliasReplacer(conf));
 
-    ExpressionResolver exprResolver = new ExpressionResolver(conf);
-    DenormalizationResolver denormResolver = new DenormalizationResolver(conf);
-    CandidateTableResolver candidateTblResolver = new 
CandidateTableResolver(conf);
+    ExpressionResolver exprResolver = new ExpressionResolver();
+    DenormalizationResolver denormResolver = new DenormalizationResolver();
+    CandidateTableResolver candidateTblResolver = new CandidateTableResolver();
     StorageTableResolver storageTableResolver = new StorageTableResolver(conf);
 
     // Phase 1 of exprResolver: Resolve expressions
@@ -160,7 +160,7 @@ public class CubeQueryRewriter {
     // Resolve joins and generate base join tree
     rewriters.add(new JoinResolver(conf));
     // Do col life validation for the time range(s) queried
-    rewriters.add(new TimeRangeChecker(conf));
+    rewriters.add(new ColumnLifetimeChecker());
     // Phase 1 of storageTableResolver: Validate and prune candidate storages
     rewriters.add(storageTableResolver);
     // Phase 2 of candidateTblResolver: Resolve candidate storages and 
dimension tables for columns included
@@ -168,7 +168,7 @@ public class CubeQueryRewriter {
     rewriters.add(candidateTblResolver);
     // Find Union and Join combinations over Storage Candidates that can 
answer the queried time range(s) and all
     // queried measures
-    rewriters.add(new CandidateCoveringSetsResolver(conf));
+    rewriters.add(new CandidateCoveringSetsResolver());
 
     // If lightest fact first option is enabled for this driver (via 
lens.cube.query.pick.lightest.fact.first = true),
     // run LightestFactResolver and keep only the lighted combination(s) 
generated by CandidateCoveringSetsResolver
@@ -209,7 +209,7 @@ public class CubeQueryRewriter {
   public CubeQueryContext rewrite(ASTNode astnode) throws LensException {
     CubeSemanticAnalyzer analyzer;
     try {
-      analyzer = new CubeSemanticAnalyzer(conf, hconf);
+      analyzer = new CubeSemanticAnalyzer(hconf);
       analyzer.analyze(astnode, qlCtx);
     } catch (SemanticException e) {
       throw new LensException(SYNTAX_ERROR.getLensErrorInfo(), e, 
e.getMessage());

http://git-wip-us.apache.org/repos/asf/lens/blob/2aaf6e0a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeSemanticAnalyzer.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeSemanticAnalyzer.java 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeSemanticAnalyzer.java
index fc96055..0e2ca82 100644
--- 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeSemanticAnalyzer.java
+++ 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeSemanticAnalyzer.java
@@ -33,16 +33,12 @@ import lombok.Getter;
  * Accepts cube query AST and rewrites into storage table query
  */
 public class CubeSemanticAnalyzer extends SemanticAnalyzer {
-  private final Configuration queryConf;
-  private final HiveConf hiveConf;
-  private final List<ValidationRule> validationRules = new 
ArrayList<ValidationRule>();
+  private final List<ValidationRule> validationRules = new ArrayList<>();
   @Getter
   private QB cubeQB;
 
-  public CubeSemanticAnalyzer(Configuration queryConf, HiveConf hiveConf) 
throws SemanticException {
+  public CubeSemanticAnalyzer(HiveConf hiveConf) throws SemanticException {
     super(new QueryState(hiveConf));
-    this.queryConf = queryConf;
-    this.hiveConf = hiveConf;
     setupRules();
   }
 
@@ -65,10 +61,6 @@ public class CubeSemanticAnalyzer extends SemanticAnalyzer {
         ast.deleteChild(ast.getChildCount() - 1);
       }
     }
-    // analyzing from the ASTNode.
-    if (!doPhase1(ast, cubeQB, initPhase1Ctx(), null)) {
-      // if phase1Result false return
-      return;
-    }
+    doPhase1(ast, cubeQB, initPhase1Ctx(), null);
   }
 }

http://git-wip-us.apache.org/repos/asf/lens/blob/2aaf6e0a/lens-cube/src/main/java/org/apache/lens/cube/parse/DenormalizationResolver.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/DenormalizationResolver.java
 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/DenormalizationResolver.java
index bb29034..bcea7ed 100644
--- 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/DenormalizationResolver.java
+++ 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/DenormalizationResolver.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -20,18 +20,17 @@ package org.apache.lens.cube.parse;
 
 import static org.apache.hadoop.hive.ql.parse.HiveParser.Identifier;
 import static org.apache.hadoop.hive.ql.parse.HiveParser.TOK_TABLE_OR_COL;
+import static 
org.apache.lens.cube.parse.CandidateTablePruneCause.denormColumnNotFound;
 
 import java.util.*;
 
 import org.apache.lens.cube.error.LensCubeErrorCode;
 import org.apache.lens.cube.metadata.*;
 import org.apache.lens.cube.metadata.ReferencedDimAttribute.ChainRefCol;
-import 
org.apache.lens.cube.parse.CandidateTablePruneCause.CandidateTablePruneCode;
 import org.apache.lens.cube.parse.ExpressionResolver.ExprSpecContext;
 import org.apache.lens.cube.parse.ExpressionResolver.ExpressionContext;
 import org.apache.lens.server.api.error.LensException;
 
-import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hive.ql.parse.ASTNode;
 import org.apache.hadoop.hive.ql.parse.HiveParser;
 
@@ -50,11 +49,8 @@ import lombok.extern.slf4j.Slf4j;
 @Slf4j
 public class DenormalizationResolver implements ContextRewriter {
 
-  public DenormalizationResolver(Configuration conf) {
-  }
-
   @ToString
-  public static class ReferencedQueriedColumn {
+  static class ReferencedQueriedColumn {
     ReferencedDimAttribute col;
     AbstractCubeTable srcTable;
     transient List<ChainRefCol> chainRefCols = new ArrayList<>();
@@ -67,17 +63,12 @@ public class DenormalizationResolver implements 
ContextRewriter {
   }
 
   @ToString
-  public static class PickedReference {
+  static class PickedReference {
     @Getter
     ChainRefCol chainRef;
     String srcAlias;
     String pickedFor;
 
-    PickedReference(String srcAlias, String pickedFor) {
-      this.srcAlias = srcAlias;
-      this.pickedFor = pickedFor;
-    }
-
     PickedReference(ChainRefCol chainRef, String srcAlias, String pickedFor) {
       this.srcAlias = srcAlias;
       this.chainRef = chainRef;
@@ -85,38 +76,29 @@ public class DenormalizationResolver implements 
ContextRewriter {
     }
   }
 
-  public static class DenormalizationContext {
+  static class DenormalizationContext {
     // map of column name to all references
+    @Getter
     private Map<String, Set<ReferencedQueriedColumn>> referencedCols = new 
HashMap<>();
 
     // candidate table name to all the references columns it needs
+    @Getter
     private Map<String, Set<ReferencedQueriedColumn>> tableToRefCols = new 
HashMap<>();
 
-    private CubeQueryContext cubeql;
-
     // set of all picked references once all candidate tables are picked
     private Set<PickedReference> pickedRefs = new HashSet<>();
     // index on column name for picked references with map from column name to
     // pickedrefs
     private Map<String, Set<PickedReference>> pickedReferences = new 
HashMap<>();
 
-    DenormalizationContext(CubeQueryContext cubeql) {
-      this.cubeql = cubeql;
-    }
-
     void addReferencedCol(String col, ReferencedQueriedColumn refer) {
-      Set<ReferencedQueriedColumn> refCols = referencedCols.get(col);
-      if (refCols == null) {
-        refCols = new HashSet<>();
-        referencedCols.put(col, refCols);
-      }
-      refCols.add(refer);
+      referencedCols.computeIfAbsent(col, k -> new HashSet<>()).add(refer);
     }
 
     // When candidate table does not have the field, this method checks
     // if the field can be reached through reference,
     // if yes adds the ref usage and returns to true, if not returns false.
-    boolean addRefUsage(CandidateTable table, String col, String srcTbl) 
throws LensException {
+    boolean addRefUsage(CubeQueryContext cubeql, CandidateTable table, String 
col, String srcTbl) throws LensException {
       // available as referenced col
       if (referencedCols.containsKey(col)) {
         for (ReferencedQueriedColumn refer : referencedCols.get(col)) {
@@ -126,12 +108,7 @@ public class DenormalizationResolver implements 
ContextRewriter {
             // there is no path
             // to the source table
             log.info("Adding denormalized column for column:{} for table:{}", 
col, table);
-            Set<ReferencedQueriedColumn> refCols = 
tableToRefCols.get(table.getName());
-            if (refCols == null) {
-              refCols = new HashSet<>();
-              tableToRefCols.put(table.getName(), refCols);
-            }
-            refCols.add(refer);
+            tableToRefCols.computeIfAbsent(table.getName(), k -> new 
HashSet<>()).add(refer);
             // Add to optional tables
             for (ChainRefCol refCol : refer.col.getChainRefColumns()) {
               cubeql.addOptionalDimTable(refCol.getChainName(), table, false, 
refer.col.getName(), true,
@@ -144,17 +121,8 @@ public class DenormalizationResolver implements 
ContextRewriter {
       return false;
     }
 
-    Map<String, Set<ReferencedQueriedColumn>> getReferencedCols() {
-      return referencedCols;
-    }
-
     private void addPickedReference(String col, PickedReference refer) {
-      Set<PickedReference> refCols = pickedReferences.get(col);
-      if (refCols == null) {
-        refCols = new HashSet<>();
-        pickedReferences.put(col, refCols);
-      }
-      refCols.add(refer);
+      pickedReferences.computeIfAbsent(col, k -> new HashSet<>()).add(refer);
     }
 
     private PickedReference getPickedReference(String col, String srcAlias) {
@@ -169,24 +137,23 @@ public class DenormalizationResolver implements 
ContextRewriter {
       return null;
     }
 
-    public Set<Dimension> rewriteDenormctx(StorageCandidate sc, Map<Dimension, 
CandidateDim> dimsToQuery,
-      boolean replaceFact) throws LensException {
+    Set<Dimension> rewriteDenormctx(CubeQueryContext cubeql,
+      StorageCandidate sc, Map<Dimension, CandidateDim> dimsToQuery, boolean 
replaceFact) throws LensException {
       Set<Dimension> refTbls = new HashSet<>();
 
       if (!tableToRefCols.isEmpty()) {
         // pick referenced columns for fact
         if (sc != null) {
-          pickColumnsForTable(sc.getName());
+          pickColumnsForTable(cubeql, sc.getName());
         }
         // pick referenced columns for dimensions
-        if (dimsToQuery != null && !dimsToQuery.isEmpty()) {
+        if (dimsToQuery != null) {
           for (CandidateDim cdim : dimsToQuery.values()) {
-            pickColumnsForTable(cdim.getName());
+            pickColumnsForTable(cubeql, cdim.getName());
           }
         }
         // Replace picked reference in all the base trees
-        replaceReferencedColumns(sc, replaceFact);
-
+        replaceReferencedColumns(cubeql, sc, replaceFact);
         // Add the picked references to dimsToQuery
         for (PickedReference picked : pickedRefs) {
           if (isPickedFor(picked, sc, dimsToQuery)) {
@@ -195,9 +162,43 @@ public class DenormalizationResolver implements 
ContextRewriter {
           }
         }
       }
+      pickedReferences.clear();
+      pickedRefs.clear();
       return refTbls;
     }
 
+    boolean hasReferences() {
+      return !tableToRefCols.isEmpty();
+    }
+    Set<Dimension> rewriteDenormctxInExpression(CubeQueryContext cubeql, 
StorageCandidate sc, Map<Dimension,
+      CandidateDim> dimsToQuery, ASTNode exprAST) throws LensException {
+      Set<Dimension> refTbls = new HashSet<>();
+      if (!tableToRefCols.isEmpty()) {
+        // pick referenced columns for fact
+        if (sc != null) {
+          pickColumnsForTable(cubeql, sc.getName());
+        }
+        // pick referenced columns for dimensions
+        if (dimsToQuery != null) {
+          for (CandidateDim cdim : dimsToQuery.values()) {
+            pickColumnsForTable(cubeql, cdim.getName());
+          }
+        }
+        // Replace picked reference in expression ast
+        resolveClause(exprAST);
+
+        // Add the picked references to dimsToQuery
+        for (PickedReference picked : pickedRefs) {
+          if (isPickedFor(picked, sc, dimsToQuery)) {
+            refTbls.add((Dimension) 
cubeql.getCubeTableForAlias(picked.getChainRef().getChainName()));
+            cubeql.addColumnsQueried(picked.getChainRef().getChainName(), 
picked.getChainRef().getRefColumn());
+          }
+        }
+      }
+      pickedReferences.clear();
+      pickedRefs.clear();
+      return refTbls;
+    }
     // checks if the reference if picked for facts and dimsToQuery passed
     private boolean isPickedFor(PickedReference picked, StorageCandidate sc, 
Map<Dimension, CandidateDim> dimsToQuery) {
       if (sc != null && picked.pickedFor.equalsIgnoreCase(sc.getName())) {
@@ -213,18 +214,12 @@ public class DenormalizationResolver implements 
ContextRewriter {
       return false;
     }
 
-    private void pickColumnsForTable(String tbl) throws LensException {
+    private void pickColumnsForTable(CubeQueryContext cubeql, String tbl) 
throws LensException {
       if (tableToRefCols.containsKey(tbl)) {
         for (ReferencedQueriedColumn refered : tableToRefCols.get(tbl)) {
-          Iterator<ChainRefCol> iter = refered.chainRefCols.iterator();
-          while (iter.hasNext()) {
-            // remove unreachable references
-            ChainRefCol reference = iter.next();
-            if (!cubeql.getAutoJoinCtx().isReachableDim(
-              (Dimension) 
cubeql.getCubeTableForAlias(reference.getChainName()), 
reference.getChainName())) {
-              iter.remove();
-            }
-          }
+          // remove unreachable references
+          refered.chainRefCols.removeIf(reference -> 
!cubeql.getAutoJoinCtx().isReachableDim(
+            (Dimension) cubeql.getCubeTableForAlias(reference.getChainName()), 
reference.getChainName()));
           if (refered.chainRefCols.isEmpty()) {
             throw new 
LensException(LensCubeErrorCode.NO_REF_COL_AVAILABLE.getLensErrorInfo(), 
refered.col.getName());
           }
@@ -236,26 +231,55 @@ public class DenormalizationResolver implements 
ContextRewriter {
         }
       }
     }
+    void pruneReferences(CubeQueryContext cubeql) {
+      for (Set<ReferencedQueriedColumn> referencedQueriedColumns : 
referencedCols.values()) {
+        for(Iterator<ReferencedQueriedColumn> iterator = 
referencedQueriedColumns.iterator(); iterator.hasNext();) {
+          ReferencedQueriedColumn rqc = iterator.next();
+          for (Iterator<ChainRefCol> iter = rqc.chainRefCols.iterator(); 
iter.hasNext();) {
+            // remove unreachable references
+            ChainRefCol reference = iter.next();
+            if (cubeql.getAutoJoinCtx() == null || 
!cubeql.getAutoJoinCtx().isReachableDim(
+              (Dimension) 
cubeql.getCubeTableForAlias(reference.getChainName()), 
reference.getChainName())) {
+              log.info("{} is not reachable", reference.getChainName());
+              iter.remove();
+            }
+          }
+          if (rqc.chainRefCols.isEmpty()) {
+            log.info("The referenced column: {} is not reachable", 
rqc.col.getName());
+            iterator.remove();
+            continue;
+          }
+          // do column life validation
+          for (TimeRange range : cubeql.getTimeRanges()) {
+            if (!rqc.col.isColumnAvailableInTimeRange(range)) {
+              log.info("The referenced column: {} is not in the range 
queried", rqc.col.getName());
+              iterator.remove();
+              break;
+            }
+          }
+        }
+      }
+    }
 
-    private void replaceReferencedColumns(StorageCandidate sc, boolean 
replaceFact) throws LensException {
+    private void replaceReferencedColumns(CubeQueryContext cubeql, 
StorageCandidate sc, boolean replaceFact) throws LensException {
       QueryAST ast = cubeql;
       boolean factRefExists = sc != null && tableToRefCols.get(sc.getName()) 
!= null && !tableToRefCols.get(sc
           .getName()).isEmpty();
       if (replaceFact && factRefExists) {
         ast = sc.getQueryAst();
       }
-      resolveClause(cubeql, ast.getSelectAST());
+      resolveClause(ast.getSelectAST());
       if (factRefExists) {
-        resolveClause(cubeql, sc.getQueryAst().getWhereAST());
+        resolveClause(sc.getQueryAst().getWhereAST());
       } else {
-        resolveClause(cubeql, ast.getWhereAST());
+        resolveClause(ast.getWhereAST());
       }
-      resolveClause(cubeql, ast.getGroupByAST());
-      resolveClause(cubeql, ast.getHavingAST());
-      resolveClause(cubeql, cubeql.getOrderByAST());
+      resolveClause(ast.getGroupByAST());
+      resolveClause(ast.getHavingAST());
+      resolveClause(cubeql.getOrderByAST());
     }
 
-    private void resolveClause(CubeQueryContext query, ASTNode node) throws 
LensException {
+    private void resolveClause(ASTNode node) throws LensException {
       if (node == null) {
         return;
       }
@@ -271,6 +295,7 @@ public class DenormalizationResolver implements 
ContextRewriter {
         ASTNode tableNode = (ASTNode) node.getChild(0);
         ASTNode tabident = HQLParser.findNodeByPath(node, TOK_TABLE_OR_COL, 
Identifier);
 
+        assert tabident != null;
         PickedReference refered = getPickedReference(colName, 
tabident.getText().toLowerCase());
         if (refered == null) {
           return;
@@ -286,16 +311,29 @@ public class DenormalizationResolver implements 
ContextRewriter {
         // recurse down
         for (int i = 0; i < node.getChildCount(); i++) {
           ASTNode child = (ASTNode) node.getChild(i);
-          resolveClause(query, child);
+          resolveClause(child);
+        }
+      }
+    }
+
+    Set<String> getNonReachableReferenceFields(String table) {
+      Set<String> nonReachableFields = new HashSet<>();
+      if (tableToRefCols.containsKey(table)) {
+        for (ReferencedQueriedColumn refcol : tableToRefCols.get(table)) {
+          if (getReferencedCols().get(refcol.col.getName()).isEmpty()) {
+            log.info("For table:{}, the column {} is not available", table, 
refcol.col);
+            nonReachableFields.add(refcol.col.getName());
+          }
         }
       }
+      return nonReachableFields;
     }
   }
 
   private void addRefColsQueried(CubeQueryContext cubeql, TrackQueriedColumns 
tqc, DenormalizationContext denormCtx) {
     for (Map.Entry<String, Set<String>> entry : 
tqc.getTblAliasToColumns().entrySet()) {
       // skip default alias
-      if (entry.getKey() == CubeQueryContext.DEFAULT_TABLE) {
+      if (Objects.equals(entry.getKey(), CubeQueryContext.DEFAULT_TABLE)) {
         continue;
       }
       // skip join chain aliases
@@ -318,6 +356,14 @@ public class DenormalizationResolver implements 
ContextRewriter {
       }
     }
   }
+  private static DenormalizationContext 
getOrCreateDeNormCtx(TrackDenormContext tdc) {
+    DenormalizationContext denormCtx = tdc.getDeNormCtx();
+    if (denormCtx == null) {
+      denormCtx = new DenormalizationContext();
+      tdc.setDeNormCtx(denormCtx);
+    }
+    return denormCtx;
+  }
   /**
    * Find all de-normalized columns, if these columns are not directly 
available in candidate tables, query will be
    * replaced with the corresponding table reference
@@ -326,38 +372,32 @@ public class DenormalizationResolver implements 
ContextRewriter {
   public void rewriteContext(CubeQueryContext cubeql) throws LensException {
     DenormalizationContext denormCtx = cubeql.getDeNormCtx();
     if (denormCtx == null) {
+      DenormalizationContext ctx = getOrCreateDeNormCtx(cubeql);
       // Adds all the reference dimensions as eligible for denorm fields
-      denormCtx = new DenormalizationContext(cubeql);
-      cubeql.setDeNormCtx(denormCtx);
       // add ref columns in cube
-      addRefColsQueried(cubeql, cubeql, denormCtx);
+      addRefColsQueried(cubeql, cubeql, ctx);
       // add ref columns from expressions
       for (Set<ExpressionContext> ecSet : 
cubeql.getExprCtx().getAllExprsQueried().values()) {
         for (ExpressionContext ec : ecSet) {
           for (ExprSpecContext esc : ec.getAllExprs()) {
-            addRefColsQueried(cubeql, esc, denormCtx);
+            addRefColsQueried(cubeql, esc, getOrCreateDeNormCtx(esc));
           }
         }
       }
     } else if (!denormCtx.tableToRefCols.isEmpty()) {
+      denormCtx.pruneReferences(cubeql);
       // In the second iteration of denorm resolver
       // candidate tables which require denorm fields and the refernces are no
       // more valid will be pruned
       if (cubeql.getCube() != null && !cubeql.getCandidates().isEmpty()) {
         for (Iterator<StorageCandidate> i =
              
CandidateUtil.getStorageCandidates(cubeql.getCandidates()).iterator(); 
i.hasNext();) {
-          StorageCandidate sc = i.next();
-          if (denormCtx.tableToRefCols.containsKey(sc.getFact().getName())) {
-            for (ReferencedQueriedColumn refcol : 
denormCtx.tableToRefCols.get(sc.getFact().getName())) {
-              if 
(denormCtx.getReferencedCols().get(refcol.col.getName()).isEmpty()) {
-                log.info("Not considering storage candidate :{} as column {} 
is not available", sc, refcol.col);
-                cubeql.addStoragePruningMsg(sc, 
CandidateTablePruneCause.columnNotFound(
-                    CandidateTablePruneCode.DENORM_COLUMN_NOT_FOUND, 
refcol.col.getName()));
-                Collection<Candidate> prunedCandidates = 
CandidateUtil.filterCandidates(cubeql.getCandidates(), sc);
-                cubeql.addCandidatePruningMsg(prunedCandidates,
-                    new 
CandidateTablePruneCause(CandidateTablePruneCode.ELEMENT_IN_SET_PRUNED));
-              }
-            }
+          StorageCandidate candidate = i.next();
+          Set<String> nonReachableFields = 
denormCtx.getNonReachableReferenceFields(candidate.getName());
+          if (!nonReachableFields.isEmpty()) {
+            log.info("Not considering fact table:{} as columns {} are not 
available", candidate, nonReachableFields);
+            cubeql.addCandidatePruningMsg(candidate, 
denormColumnNotFound(nonReachableFields));
+            i.remove();
           }
         }
         if (cubeql.getCandidates().size() == 0) {
@@ -370,16 +410,11 @@ public class DenormalizationResolver implements 
ContextRewriter {
         for (Dimension dim : cubeql.getDimensions()) {
           for (Iterator<CandidateDim> i = 
cubeql.getCandidateDimTables().get(dim).iterator(); i.hasNext();) {
             CandidateDim cdim = i.next();
-            if (denormCtx.tableToRefCols.containsKey(cdim.getName())) {
-              for (ReferencedQueriedColumn refcol : 
denormCtx.tableToRefCols.get(cdim.getName())) {
-                if 
(denormCtx.getReferencedCols().get(refcol.col.getName()).isEmpty()) {
-                  log.info("Not considering dim table:{} as column {} is not 
available", cdim, refcol.col);
-                  cubeql.addDimPruningMsgs(dim, cdim.dimtable,
-                    
CandidateTablePruneCause.columnNotFound(CandidateTablePruneCode.DENORM_COLUMN_NOT_FOUND,
-                        refcol.col.getName()));
-                  i.remove();
-                }
-              }
+            Set<String> nonReachableFields = 
denormCtx.getNonReachableReferenceFields(cdim.getName());
+            if (!nonReachableFields.isEmpty()) {
+              log.info("Not considering dim table:{} as column {} is not 
available", cdim, nonReachableFields);
+              cubeql.addDimPruningMsgs(dim, cdim.dimtable, 
denormColumnNotFound(nonReachableFields));
+              i.remove();
             }
           }
 

Reply via email to