Repository: incubator-lens
Updated Branches:
  refs/heads/master c8d38f7cf -> f1387c315


LENS-647 : Fix multi fact query with expressions


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

Branch: refs/heads/master
Commit: f1387c31537eb7f73ba2de503e7a17120df1e691
Parents: c8d38f7
Author: Amareshwari Sriramadasu <[email protected]>
Authored: Fri Jul 10 12:19:10 2015 +0530
Committer: Amareshwari Sriramadasu <[email protected]>
Committed: Fri Jul 10 12:19:10 2015 +0530

----------------------------------------------------------------------
 .../apache/lens/cube/parse/CandidateFact.java   |  10 +-
 .../cube/parse/CandidateTablePruneCause.java    |   9 +-
 .../lens/cube/parse/CubeQueryContext.java       |   4 +-
 .../lens/cube/parse/ExpressionResolver.java     |  65 ++++---
 .../lens/cube/parse/TestBaseCubeQueries.java    | 171 +++++++++++++------
 5 files changed, 174 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java
index 63d2508..86c420b 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java
@@ -190,10 +190,10 @@ public class CandidateFact implements CandidateTable {
     int currentChild = 0;
     for (int i = 0; i < cubeql.getSelectAST().getChildCount(); i++) {
       ASTNode selectExpr = (ASTNode) this.selectAST.getChild(currentChild);
-      Set<String> exprCols = getColsInExpr(cubeCols, selectExpr);
+      Set<String> exprCols = getColsInExpr(cubeql, cubeCols, selectExpr);
       if (getColumns().containsAll(exprCols)) {
         selectIndices.add(i);
-        if (cubeql.getQueriedDimAttrs().containsAll(exprCols)) {
+        if (cubeql.getCube().getDimAttributeNames().containsAll(exprCols)) {
           dimFieldIndices.add(i);
         }
         ASTNode aliasNode = HQLParser.findNodeByPath(selectExpr, Identifier);
@@ -225,7 +225,8 @@ public class CandidateFact implements CandidateTable {
     // TODO
   }
 
-  private Set<String> getColsInExpr(final Set<String> cubeCols, ASTNode expr) 
throws SemanticException {
+  private Set<String> getColsInExpr(final CubeQueryContext cubeql, final 
Set<String> cubeCols,
+    ASTNode expr) throws SemanticException {
     final Set<String> cubeColsInExpr = new HashSet<String>();
     HQLParser.bft(expr, new ASTNodeVisitor() {
       @Override
@@ -244,9 +245,10 @@ public class CandidateFact implements CandidateTable {
             cubeColsInExpr.add(column);
           }
         } else if (node.getToken().getType() == DOT) {
+          String alias = HQLParser.findNodeByPath(node, TOK_TABLE_OR_COL, 
Identifier).getText().toLowerCase();
           ASTNode colIdent = (ASTNode) node.getChild(1);
           String column = colIdent.getText().toLowerCase();
-          if (cubeCols.contains(column)) {
+          if 
(cubeql.getAliasForTableName(cubeql.getCube()).equalsIgnoreCase(alias) && 
cubeCols.contains(column)) {
             cubeColsInExpr.add(column);
           }
         }

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java
 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java
index 75d5581..9ea43bb 100644
--- 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java
+++ 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java
@@ -36,10 +36,11 @@ import lombok.NoArgsConstructor;
 @JsonWriteNullProperties(false)
 @Data
 @NoArgsConstructor
-
 public class CandidateTablePruneCause {
 
   public enum CandidateTablePruneCode {
+    // other fact set element is removed
+    ELEMENT_IN_SET_PRUNED("Other candidate from measure covering set is 
pruned"),
     FACT_NOT_AVAILABLE_IN_RANGE("No facts available for all of these time 
ranges: %s") {
       @Override
       Object[] getFormatPlaceholders(Set<CandidateTablePruneCause> causes) {
@@ -70,6 +71,9 @@ public class CandidateTablePruneCause {
         return new String[]{columns.toString()};
       }
     },
+    // candidate table tries to get denormalized field from dimension and the
+    // referred dimension is invalid.
+    INVALID_DENORM_TABLE("Referred dimension is invalid in one of the 
candidate tables"),
     // column not valid in cube table
     COLUMN_NOT_VALID("Column not valid in cube table"),
     // column not found in cube table
@@ -92,9 +96,6 @@ public class CandidateTablePruneCause {
         }
       }
     },
-    // candidate table tries to get denormalized field from dimension and the
-    // referred dimension is invalid.
-    INVALID_DENORM_TABLE("Referred dimension is invalid in one of the 
candidate tables"),
     // missing storage tables for cube table
     MISSING_STORAGES("Missing storage tables for the cube table"),
     // no candidate storges for cube table, storage cause will have why each

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/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 57c075c..39b13cc 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
@@ -1196,10 +1196,12 @@ public class CubeQueryContext implements 
TrackQueriedColumns {
       Set<CandidateFact> cfacts = i.next();
       if (!candidateFacts.containsAll(cfacts)) {
         LOG.info("Not considering fact table set:" + cfacts
-          + " as they have non candidate tables and facts missing because of" 
+ pruneCause);
+          + " as they have non candidate tables and facts missing because of " 
+ pruneCause);
         i.remove();
       }
     }
+    // prune candidate facts
+    
pruneCandidateFactWithCandidateSet(CandidateTablePruneCode.ELEMENT_IN_SET_PRUNED);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java 
b/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java
index b2997dd..895cb06 100644
--- a/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java
+++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java
@@ -32,6 +32,7 @@ import org.apache.lens.cube.metadata.CubeInterface;
 import org.apache.lens.cube.metadata.Dimension;
 import org.apache.lens.cube.metadata.ExprColumn;
 import org.apache.lens.cube.metadata.ExprColumn.ExprSpec;
+import 
org.apache.lens.cube.parse.CandidateTablePruneCause.CandidateTablePruneCode;
 import org.apache.lens.cube.parse.HQLParser.ASTNodeVisitor;
 import org.apache.lens.cube.parse.HQLParser.TreeNode;
 
@@ -204,6 +205,16 @@ class ExpressionResolver implements ContextRewriter {
       }
       return false;
     }
+
+    boolean isEvaluable(CandidateTable cTable) {
+      if (directlyAvailableIn.contains(cTable)) {
+        return true;
+      }
+      if (evaluableExpressions.get(cTable) == null) {
+        return false;
+      }
+      return !evaluableExpressions.get(cTable).isEmpty();
+    }
   }
 
   static class ExprSpecContext implements TrackQueriedColumns {
@@ -395,13 +406,7 @@ class ExpressionResolver implements ContextRewriter {
     // checks if expr is evaluable
     public boolean isEvaluable(String expr, CandidateTable cTable) {
       ExpressionContext ec = getExpressionContext(expr, 
cubeql.getAliasForTableName(cTable.getBaseTable().getName()));
-      if (ec.directlyAvailableIn.contains(cTable)) {
-        return true;
-      }
-      if (ec.evaluableExpressions.get(cTable) == null) {
-        return false;
-      }
-      return !ec.evaluableExpressions.get(cTable).isEmpty();
+      return ec.isEvaluable(cTable);
     }
 
     /**
@@ -671,24 +676,40 @@ class ExpressionResolver implements ContextRewriter {
       cubeql.getExprCtx().pruneExpressions();
       // prune candidate facts without any valid expressions
       if (cubeql.getCube() != null && !cubeql.getCandidateFacts().isEmpty()) {
-        for (Iterator<CandidateFact> i = 
cubeql.getCandidateFacts().iterator(); i.hasNext();) {
-          CandidateFact cfact = i.next();
-          for (Map.Entry<String, Set<ExpressionContext>> ecEntry : 
exprCtx.allExprsQueried.entrySet()) {
-            Set<ExpressionContext> ecSet = ecEntry.getValue();
-            for (ExpressionContext ec : ecSet) {
-              if 
(ec.getSrcTable().getName().equals(cfact.getBaseTable().getName())) {
-                if (!ec.directlyAvailableIn.contains(cfact)
-                  && (ec.evaluableExpressions.get(cfact) == null
-                  || ec.evaluableExpressions.get(cfact).isEmpty())) {
-                  log.info("Not considering fact table:{} as {} is not 
evaluable", cfact, ec.exprCol.getName());
-                  cubeql.addFactPruningMsgs(cfact.fact,
-                    
CandidateTablePruneCause.expressionNotEvaluable(ec.exprCol.getName()));
-                  i.remove();
+        for (Map.Entry<String, Set<ExpressionContext>> ecEntry : 
exprCtx.allExprsQueried.entrySet()) {
+          String expr = ecEntry.getKey();
+          Set<ExpressionContext> ecSet = ecEntry.getValue();
+          for (ExpressionContext ec : ecSet) {
+            if (ec.getSrcTable().getName().equals(cubeql.getCube().getName())) 
{
+              if (cubeql.getQueriedExprsWithMeasures().contains(expr)) {
+                for (Iterator<Set<CandidateFact>> sItr = 
cubeql.getCandidateFactSets().iterator(); sItr.hasNext();) {
+                  Set<CandidateFact> factSet = sItr.next();
+                  boolean evaluableInSet = false;
+                  for (CandidateFact cfact : factSet) {
+                    if (ec.isEvaluable(cfact)) {
+                      evaluableInSet = true;
+                    }
+                  }
+                  if (!evaluableInSet) {
+                    log.info("Not considering fact table set:{} as {} is not 
evaluable", factSet, ec.exprCol.getName());
+                    sItr.remove();
+                  }
+                }
+              } else {
+                for (Iterator<CandidateFact> i = 
cubeql.getCandidateFacts().iterator(); i.hasNext();) {
+                  CandidateFact cfact = i.next();
+                  if (!ec.isEvaluable(cfact)) {
+                    log.info("Not considering fact table:{} as {} is not 
evaluable", cfact, ec.exprCol.getName());
+                    cubeql.addFactPruningMsgs(cfact.fact,
+                      
CandidateTablePruneCause.expressionNotEvaluable(ec.exprCol.getName()));
+                    i.remove();
+                  }
                 }
               }
             }
           }
         }
+        
cubeql.pruneCandidateFactWithCandidateSet(CandidateTablePruneCode.EXPRESSION_NOT_EVALUABLE);
       }
       // prune candidate dims without any valid expressions
       if (cubeql.getDimensions() != null && !cubeql.getDimensions().isEmpty()) 
{
@@ -699,9 +720,7 @@ class ExpressionResolver implements ContextRewriter {
               Set<ExpressionContext> ecSet = ecEntry.getValue();
               for (ExpressionContext ec : ecSet) {
                 if 
(ec.getSrcTable().getName().equals(cdim.getBaseTable().getName())) {
-                  if (!ec.directlyAvailableIn.contains(cdim)
-                    && (ec.evaluableExpressions.get(cdim) == null
-                    || ec.evaluableExpressions.get(cdim).isEmpty())) {
+                  if (!ec.isEvaluable(cdim)) {
                     log.info("Not considering dim table:{} as {} is not 
evaluable", cdim, ec.exprCol.getName());
                     cubeql.addDimPruningMsgs(dim, cdim.dimtable,
                       
CandidateTablePruneCause.expressionNotEvaluable(ec.exprCol.getName()));

http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java
----------------------------------------------------------------------
diff --git 
a/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java 
b/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java
index 53996c4..f65bd28 100644
--- 
a/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java
+++ 
b/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java
@@ -33,6 +33,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.lens.cube.metadata.UpdatePeriod;
+import 
org.apache.lens.cube.parse.CandidateTablePruneCause.CandidateTablePruneCode;
 import org.apache.lens.server.api.error.LensException;
 
 import org.apache.commons.lang.time.DateUtils;
@@ -42,6 +43,7 @@ import org.apache.hadoop.hive.ql.parse.ASTNode;
 import org.apache.hadoop.hive.ql.parse.SemanticException;
 
 import org.antlr.runtime.CommonToken;
+import org.testng.Assert;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
@@ -83,18 +85,18 @@ public class TestBaseCubeQueries extends TestQueryRewrite {
     String columnSetsStr = matcher.group(1);
     assertNotEquals(columnSetsStr.indexOf("stateid"), -1);
     assertNotEquals(columnSetsStr.indexOf("msr3, msr13"), -1);
-    assertEquals(pruneCauses.getDetails(),
-      new HashMap<String, List<CandidateTablePruneCause>>() {
-        {
-          put("testfact3_base,testfact3_raw_base", 
Arrays.asList(CandidateTablePruneCause.columnNotFound("stateid")));
-          put("testfact_deprecated,testfact2_raw_base,testfact2_base",
-            Arrays.asList(CandidateTablePruneCause.columnNotFound("msr3", 
"msr13")));
-        }
-      }
-    );
+    
assertEquals(pruneCauses.getDetails().get("testfact3_base,testfact3_raw_base"),
+      Arrays.asList(CandidateTablePruneCause.columnNotFound("stateid")));
+    
assertEquals(pruneCauses.getDetails().get("testfact_deprecated,testfact2_raw_base,testfact2_base"),
+      Arrays.asList(CandidateTablePruneCause.columnNotFound("msr3", "msr13")));
+    
assertTrue(pruneCauses.getDetails().containsKey("testfact1_base,testfact1_raw_base")
+      || 
pruneCauses.getDetails().containsKey("testfact1_raw_base,testfact1_base"));
+    String fact1BaseKey = 
pruneCauses.getDetails().containsKey("testfact1_base,testfact1_raw_base")
+      ? "testfact1_base,testfact1_raw_base" : 
"testfact1_raw_base,testfact1_base";
+    assertEquals(pruneCauses.getDetails().get(fact1BaseKey),
+      Arrays.asList(new 
CandidateTablePruneCause(CandidateTablePruneCode.ELEMENT_IN_SET_PRUNED)));
   }
 
-
   @Test
   public void testCommonDimensions() throws Exception {
     String hqlQuery = rewrite("select dim1, SUM(msr1) from basecube" + " where 
" + TWO_DAYS_RANGE, conf);
@@ -132,8 +134,15 @@ public class TestBaseCubeQueries extends TestQueryRewrite {
   }
 
   @Test
-  public void testMultipleFacts() throws Exception {
-    String hqlQuery = rewrite("select roundedmsr2, msr12 from basecube" + " 
where " + TWO_DAYS_RANGE, conf);
+  public void testMultiFactQueryWithNoDimensionsSelected() throws Exception {
+    CubeQueryContext ctx = rewriteCtx("select roundedmsr2, msr12 from 
basecube" + " where " + TWO_DAYS_RANGE, conf);
+    Set<String> candidateFacts = new HashSet<String>();
+    for (CandidateFact cfact : ctx.getCandidateFacts()) {
+      candidateFacts.add(cfact.getName().toLowerCase());
+    }
+    Assert.assertTrue(candidateFacts.contains("testfact1_base"));
+    Assert.assertTrue(candidateFacts.contains("testfact2_base"));
+    String hqlQuery = ctx.toHQL();
     String expected1 =
       getExpectedQuery(cubeName, "select sum(basecube.msr12) msr12 FROM ", 
null,
         null, getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE"));
@@ -147,17 +156,20 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
       || lower.startsWith("select mq1.roundedmsr2 roundedmsr2, mq2.msr12 msr12 
from "), hqlQuery);
     assertTrue(lower.contains("mq1 full outer join") && lower.endsWith("mq2"), 
hqlQuery);
     assertFalse(lower.contains("<=>"), hqlQuery);
+  }
 
-    hqlQuery = rewrite("select dim1, roundedmsr2, msr12 from basecube" + " 
where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+  @Test
+  public void testMultiFactQueryWithSingleCommonDimension() throws Exception {
+    String hqlQuery = rewrite("select dim1, roundedmsr2, msr12 from basecube" 
+ " where " + TWO_DAYS_RANGE, conf);
+    String expected1 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
sum(basecube.msr12) msr12 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact2_BASE"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact1_BASE"));
     TestCubeRewriter.compareContains(expected1, hqlQuery);
     TestCubeRewriter.compareContains(expected2, hqlQuery);
-    lower = hqlQuery.toLowerCase();
+    String lower = hqlQuery.toLowerCase();
     assertTrue(
       lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, 
mq2.roundedmsr2 roundedmsr2, mq1.msr12 msr12 from ")
       || lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, 
mq1.roundedmsr2 roundedmsr2, mq2.msr12 msr12"
@@ -165,18 +177,44 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
 
     assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"),
       hqlQuery);
+  }
 
+  @Test
+  public void 
testMultiFactQueryWithSingleCommonDimensionWithLightestFactFirst() throws 
Exception {
+    Configuration tConf = new Configuration(conf);
+    tConf.setBoolean(CubeQueryConfUtil.LIGHTEST_FACT_FIRST, true);
+    String hqlQuery = rewrite("select dim1, roundedmsr2, msr12 from basecube" 
+ " where " + TWO_DAYS_RANGE, tConf);
+    String expected1 =
+      getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
sum(basecube.msr12) msr12 FROM ", null,
+        " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact2_BASE"));
+    String expected2 =
+      getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null,
+        " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact1_BASE"));
+    TestCubeRewriter.compareContains(expected1, hqlQuery);
+    TestCubeRewriter.compareContains(expected2, hqlQuery);
+    String lower = hqlQuery.toLowerCase();
+    assertTrue(
+      lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, 
mq2.roundedmsr2 roundedmsr2, mq1.msr12 msr12 from ")
+      || lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, 
mq1.roundedmsr2 roundedmsr2, mq2.msr12 msr12"
+        + " from "), hqlQuery);
+
+    assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"),
+      hqlQuery);
+  }
+
+  @Test
+  public void testMultiFactQueryWithSingleCommonDimensionWithColumnsSwapped() 
throws Exception {
     // columns in select interchanged
-    hqlQuery = rewrite("select dim1, msr12, roundedmsr2 from basecube" + " 
where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+    String hqlQuery = rewrite("select dim1, msr12, roundedmsr2 from basecube" 
+ " where " + TWO_DAYS_RANGE, conf);
+    String expected1 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
sum(basecube.msr12) msr12 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact2_BASE"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact1_BASE"));
     TestCubeRewriter.compareContains(expected1, hqlQuery);
     TestCubeRewriter.compareContains(expected2, hqlQuery);
-    lower = hqlQuery.toLowerCase();
+    String lower = hqlQuery.toLowerCase();
     assertTrue(
       lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, mq2.msr12 
msr12, mq1.roundedmsr2 roundedmsr2 from ")
       || lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, mq1.msr12 
msr12, mq2.roundedmsr2 roundedmsr2"
@@ -184,13 +222,17 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
 
     assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"),
       hqlQuery);
+  }
 
+  @Test
+  public void testMultiFactQueryInvolvingThreeFactTables() throws Exception {
     // query with 3 fact tables
-    hqlQuery = rewrite("select dim1, msr12, roundedmsr2, msr13, msr3 from 
basecube" + " where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+    String hqlQuery = rewrite("select dim1, msr12, roundedmsr2, msr13, msr3 
from basecube where " + TWO_DAYS_RANGE,
+      conf);
+    String expected1 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
sum(basecube.msr12) msr12 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact2_BASE"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName,
         "select basecube.dim1 dim1, round(sum(basecube.msr2)/1000) 
roundedmsr2, max(basecube.msr3) msr3 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact1_BASE"));
@@ -221,13 +263,16 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
           + " mq2.roundedmsr2 roundedmsr2, mq1.msr13 msr13, mq2.msr3 msr3 from 
"), hqlQuery);
     assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.contains("mq2 full outer join ")
       && hqlQuery.endsWith("mq3 on mq1.dim1 <=> mq2.dim1 AND mq1.dim1 <=> 
mq3.dim1"), hqlQuery);
+  }
 
+  @Test
+  public void testMultiFactQueryWithTwoCommonDimensions() throws Exception {
     // query two dim attributes
-    hqlQuery = rewrite("select dim1, dim11, msr12, roundedmsr2 from basecube" 
+ " where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+    String hqlQuery = rewrite("select dim1, dim11, msr12, roundedmsr2 from 
basecube where " + TWO_DAYS_RANGE, conf);
+    String expected1 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, basecube.dim11 
dim11, sum(basecube.msr12) msr12 FROM ",
         null, " group by basecube.dim1", 
getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName,
         "select basecube.dim1 dim1, basecube.dim11 dim11, 
round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact1_BASE"));
@@ -242,13 +287,16 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
 
     assertTrue(hqlQuery.contains("mq1 full outer join ")
       && hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1 AND mq1.dim11 <=> 
mq2.dim11"), hqlQuery);
+  }
 
+  @Test
+  public void testMultiFactQueryWithNoAggregates() throws Exception {
     // no aggregates in the query
-    hqlQuery = rewrite("select dim1, msr11, roundedmsr2 from basecube" + " 
where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+    String hqlQuery = rewrite("select dim1, msr11, roundedmsr2 from basecube" 
+ " where " + TWO_DAYS_RANGE, conf);
+    String expected1 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, basecube.msr11 
msr11 FROM ", null, null,
         getWhereForHourly2days(cubeName, "C1_testfact2_raw_base"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
round(basecube.msr2/1000) roundedmsr2 FROM ", null, null,
         getWhereForHourly2days(cubeName, "C1_testfact1_raw_base"));
     TestCubeRewriter.compareContains(expected1, hqlQuery);
@@ -260,14 +308,17 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
 
     assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"),
       hqlQuery);
+  }
 
+  @Test
+  public void testMultiFactQueryWithColumnAliases() throws Exception {
     // query with aliases passed
-    hqlQuery =
+    String hqlQuery =
       rewrite("select dim1 d1, msr12 `my msr12`, roundedmsr2 m2 from basecube" 
+ " where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+    String expected1 =
       getExpectedQuery(cubeName, "select basecube.dim1 d1, sum(basecube.msr12) 
expr2 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact2_BASE"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName, "select basecube.dim1 d1, 
round(sum(basecube.msr2)/1000) m2 FROM ", null,
         " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, 
"C1_testFact1_BASE"));
     TestCubeRewriter.compareContains(expected1, hqlQuery);
@@ -278,13 +329,16 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
       hqlQuery.toLowerCase().startsWith("select coalesce(mq1.d1, mq2.d1) d1, 
mq1.expr2 `my msr12`, mq2.m2 m2 from "),
       hqlQuery);
     assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.d1 <=> mq2.d1"), hqlQuery);
+  }
 
-    // query with non default aggregate
-    hqlQuery = rewrite("select dim1, avg(msr12), avg(msr2) from basecube" + " 
where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+  @Test
+  public void testMultiFactQueryWithNoDefaultAggregates() throws Exception {
+   // query with non default aggregate
+    String hqlQuery = rewrite("select dim1, avg(msr12), avg(msr2) from 
basecube" + " where " + TWO_DAYS_RANGE, conf);
+    String expected1 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
avg(basecube.msr12) msr12 FROM ", null,
         " group by basecube.dim1", getWhereForHourly2days(cubeName, 
"C1_testfact2_raw_base"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName, "select basecube.dim1 dim1, 
avg(basecube.msr2)) msr2 FROM ", null,
         " group by basecube.dim1", getWhereForHourly2days(cubeName, 
"C1_testfact1_raw_base"));
     TestCubeRewriter.compareContains(expected1, hqlQuery);
@@ -296,14 +350,17 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
 
     assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"),
       hqlQuery);
+  }
 
+  @Test
+  public void testMultiFactQueryWithJoins() throws Exception {
     // query with join
-    hqlQuery = rewrite("select testdim2.name, msr12, roundedmsr2 from 
basecube" + " where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+    String hqlQuery = rewrite("select testdim2.name, msr12, roundedmsr2 from 
basecube where " + TWO_DAYS_RANGE, conf);
+    String expected1 =
       getExpectedQuery(cubeName, "select testdim2.name name, 
sum(basecube.msr12) msr12 FROM ", " JOIN " + getDbName()
           + "c1_testdim2tbl testdim2 ON basecube.dim2 = " + " testdim2.id and 
(testdim2.dt = 'latest') ", null,
         " group by testdim2.name", null, 
getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName, "select testdim2.name name, 
round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", " JOIN "
           + getDbName() + "c1_testdim2tbl testdim2 ON basecube.dim2 = "
           + " testdim2.id and (testdim2.dt = 'latest') ", null, " group by 
testdim2.name", null,
@@ -316,14 +373,17 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
         "select coalesce(mq1.name, mq2.name) name, mq1.msr12 msr12, 
mq2.roundedmsr2 roundedmsr2 from "), hqlQuery);
     assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.name <=> mq2.name"),
       hqlQuery);
+  }
 
+  @Test
+  public void testMultiFactQueryWithDenormColumn() throws Exception {
     // query with denorm variable
-    hqlQuery = rewrite("select dim2, msr13, roundedmsr2 from basecube" + " 
where " + TWO_DAYS_RANGE, conf);
-    expected1 =
+    String hqlQuery = rewrite("select dim2, msr13, roundedmsr2 from basecube" 
+ " where " + TWO_DAYS_RANGE, conf);
+    String expected1 =
       getExpectedQuery(cubeName, "select testdim2.id dim2, max(basecube.msr13) 
msr13 FROM ", " JOIN " + getDbName()
           + "c1_testdim2tbl testdim2 ON basecube.dim12 = " + " testdim2.id and 
(testdim2.dt = 'latest') ", null,
         " group by testdim2.id", null, getWhereForHourly2days(cubeName, 
"C1_testFact3_RAW_BASE"));
-    expected2 =
+    String expected2 =
       getExpectedQuery(cubeName, "select basecube.dim2 dim2, 
round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null,
         " group by basecube.dim2", getWhereForHourly2days(cubeName, 
"C1_testfact1_raw_base"));
     TestCubeRewriter.compareContains(expected1, hqlQuery);
@@ -334,33 +394,38 @@ public class TestBaseCubeQueries extends TestQueryRewrite 
{
         "select coalesce(mq1.dim2, mq2.dim2) dim2, mq1.msr13 msr13, 
mq2.roundedmsr2 roundedmsr2 from "), hqlQuery);
     assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.dim2 <=> mq2.dim2"),
       hqlQuery);
+  }
 
+  @Test
+  public void testMultiFactQueryWithExpressionInvolvingDenormVariable() throws 
Exception {
     // query with expression
-    // TODO allow expression to be answered from denorm columns
-    /*
-    hqlQuery =
+    // The expression to be answered from denorm columns
+    String hqlQuery =
       rewrite(
         "select booleancut, round(sum(msr2)/1000), avg(msr13 + msr14) from 
basecube" + " where " + TWO_DAYS_RANGE,
         conf);
-    expected1 =
-      getExpectedQuery(cubeName, "select basecube.dim1 != 'x' AND testdim2.id 
!= 10 expr1,"
+    String expected1 =
+      getExpectedQuery(cubeName, "select basecube.dim1 != 'x' AND testdim2.id 
!= 10 booleancut,"
           + " avg(basecube.msr13 + basecube.msr14) expr3 FROM ", " JOIN " + 
getDbName()
           + "c1_testdim2tbl testdim2 ON basecube.dim12 = " + " testdim2.id and 
(testdim2.dt = 'latest') ", null,
         " group by basecube.dim1 != 'x' AND testdim2.id != 10", null,
         getWhereForHourly2days(cubeName, "C1_testfact3_raw_base"));
-    expected2 =
-      getExpectedQuery(cubeName, "select basecube.dim1 != 'x' AND 
basecube.dim2 != 10 expr1,"
+    String expected2 =
+      getExpectedQuery(cubeName, "select basecube.dim1 != 'x' AND 
basecube.dim2 != 10 booleancut,"
           + " round(sum(basecube.msr2)/1000) msr2 FROM ", null,
         " group by basecube.dim1 != 'x' AND basecube.dim2 != 10",
         getWhereForHourly2days(cubeName, "C1_testfact1_raw_base"));
     TestCubeRewriter.compareContains(expected1, hqlQuery);
     TestCubeRewriter.compareContains(expected2, hqlQuery);
     assertTrue(hqlQuery.toLowerCase()
-      .startsWith("select coalesce(mq1.expr1, mq2.expr1) expr1, mq2.msr2 msr2, 
mq1.expr3 expr3 from ")
+      .startsWith("select coalesce(mq1.booleancut, mq2.booleancut) booleancut, 
mq2.msr2 msr2,"
+        + " mq1.expr3 expr3 from ")
       || hqlQuery.toLowerCase()
-        .startsWith("select coalesce(mq1.expr1, mq2.expr1) expr1, mq1.msr2 
msr2, mq2.expr3 expr3 from "), hqlQuery);
-    assertTrue(hqlQuery.contains("mq1 full outer join ") && 
hqlQuery.endsWith("mq2 on mq1.expr1 <=> mq2.expr1"),
-      hqlQuery);*/
+        .startsWith("select coalesce(mq1.booleancut, mq2.booleancut) 
booleancut, mq1.msr2 msr2,"
+          + " mq2.expr3 expr3 from "), hqlQuery);
+    assertTrue(hqlQuery.contains("mq1 full outer join ")
+      && hqlQuery.endsWith("mq2 on mq1.booleancut <=> mq2.booleancut"),
+      hqlQuery);
   }
 
   @Test

Reply via email to