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) {
       continue;
     }
     // skip join chain aliases
     if (cubeql.getJoinchains().keySet().contains(entry.getKey().toLowerCase())) {
       continue;
     }
     AbstractCubeTable tbl = cubeql.getCubeTableForAlias(entry.getKey());
     Set<String> columns = entry.getValue();
     for (String column : columns) {
       CubeColumn col;
       if (tbl instanceof CubeInterface) {
         col = ((CubeInterface) tbl).getColumnByName(column);
       } else {
         col = ((Dimension) tbl).getColumnByName(column);
       }
       if (col instanceof ReferencedDimAttribute) {
         // considering all referenced dimensions to be denormalized columns
         denormCtx.addReferencedCol(
             column, new ReferencedQueriedColumn((ReferencedDimAttribute) col, tbl));
       }
     }
   }
 }
  /**
   * Find all de-normalized columns, if these columns are not directly available in candidate
   * tables, query will be replaced with the corresponding table reference
   */
  @Override
  public void rewriteContext(CubeQueryContext cubeql) throws LensException {
    DenormalizationContext denormCtx = cubeql.getDeNormCtx();
    if (denormCtx == null) {
      // 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);
      // 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);
          }
        }
      }
    } else if (!denormCtx.tableToRefCols.isEmpty()) {
      // 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.getCandidateFacts().isEmpty()) {
        for (Iterator<CandidateFact> i = cubeql.getCandidateFacts().iterator(); i.hasNext(); ) {
          CandidateFact cfact = i.next();
          if (denormCtx.tableToRefCols.containsKey(cfact.getName())) {
            for (ReferencedQueriedColumn refcol : denormCtx.tableToRefCols.get(cfact.getName())) {
              if (denormCtx.getReferencedCols().get(refcol.col.getName()).isEmpty()) {
                log.info(
                    "Not considering fact table:{} as column {} is not available",
                    cfact,
                    refcol.col);
                cubeql.addFactPruningMsgs(
                    cfact.fact, CandidateTablePruneCause.columnNotFound(refcol.col.getName()));
                i.remove();
              }
            }
          }
        }
        if (cubeql.getCandidateFacts().size() == 0) {
          throw new LensException(
              LensCubeErrorCode.NO_FACT_HAS_COLUMN.getLensErrorInfo(),
              cubeql.getColumnsQueried(cubeql.getCube().getName()).toString());
        }
        cubeql.pruneCandidateFactSet(CandidateTablePruneCode.COLUMN_NOT_FOUND);
      }
      if (cubeql.getDimensions() != null && !cubeql.getDimensions().isEmpty()) {
        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(refcol.col.getName()));
                  i.remove();
                }
              }
            }
          }

          if (cubeql.getCandidateDimTables().get(dim).size() == 0) {
            throw new LensException(
                LensCubeErrorCode.NO_DIM_HAS_COLUMN.getLensErrorInfo(),
                dim.toString(),
                cubeql.getColumnsQueried(dim.getName()).toString());
          }
        }
      }
    }
  }