>From <[email protected]>:

[email protected] has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19729 )


Change subject: [ASTERIXDB-3600][COMP] cardinality improvements
......................................................................

[ASTERIXDB-3600][COMP] cardinality improvements

Change-Id: I3287d014f97369d7def85288894c23a0fcd977cd
---
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinCondition.java
M asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
M asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
7 files changed, 185 insertions(+), 41 deletions(-)



  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/29/19729/1

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
index 148ace9..35103e1 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
@@ -367,7 +367,7 @@

     private boolean 
everyLeafInputDoesNotHaveADataScanOperator(List<ILogicalOperator> leafInputs) {
         for (ILogicalOperator leafInput : leafInputs) {
-            DataSourceScanOperator scanOp = (DataSourceScanOperator) 
findDataSourceScanOperator(leafInput);
+            DataSourceScanOperator scanOp = 
joinEnum.findDataSourceScanOperator(leafInput);
             if (scanOp == null) {
                 return true;
             }
@@ -502,7 +502,7 @@
     }

     private ILogicalOperator truncateInput(ILogicalOperator op) throws 
AlgebricksException {
-        ILogicalOperator dsOp = findDataSourceScanOperator(op);
+        ILogicalOperator dsOp = joinEnum.findDataSourceScanOperator(op);
         ILogicalOperator ds = 
OperatorManipulationUtil.bottomUpCopyOperators(dsOp);
         return ds;
     }
@@ -1144,9 +1144,9 @@
         op.getAnnotations().put(OperatorAnnotations.OP_OUTPUT_CARDINALITY,
                 (double) Math.round(plan.getJoinNode().getCardinality() * 100) 
/ 100);
         op.getAnnotations().put(OperatorAnnotations.OP_INPUT_DOCSIZE,
-                (double) Math.round(plan.getJoinNode().getInputSize() * 100) / 
100);
+        (double) Math.round(plan.getJoinNode().getInputSize() * 100) / 100);
         op.getAnnotations().put(OperatorAnnotations.OP_OUTPUT_DOCSIZE,
-                (double) Math.round(plan.getJoinNode().getOutputSize() * 100) 
/ 100);
+        (double) Math.round(plan.getJoinNode().getOutputSize() * 100) / 100);
         op.getAnnotations().put(OperatorAnnotations.OP_COST_TOTAL,
                 (double) Math.round(plan.computeTotalCost() * 100) / 100);
         if (plan.IsScanNode()) {
@@ -1171,6 +1171,7 @@
     /**
      * Finds the DataSourceScanOperator given a leafInput
      */
+    /*
     private ILogicalOperator findDataSourceScanOperator(ILogicalOperator op) {
         ILogicalOperator origOp = op;
         while (op != null && op.getOperatorTag() != 
LogicalOperatorTag.EMPTYTUPLESOURCE) {
@@ -1181,6 +1182,8 @@
         }
         return null;
     }
+
+     */

     private void removeJoinAnnotations(AbstractFunctionCallExpression afcExpr) 
{
         afcExpr.removeAnnotation(BroadcastExpressionAnnotation.class);
@@ -1262,7 +1265,7 @@
         if (selOp != null) {
             addCardCostAnnotations(selOp, plan);
         }
-        addCardCostAnnotations(findDataSourceScanOperator(leftInput), plan);
+        addCardCostAnnotations(joinEnum.findDataSourceScanOperator(leftInput), 
plan);
     }

     private void getJoinNode(PlanNode plan, List<JoinOperator> allJoinOps) 
throws AlgebricksException {
@@ -1374,7 +1377,7 @@
             joinOp.getInputs().get(0).setValue(leftInput);
             ILogicalOperator op = joinOp.getInputs().get(0).getValue();
             context.computeAndSetTypeEnvironmentForOperator(op);
-            addCardCostAnnotations(findDataSourceScanOperator(leftInput), 
leftPlan);
+            
addCardCostAnnotations(joinEnum.findDataSourceScanOperator(leftInput), 
leftPlan);
         } else {
             // join
             totalNumberOfJoins.increment();
@@ -1394,7 +1397,7 @@
             }
             joinOp.getInputs().get(1).setValue(rightInput);
             
context.computeAndSetTypeEnvironmentForOperator(joinOp.getInputs().get(1).getValue());
-            addCardCostAnnotations(findDataSourceScanOperator(rightInput), 
rightPlan);
+            
addCardCostAnnotations(joinEnum.findDataSourceScanOperator(rightInput), 
rightPlan);
         } else {
             // join
             totalNumberOfJoins.increment();
@@ -1484,7 +1487,7 @@
             throws AlgebricksException {
         int n = 0;
         for (ILogicalOperator li : leafInputs) {
-            DataSourceScanOperator scanOp = (DataSourceScanOperator) 
findDataSourceScanOperator(li);
+            DataSourceScanOperator scanOp = 
joinEnum.findDataSourceScanOperator(li);
             if (scanOp == null) {
                 continue;
             }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinCondition.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinCondition.java
index f37f8a3..0f4cc82 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinCondition.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinCondition.java
@@ -43,7 +43,7 @@
     protected int leftSideBits;
     protected int rightSideBits;
     protected int numLeafInputs;
-    protected double selectivity;
+    protected double selectivity = -1.0; // This must be changed obviously
     protected comparisonOp comparisonType;
     protected JoinOperator joinOp = null;
     protected List<LogicalVariable> usedVars = null;
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
index 4be0e66..b39361b 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
@@ -677,26 +677,117 @@
         return null;
     }

-    // in case we have l.partkey = ps.partkey and l.suppkey = ps.suppkey, we 
will only use the first one for cardinality computations.
-    // treat it like a Pk-Fk join; simplifies cardinality computation
-    private void markCompositeJoinPredicates() {
-        // can use dataSetBits??? This will be simpler.
-        for (int i = 0; i < joinConditions.size() - 1; i++) {
+    // This is basically a heuristic routine. Not guaranteed to be 100% 
accurate.
+    // Use only when primary keys are not defined (shadow data sets)
+    // Examples l.partkey = ps.partkey and l.suppkey = ps.suppkey TPCH
+    // c.c_d_id = o.o_d_id and c.c_w_id = o.o_w_id and c.c_id = o.o_c_id in CH2
+    //for (JoinCondition jc : joinConditions) {
+    //jc.selectivity = stats.getSelectivityFromAnnotationMain(jc, null, true, 
false, jc.joinOp);
+    //}
+    private void markCompositeJoinPredicates() throws AlgebricksException {
+        List<JoinCondition> JCs = new ArrayList<>();
+        for (int i = 0; i < joinConditions.size(); i++) {
             JoinCondition jcI = joinConditions.get(i);
-            if (jcI.comparisonType == JoinCondition.comparisonOp.OP_EQ && 
!jcI.partOfComposite) {
+            if (jcI.usedVars == null || jcI.usedVars.size() != 2 || 
jcI.numLeafInputs != 2 || jcI.partOfComposite) {
+                continue;
+            }
+            JCs.clear();
+            JCs.add(jcI);
+            if (jcI.comparisonType == JoinCondition.comparisonOp.OP_EQ) {
                 for (int j = i + 1; j < joinConditions.size(); j++) {
                     JoinCondition jcJ = joinConditions.get(j);
-                    if (jcJ.comparisonType == JoinCondition.comparisonOp.OP_EQ 
&& jcI.datasetBits == jcJ.datasetBits) {
-                        jcI.selectivity = 1.0 / 
smallerDatasetSize(jcI.datasetBits);
-                        // 1/P will be the selectivity of the composite clause
-                        jcJ.partOfComposite = true;
-                        jcJ.selectivity = 1.0;
+                    if (jcJ.usedVars == null) {
+                        continue;
+                    }
+                    if (jcJ.comparisonType == JoinCondition.comparisonOp.OP_EQ 
&& (jcJ.usedVars.size() == 2)
+                            && (jcJ.numLeafInputs == 2) && (jcI.datasetBits == 
jcJ.datasetBits)) {
+                        JCs.add(jcJ);
                     }
                 }
+                double sel = checkForPrimaryKey(JCs);
+                //if (JCs.size() > 1) { // need at least two to form a 
composite join key
+                // Now check if selectivities have to be adjusted for this 
composite key
+                if (JCs.size() > 1) {
+                    for (JoinCondition jc : JCs) {
+                        jc.partOfComposite = true;
+                    }
+                }
+                if (sel == -1.0) {
+                    for (JoinCondition jc : JCs) {
+                        jc.selectivity = 
stats.getSelectivityFromAnnotationMain(jc, null, true, false, jc.joinOp);
+                    }
+
+                } else {
+                    for (JoinCondition jc : JCs) {
+                        jc.selectivity = 1.0;
+                    }
+                    JCs.get(0).selectivity = sel; // store this in the first 
condition. Does not matter which one it is!
+                }
+                /*
+                    double cardOne = 
jnArray[jcI.leftSide].getOrigCardinality();
+                    double cardTwo = 
jnArray[jcI.rightSide].getOrigCardinality();
+                    double sel = 1.0;
+                    for (JoinCondition jc : JCs) {
+                        sel *= jc.selectivity;
+                    }
+                    double card = 1.0 / sel;
+                    if (close(card, cardOne) || close(card, cardTwo)) { // No 
need to do anything since selectivities are well behaved
+                        continue;
+                    }
+                    // Now we need to make the smaller side the primary side 
as no other information is available at this time
+                    jcI.selectivity = 1.0 / Math.min(cardOne, cardTwo);
+                    for (int j = 1; j < JCs.size(); j++) {
+                        JCs.get(j).selectivity = 1.0;
+                    }
+                //}*/
             }
         }
     }

+    // at this point the join is binary. Not sure if all the predicates may 
not be in the same order?? Appears to be the case
+    private double checkForPrimaryKey(List<JoinCondition> jCs) {
+        List<LogicalVariable> leftVars = new ArrayList<>();
+        List<LogicalVariable> rightVars = new ArrayList<>();
+        for (JoinCondition jc : jCs) {
+            leftVars.add(jc.usedVars.get(0));
+            rightVars.add(jc.usedVars.get(1));
+        }
+        double sel = -1.0;
+        ILogicalOperator leftLeafInput = leafInputs.get(jCs.get(0).leftSide - 
1);
+        DataSourceScanOperator leftScanOp = 
findDataSourceScanOperator(leftLeafInput);
+        boolean leftPrimary = false;
+        if (leftScanOp.getVariables().containsAll(leftVars)
+                && leftScanOp.getVariables().size() == leftVars.size() + 1) {
+            // this is the primary side
+            leftPrimary = true;
+            sel = 1.0 / jnArray[jCs.get(0).leftSide].getOrigCardinality();
+        }
+        boolean rightPrimary = false;
+        ILogicalOperator rightLeafInput = leafInputs.get(jCs.get(0).rightSide 
- 1);
+        DataSourceScanOperator rightScanOp = 
findDataSourceScanOperator(rightLeafInput);
+        if (rightScanOp.getVariables().containsAll(rightVars)
+                && rightScanOp.getVariables().size() == rightVars.size() + 1) {
+            // this is the primary side
+            rightPrimary = true;
+            sel = 1.0 / jnArray[jCs.get(0).rightSide].getOrigCardinality();
+        }
+
+        if (leftPrimary && rightPrimary) {
+            // this is the subset case. The join cardinality will be the 
smaller side. So selectvity will be 1/biggerCard
+            sel = 1.0 / 
Math.max(jnArray[jCs.get(0).leftSide].getOrigCardinality(),
+                    jnArray[jCs.get(0).rightSide].getOrigCardinality());
+        }
+        return sel;
+    }
+
+    private boolean close(double size1, double size2) {
+        double ratio = size1 / size2;
+        if (ratio > 0.8 && ratio < 1.2) {
+            return true;
+        }
+        return false;
+    }
+
     private double smallerDatasetSize(int datasetBits) {
         double size = Cost.MAX_CARD;
         for (JoinNode jn : this.jnArray)
@@ -899,16 +990,15 @@
                     jn.datasetIndexes = new ArrayList<>();
                     jn.datasetIndexes.addAll(jnI.datasetIndexes);
                     jn.datasetIndexes.addAll(jnJ.datasetIndexes);
-                    Collections.sort(jn.datasetIndexes);

                     jn.datasetNames = new ArrayList<>();
                     jn.datasetNames.addAll(jnI.datasetNames);
                     jn.datasetNames.addAll(jnJ.datasetNames);
-                    Collections.sort(jn.datasetNames);
+
                     jn.aliases = new ArrayList<>();
                     jn.aliases.addAll(jnI.aliases);
                     jn.aliases.addAll(jnJ.aliases);
-                    Collections.sort(jn.aliases);
+
                     jn.size = jnI.size + jnJ.size; // These are the original 
document sizes
                     jn.setCardinality(jn.computeJoinCardinality(), true);
                     jn.setSizeVarsAfterScan(jnI.getSizeVarsAfterScan() + 
jnJ.getSizeVarsAfterScan());
@@ -1272,7 +1362,10 @@
         }

         for (JoinCondition jc : joinConditions) {
-            jc.selectivity = stats.getSelectivityFromAnnotationMain(jc, null, 
true, false, jc.joinOp);
+            if (!((AbstractFunctionCallExpression) 
jc.joinCondition).getFunctionIdentifier()
+                    .equals(AlgebricksBuiltinFunctions.EQ)) {
+                jc.selectivity = stats.getSelectivityFromAnnotationMain(jc, 
null, true, false, jc.joinOp);
+            }
         }

         findSelectionPredsInsideJoins(); // This was added to make TPCH Q7 
work.
@@ -1283,14 +1376,19 @@
         }

         markCompositeJoinPredicates();
+        for (JoinCondition jc : joinConditions) {
+            if (jc.selectivity == -1) {// just in case we missed computing 
some selectivities perhaps because there were no keys found
+                jc.selectivity = stats.getSelectivityFromAnnotationMain(jc, 
null, true, false, jc.joinOp);
+            }
+        }
         int lastJnNum = enumerateHigherLevelJoinNodes();
         JoinNode lastJn = jnArray[allTabsJnNum];
+        // return the cheapest plan
         if (LOGGER.isTraceEnabled()) {
             EnumerateJoinsRule.printPlan(pp, op, "Original Whole plan in JN 
END");
             LOGGER.trace(dumpJoinNodes(lastJnNum));
         }

-        // return the cheapest plan
         return lastJn.cheapestPlanIndex;
     }

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
index 2aa93a7..3451966 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
@@ -19,6 +19,8 @@

 package org.apache.asterix.optimizer.rules.cbo;

+import java.text.DecimalFormat;
+import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -513,9 +515,17 @@

     private static double adjustSelectivities(JoinCondition jc1, JoinCondition 
jc2, JoinCondition jc3) {
         double sel;
+
         if (jc1.comparisonType == JoinCondition.comparisonOp.OP_EQ
                 && jc2.comparisonType == JoinCondition.comparisonOp.OP_EQ
                 && jc3.comparisonType == JoinCondition.comparisonOp.OP_EQ) {
+            if (!jc1.partOfComposite)
+                return jc1.selectivity;
+            if (!jc2.partOfComposite)
+                return jc2.selectivity;
+            if (!jc3.partOfComposite)
+                return jc3.selectivity;
+            // one of the above must be true.
             sel = findRedundantSel(jc1, jc2, jc3);
         } else {
             // at least one of the predicates in not an equality predicate
@@ -1591,6 +1601,8 @@

     @Override
     public String toString() {
+        NumberFormat scientificFormat = new DecimalFormat("0.###E0");
+        DecimalFormat formatter = new DecimalFormat("#,###.00");
         List<PlanNode> allPlans = joinEnum.getAllPlans();
         StringBuilder sb = new StringBuilder(128);
         if (IsBaseLevelJoinNode()) {
@@ -1615,9 +1627,16 @@
         sb.append("level ").append(level).append('\n');
         sb.append("highestDatasetId ").append(highestDatasetId).append('\n');
         if (IsBaseLevelJoinNode()) {
-            sb.append("orig cardinality ").append(dumpDouble(origCardinality));
+            //sb.append("orig cardinality 
").append(dumpDouble(origCardinality));
+            //sb.append("orig cardinality 
").append(dumpDouble(Double.parseDouble(scientificFormat.format(origCardinality))));
+            sb.append("orig cardinality2 ")
+                    
.append(formatter.format(Double.parseDouble(String.valueOf(origCardinality))));
+            sb.append("\n    cardinality 
\n").append(formatter.format(Double.parseDouble(String.valueOf(cardinality))));
+        } else {
+            //sb.append("cardinality ").append(dumpDouble(cardinality));
+            //sb.append("cardinality 
").append(dumpDouble(Double.parseDouble(scientificFormat.format(cardinality))));
+            sb.append("cardinality 
\n").append(formatter.format(Double.parseDouble(String.valueOf(cardinality))));
         }
-        sb.append("cardinality ").append(dumpDouble(cardinality));
         sb.append("size ").append(dumpDouble(size));
         sb.append("outputSize(sizeVarsAfterScan) 
").append(dumpDouble(sizeVarsAfterScan));
         if (planIndexesArray.size() == 0) {
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
index 4f5688a..18bc53f 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
@@ -181,36 +181,48 @@
                 return 0.5; // this may not be accurate obviously!
             } // we can do all relops here and other joins such as interval 
joins and spatial joins, the compile time might increase a lot

+            boolean unnestOp1 = 
joinEnum.findUnnestOp(joinEnum.leafInputs.get(idx1 - 1));
+            boolean unnestOp2 = 
joinEnum.findUnnestOp(joinEnum.leafInputs.get(idx2 - 1));
+            boolean unnestOp = unnestOp1 || unnestOp2;
             Index.SampleIndexDetails idxDetails1 = (Index.SampleIndexDetails) 
index1.getIndexDetails();
             Index.SampleIndexDetails idxDetails2 = (Index.SampleIndexDetails) 
index2.getIndexDetails();
-            if ((idxDetails1.getSourceCardinality() < 
idxDetails1.getSampleCardinalityTarget())
+            if (((idxDetails1.getSourceCardinality() < 
idxDetails1.getSampleCardinalityTarget())
                     || (idxDetails2.getSourceCardinality() < 
idxDetails2.getSampleCardinalityTarget())
-                    || exprUsedVars.size() > 2) { //* if there are more than 2 
variables, it is not a simple join like r.a op s.a
-                double sel = 
findJoinSelFromSamples(joinEnum.leafInputs.get(idx1 - 1),
+                    || exprUsedVars.size() > 2) && !unnestOp) { //* if there 
are more than 2 variables, it is not a simple join like r.a op s.a
+                double sels = 
findJoinSelFromSamples(joinEnum.leafInputs.get(idx1 - 1),
                         joinEnum.leafInputs.get(idx2 - 1), index1, index2, 
joinExpr, jOp);
-                if (sel == 0.0) {
-                    sel = 1.0 / Math.max(card1, card2);
+                if (sels == 0.0) {
+                    sels = 1.0 / Math.max(card1, card2);
                 }
-                return sel;
+                return sels;
             }
             // Now we can handle only equi joins. We make all the uniform and 
independence assumptions here.
-            double sel = naiveJoinSelectivity(exprUsedVars, card1, card2, 
idx1, idx2);
-            return sel;
+            double seln = naiveJoinSelectivity(exprUsedVars, card1, card2, 
idx1, idx2, unnestOp1, unnestOp2);
+            return seln;
         }
     }

     private double naiveJoinSelectivity(List<LogicalVariable> exprUsedVars, 
double card1, double card2, int idx1,
-            int idx2) throws AlgebricksException {
+            int idx2, boolean unnestOp1, boolean unnestOp2) throws 
AlgebricksException {
         ILogicalOperator leafInput;
         LogicalVariable var;

-        // choose the smaller side sample; better results this way for sure!
-        if (card1 < card2) {
+        if (unnestOp1) {// we cannot choose teh side with an array as we need 
the unnesting scaling factor also.
+                            // have to see if there are other alternatives 
later
+            leafInput = joinEnum.leafInputs.get(idx2 - 1);
+            var = exprUsedVars.get(1);
+        } else if (unnestOp2) {
             leafInput = joinEnum.leafInputs.get(idx1 - 1);
             var = exprUsedVars.get(0);
         } else {
-            leafInput = joinEnum.leafInputs.get(idx2 - 1);
-            var = exprUsedVars.get(1);
+            // choose the smaller side sample; better results this way for 
sure!
+            if (card1 < card2) {
+                leafInput = joinEnum.leafInputs.get(idx1 - 1);
+                var = exprUsedVars.get(0);
+            } else {
+                leafInput = joinEnum.leafInputs.get(idx2 - 1);
+                var = exprUsedVars.get(1);
+            }
         }
         Index index = findIndex(leafInput);
         if (index == null) {
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml 
b/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
index 10e8302..a472904 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
@@ -15922,7 +15922,7 @@
         <expected-warn><![CDATA[ASX1132: Invalid specification for hint 
productivity. Invalid format for productivity values (in line 31, at column 
23)]]></expected-warn>
         <expected-warn><![CDATA[ASX1132: Invalid specification for hint 
productivity. Invalid format for productivity values (in line 31, at column 
23)]]></expected-warn>
         <expected-warn><![CDATA[ASX1132: Invalid specification for hint 
productivity. Invalid format for productivity values (in line 31, at column 
23)]]></expected-warn>
-        <expected-warn>HYR10006: Could not apply productivity hint: 
Productivity specified: 0.0, has to be a decimal value greater than 0 (in line 
33, at column 47)</expected-warn>
+        <expected-warn><![CDATA[ASX1132: Invalid specification for hint 
productivity. Productivity has to be a decimal value greater than 0 (in line 
33, at column 23)]]></expected-warn>
       </compilation-unit>
     </test-case>
     <test-case FilePath="warnings" check-warnings="true">
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj 
b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 7a46e95..a91b3d5 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -774,6 +774,9 @@
                  Matcher numMat = number.matcher(matchedGroup);
                  if (numMat.find()) {
                    productivity = Double.parseDouble (numMat.group());
+                   if (productivity == 0.0) {
+                     throw new 
SqlppParseException(getSourceLocation(hintToken), "Productivity has to be a 
decimal value greater than 0");
+                   }
                  }
                  else {
                    throw new SqlppParseException(getSourceLocation(hintToken), 
"Productivity has to be a decimal value greater than 0");

--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19729
To unsubscribe, or for help writing mail filters, visit 
https://asterix-gerrit.ics.uci.edu/settings

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: I3287d014f97369d7def85288894c23a0fcd977cd
Gerrit-Change-Number: 19729
Gerrit-PatchSet: 1
Gerrit-Owner: [email protected]
Gerrit-MessageType: newchange

Reply via email to