private void resolveColumnsAndReplaceAlias(CubeQueryContext cubeql, Set<ExprSpecContext> exprs)
     throws SemanticException {
   Set<ExprSpecContext> nestedExpressions = new LinkedHashSet<ExprSpecContext>();
   for (ExprSpecContext esc : exprs) {
     for (Map.Entry<String, Set<String>> entry : esc.getTblAliasToColumns().entrySet()) {
       if (entry.getKey().equals(CubeQueryContext.DEFAULT_TABLE)) {
         continue;
       }
       AbstractBaseTable baseTable =
           (AbstractBaseTable) cubeql.getCubeTableForAlias(entry.getKey());
       Set<String> exprCols = new HashSet<String>();
       for (String col : entry.getValue()) {
         // col is an expression
         if (baseTable.getExpressionNames().contains(col)) {
           exprCols.add(col);
         }
       }
       // get all combinations of expression replaced with inner exprs AST.
       addAllNestedExpressions(cubeql, esc, baseTable, nestedExpressions, exprCols);
     }
   }
   for (ExprSpecContext esc : nestedExpressions) {
     esc.resolveColumns(cubeql);
     esc.replaceAliasInAST(cubeql);
     for (String table : esc.getTblAliasToColumns().keySet()) {
       try {
         if (!CubeQueryContext.DEFAULT_TABLE.equalsIgnoreCase(table)
             && !srcAlias.equals(table)) {
           cubeql.addOptionalDimTable(
               table,
               null,
               false,
               null,
               false,
               esc.getTblAliasToColumns().get(table).toArray(new String[0]));
           esc.exprDims.add((Dimension) cubeql.getCubeTableForAlias(table));
         }
       } catch (HiveException e) {
         throw new SemanticException(e);
       }
     }
   }
   exprs.addAll(nestedExpressions);
 }
 private void addAllNestedExpressions(
     CubeQueryContext cubeql,
     ExprSpecContext baseEsc,
     AbstractBaseTable baseTable,
     Set<ExprSpecContext> nestedExpressions,
     Set<String> exprCols)
     throws SemanticException {
   for (String col : exprCols) {
     Set<ExprSpecContext> replacedExpressions = new LinkedHashSet<ExprSpecContext>();
     for (ExprSpec es : baseTable.getExpressionByName(col).getExpressionSpecs()) {
       ASTNode finalAST = HQLParser.copyAST(baseEsc.getFinalAST());
       replaceColumnInAST(finalAST, col, es.getASTNode());
       ExprSpecContext replacedESC = new ExprSpecContext(baseEsc, es, finalAST, cubeql);
       nestedExpressions.add(replacedESC);
       replacedExpressions.add(replacedESC);
     }
     Set<String> remaining = new LinkedHashSet<String>(exprCols);
     remaining.remove(col);
     for (ExprSpecContext replacedESC : replacedExpressions) {
       addAllNestedExpressions(cubeql, replacedESC, baseTable, nestedExpressions, remaining);
     }
   }
 }
 void pruneExpressions() {
   for (Set<ExpressionContext> ecSet : allExprsQueried.values()) {
     for (ExpressionContext ec : ecSet) {
       Set<ExprSpecContext> removedEsc = new HashSet<ExprSpecContext>();
       for (Iterator<ExprSpecContext> iterator = ec.getAllExprs().iterator();
           iterator.hasNext(); ) {
         ExprSpecContext esc = iterator.next();
         boolean removed = false;
         // Go over expression dims and remove expression involving dimensions for which
         // candidate tables are
         // not there
         for (Dimension exprDim : esc.exprDims) {
           if (cubeql.getCandidateDims().get(exprDim) == null
               || cubeql.getCandidateDims().get(exprDim).isEmpty()) {
             log.info(
                 "Removing expression {} as {} it does not have any candidate tables",
                 esc,
                 exprDim);
             iterator.remove();
             removedEsc.add(esc);
             removed = true;
             break;
           }
         }
         if (removed) {
           continue;
         }
         // remove expressions which are not valid in the timerange queried
         // If an expression is defined as
         // ex = a + b // from t1 to t2;
         // ex = c + d // from t2 to t3
         // With range queried, invalid expressions will be removed
         // If range is including more than one expression, queries can be unioned as an
         // improvement at later time.
         // But for now, they are not eligible expressions
         for (TimeRange range : cubeql.getTimeRanges()) {
           if (!esc.isValidInTimeRange(range)) {
             log.info("Removing expression {} as it is not valid in timerange queried", esc);
             iterator.remove();
             removedEsc.add(esc);
             removed = true;
             break;
           }
         }
         if (removed) {
           continue;
         }
         // Go over expressions and remove expression containing unavailable columns in timerange
         // In the example above,
         // if ex = a +b ; and a is not available in timerange queried, it will be removed.
         for (TimeRange range : cubeql.getTimeRanges()) {
           boolean toRemove = false;
           for (Map.Entry<String, Set<String>> entry : esc.getTblAliasToColumns().entrySet()) {
             if (CubeQueryContext.DEFAULT_TABLE.equalsIgnoreCase(entry.getKey())) {
               continue;
             }
             AbstractBaseTable baseTable =
                 (AbstractBaseTable) cubeql.getCubeTableForAlias(entry.getKey());
             for (String col : entry.getValue()) {
               if (!baseTable.getColumnByName(col).isColumnAvailableInTimeRange(range)) {
                 toRemove = true;
                 break;
               }
             }
             if (toRemove) {
               break;
             }
           }
           if (toRemove) {
             log.info(
                 "Removing expression {} as its columns are unavailable in timerange queried",
                 esc);
             iterator.remove();
             removedEsc.add(esc);
             removed = true;
             break;
           }
         }
       }
       for (Set<ExprSpecContext> evalSet : ec.evaluableExpressions.values()) {
         evalSet.removeAll(removedEsc);
       }
     }
   }
 }