>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