[ASTERIXDB-2951][COMP] Support IS DISTINCT FROM operator
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- Add support for IS [NOT] DISTINCT FROM comparison operator
- Add testcases and update documentation
Change-Id: Ifad404fa7c613771f60bd12f3aa2bd5fea77ba34
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/12884
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/is_distinct_01/is_distinct_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/is_distinct_01/is_distinct_01.1.query.sqlpp
new file mode 100644
index 0000000..c0ed568
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/is_distinct_01/is_distinct_01.1.query.sqlpp
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+from
+ [ int64(2), float(2.0), double(2.5), "str1", "str2", true, false, null, missing ] arg1,
+ [ int32(2), double(2.0), float(2.5), "str1", "str2", true, false, null, missing ] arg2
+let
+ is_distinct = arg1 is distinct from arg2,
+ is_not_distinct = arg1 is not distinct from arg2
+select
+ case
+ when arg1 is missing then "MISSING"
+ when arg1 is null then "NULL"
+ else arg1
+ end as arg1,
+ case
+ when arg2 is missing then "MISSING"
+ when arg2 is null then "NULL"
+ else arg2
+ end as arg2,
+ is_distinct as `!!==`,
+ is_not_distinct as `==`
+order by is_distinct, arg1, arg2
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/is_distinct_01/is_distinct_01.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/is_distinct_01/is_distinct_01.2.query.sqlpp
new file mode 100644
index 0000000..fcc1dc2
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/comparison/is_distinct_01/is_distinct_01.2.query.sqlpp
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+let
+ x = 2, y = 3
+select
+ /* test expression */
+ x between 1 and 3 is not distinct from x between 0 and 4 as t1,
+ /* expected operator precedence */
+ (x between 1 and 3) is not distinct from (x between 0 and 4) as t1_expected,
+ /* unexpected operator precedence */
+ (((x between 1 and 3) is not distinct from x) between 0 and 4) as t1_unexpected,
+
+ /* test expression */
+ x is unknown is not distinct from y is unknown as t2,
+ /* expected operator precedence */
+ (x is unknown) is not distinct from (y is unknown) as t2_expected,
+ /* unexpected operator precedence */
+ (((x is unknown) is not distinct from y) is unknown) as t2_unexpected,
+
+ /* test expression */
+ x is not unknown is distinct from y is unknown as t3,
+ /* expected operator precedence */
+ (x is not unknown) is distinct from (y is unknown) as t3_expected,
+ /* unexpected operator precedence */
+ (((x is not unknown) is distinct from y) is unknown) as t3_unexpected;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/comparison/is_distinct_01/is_distinct_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/comparison/is_distinct_01/is_distinct_01.1.adm
new file mode 100644
index 0000000..6b0764d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/comparison/is_distinct_01/is_distinct_01.1.adm
@@ -0,0 +1,81 @@
+{ "!!==": false, "==": true, "arg1": "MISSING", "arg2": "MISSING" }
+{ "!!==": false, "==": true, "arg1": "NULL", "arg2": "NULL" }
+{ "!!==": false, "==": true, "arg1": 2, "arg2": 2 }
+{ "!!==": false, "==": true, "arg1": 2, "arg2": 2.0 }
+{ "!!==": false, "==": true, "arg1": 2.0, "arg2": 2 }
+{ "!!==": false, "==": true, "arg1": 2.0, "arg2": 2.0 }
+{ "!!==": false, "==": true, "arg1": 2.5, "arg2": 2.5 }
+{ "!!==": false, "==": true, "arg1": "str1", "arg2": "str1" }
+{ "!!==": false, "==": true, "arg1": "str2", "arg2": "str2" }
+{ "!!==": false, "==": true, "arg1": false, "arg2": false }
+{ "!!==": false, "==": true, "arg1": true, "arg2": true }
+{ "!!==": true, "==": false, "arg1": "MISSING", "arg2": "NULL" }
+{ "!!==": true, "==": false, "arg1": "MISSING", "arg2": 2 }
+{ "!!==": true, "==": false, "arg1": "MISSING", "arg2": 2.0 }
+{ "!!==": true, "==": false, "arg1": "MISSING", "arg2": 2.5 }
+{ "!!==": true, "==": false, "arg1": "MISSING", "arg2": "str1" }
+{ "!!==": true, "==": false, "arg1": "MISSING", "arg2": "str2" }
+{ "!!==": true, "==": false, "arg1": "MISSING", "arg2": false }
+{ "!!==": true, "==": false, "arg1": "MISSING", "arg2": true }
+{ "!!==": true, "==": false, "arg1": "NULL", "arg2": "MISSING" }
+{ "!!==": true, "==": false, "arg1": "NULL", "arg2": 2 }
+{ "!!==": true, "==": false, "arg1": "NULL", "arg2": 2.0 }
+{ "!!==": true, "==": false, "arg1": "NULL", "arg2": 2.5 }
+{ "!!==": true, "==": false, "arg1": "NULL", "arg2": "str1" }
+{ "!!==": true, "==": false, "arg1": "NULL", "arg2": "str2" }
+{ "!!==": true, "==": false, "arg1": "NULL", "arg2": false }
+{ "!!==": true, "==": false, "arg1": "NULL", "arg2": true }
+{ "!!==": true, "==": false, "arg1": 2, "arg2": "MISSING" }
+{ "!!==": true, "==": false, "arg1": 2.0, "arg2": "MISSING" }
+{ "!!==": true, "==": false, "arg1": 2, "arg2": "NULL" }
+{ "!!==": true, "==": false, "arg1": 2.0, "arg2": "NULL" }
+{ "!!==": true, "==": false, "arg1": 2, "arg2": 2.5 }
+{ "!!==": true, "==": false, "arg1": 2.0, "arg2": 2.5 }
+{ "!!==": true, "==": false, "arg1": 2, "arg2": "str1" }
+{ "!!==": true, "==": false, "arg1": 2.0, "arg2": "str1" }
+{ "!!==": true, "==": false, "arg1": 2, "arg2": "str2" }
+{ "!!==": true, "==": false, "arg1": 2.0, "arg2": "str2" }
+{ "!!==": true, "==": false, "arg1": 2, "arg2": false }
+{ "!!==": true, "==": false, "arg1": 2.0, "arg2": false }
+{ "!!==": true, "==": false, "arg1": 2, "arg2": true }
+{ "!!==": true, "==": false, "arg1": 2.0, "arg2": true }
+{ "!!==": true, "==": false, "arg1": 2.5, "arg2": "MISSING" }
+{ "!!==": true, "==": false, "arg1": 2.5, "arg2": "NULL" }
+{ "!!==": true, "==": false, "arg1": 2.5, "arg2": 2 }
+{ "!!==": true, "==": false, "arg1": 2.5, "arg2": 2.0 }
+{ "!!==": true, "==": false, "arg1": 2.5, "arg2": "str1" }
+{ "!!==": true, "==": false, "arg1": 2.5, "arg2": "str2" }
+{ "!!==": true, "==": false, "arg1": 2.5, "arg2": false }
+{ "!!==": true, "==": false, "arg1": 2.5, "arg2": true }
+{ "!!==": true, "==": false, "arg1": "str1", "arg2": "MISSING" }
+{ "!!==": true, "==": false, "arg1": "str1", "arg2": "NULL" }
+{ "!!==": true, "==": false, "arg1": "str1", "arg2": 2 }
+{ "!!==": true, "==": false, "arg1": "str1", "arg2": 2.0 }
+{ "!!==": true, "==": false, "arg1": "str1", "arg2": 2.5 }
+{ "!!==": true, "==": false, "arg1": "str1", "arg2": "str2" }
+{ "!!==": true, "==": false, "arg1": "str1", "arg2": false }
+{ "!!==": true, "==": false, "arg1": "str1", "arg2": true }
+{ "!!==": true, "==": false, "arg1": "str2", "arg2": "MISSING" }
+{ "!!==": true, "==": false, "arg1": "str2", "arg2": "NULL" }
+{ "!!==": true, "==": false, "arg1": "str2", "arg2": 2 }
+{ "!!==": true, "==": false, "arg1": "str2", "arg2": 2.0 }
+{ "!!==": true, "==": false, "arg1": "str2", "arg2": 2.5 }
+{ "!!==": true, "==": false, "arg1": "str2", "arg2": "str1" }
+{ "!!==": true, "==": false, "arg1": "str2", "arg2": false }
+{ "!!==": true, "==": false, "arg1": "str2", "arg2": true }
+{ "!!==": true, "==": false, "arg1": false, "arg2": "MISSING" }
+{ "!!==": true, "==": false, "arg1": false, "arg2": "NULL" }
+{ "!!==": true, "==": false, "arg1": false, "arg2": 2 }
+{ "!!==": true, "==": false, "arg1": false, "arg2": 2.0 }
+{ "!!==": true, "==": false, "arg1": false, "arg2": 2.5 }
+{ "!!==": true, "==": false, "arg1": false, "arg2": "str1" }
+{ "!!==": true, "==": false, "arg1": false, "arg2": "str2" }
+{ "!!==": true, "==": false, "arg1": false, "arg2": true }
+{ "!!==": true, "==": false, "arg1": true, "arg2": "MISSING" }
+{ "!!==": true, "==": false, "arg1": true, "arg2": "NULL" }
+{ "!!==": true, "==": false, "arg1": true, "arg2": 2 }
+{ "!!==": true, "==": false, "arg1": true, "arg2": 2.0 }
+{ "!!==": true, "==": false, "arg1": true, "arg2": 2.5 }
+{ "!!==": true, "==": false, "arg1": true, "arg2": "str1" }
+{ "!!==": true, "==": false, "arg1": true, "arg2": "str2" }
+{ "!!==": true, "==": false, "arg1": true, "arg2": false }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/comparison/is_distinct_01/is_distinct_01.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/comparison/is_distinct_01/is_distinct_01.2.adm
new file mode 100644
index 0000000..bd83c66
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/comparison/is_distinct_01/is_distinct_01.2.adm
@@ -0,0 +1 @@
+{ "t1": true, "t1_expected": true, "t1_unexpected": null, "t2": true, "t2_expected": true, "t2_unexpected": false, "t3": true, "t3_expected": true, "t3_unexpected": false }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 5937278..cb4c5ad 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -3431,6 +3431,11 @@
</compilation-unit>
</test-case>
<test-case FilePath="comparison">
+ <compilation-unit name="is_distinct_01">
+ <output-dir compare="Text">is_distinct_01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="comparison">
<compilation-unit name="like">
<output-dir compare="Text">like</output-dir>
</compilation-unit>
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/2_expr.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/2_expr.md
index 9ecc29b..37bd2f0 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/2_expr.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/2_expr.md
@@ -53,7 +53,7 @@
| || | String concatenation |
| IS NULL, IS NOT NULL, IS MISSING, IS NOT MISSING, <br/>IS UNKNOWN, IS NOT UNKNOWN, IS VALUED, IS NOT VALUED | Unknown value comparison |
| BETWEEN, NOT BETWEEN | Range comparison (inclusive on both sides) |
-| =, !=, <>, <, >, <=, >=, LIKE, NOT LIKE, IN, NOT IN | Comparison |
+| =, !=, <>, <, >, <=, >=, LIKE, NOT LIKE, IN, NOT IN, IS DISTINCT FROM, IS NOT DISTINCT FROM | Comparison |
| NOT | Logical negation |
| AND | Conjunction |
| OR | Disjunction |
@@ -130,6 +130,8 @@
| >= | Greater than or equal to | FROM customers AS c <br/> WHERE c.rating >= 640 <br/> SELECT *; |
| LIKE | Test if the left side matches a pattern defined on the right side; in the pattern, "%" matches any string while "_" matches any character. | FROM customers AS c WHERE c.name LIKE "%Dodge%" SELECT *;|
| NOT LIKE | Test if the left side does not match a pattern defined on the right side; in the pattern, "%" matches any string while "_" matches any character. | FROM customers AS c WHERE c.name NOT LIKE "%Dodge%" SELECT *;|
+| IS DISTINCT FROM | Inequality test that that treats NULL values as equal to each other and MISSING values as equal to each other | FROM orders AS o <br/> WHERE o.order_date IS DISTINCT FROM o.ship_date <br/> SELECT *; | |
+| IS NOT DISTINCT FROM | Equality test that treats NULL values as equal to each other and MISSING values as equal to each other | FROM orders AS o <br/> WHERE o.order_date IS NOT DISTINCT FROM o.ship_date <br/> SELECT *; |
The following table summarizes how the missing value comparison operators work.
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/struct/OperatorType.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/struct/OperatorType.java
index f4f2ae1..e207e75 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/struct/OperatorType.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/struct/OperatorType.java
@@ -41,7 +41,9 @@
IN("in"),
NOT_IN("not_in"),
BETWEEN("between"),
- NOT_BETWEEN("not_between");
+ NOT_BETWEEN("not_between"),
+ DISTINCT("distinct"),
+ NOT_DISTINCT("not_distinct");
private static final OperatorType[] VALUES = values();
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java
index c47634e..93a14ca 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java
@@ -29,13 +29,17 @@
import org.apache.asterix.lang.common.base.Expression;
import org.apache.asterix.lang.common.base.ILangExpression;
import org.apache.asterix.lang.common.expression.CallExpr;
+import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
import org.apache.asterix.lang.common.expression.QuantifiedExpression.Quantifier;
import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.literal.FalseLiteral;
+import org.apache.asterix.lang.common.literal.TrueLiteral;
import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
import org.apache.asterix.lang.common.struct.OperatorType;
import org.apache.asterix.lang.common.struct.QuantifiedPair;
+import org.apache.asterix.lang.sqlpp.expression.CaseExpression;
import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil;
import org.apache.asterix.lang.sqlpp.util.SqlppRewriteUtil;
import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppExpressionScopingVisitor;
@@ -71,8 +75,9 @@
case BETWEEN:
case NOT_BETWEEN:
return processBetweenOperator(operatorExpr, opType);
- default:
- break;
+ case DISTINCT:
+ case NOT_DISTINCT:
+ return processDistinctOperator(operatorExpr, opType);
}
return operatorExpr;
}
@@ -144,18 +149,83 @@
Expression targetCopy = (Expression) SqlppRewriteUtil.deepCopy(target);
Expression rightComparison = createOperatorExpression(OperatorType.LE, targetCopy, right,
operatorExpr.getHints(), operatorExpr.getSourceLocation());
- OperatorExpr andExpr = new OperatorExpr();
- andExpr.addOperand(leftComparison);
- andExpr.addOperand(rightComparison);
- andExpr.addOperator(OperatorType.AND);
- andExpr.setSourceLocation(operatorExpr.getSourceLocation());
- if (opType == OperatorType.BETWEEN) {
- return andExpr;
- } else {
- CallExpr callExpr = new CallExpr(new FunctionSignature(BuiltinFunctions.NOT),
- new ArrayList<>(Collections.singletonList(andExpr)));
- callExpr.setSourceLocation(operatorExpr.getSourceLocation());
- return callExpr;
+ Expression andExpr = createOperatorExpression(OperatorType.AND, leftComparison, rightComparison, null,
+ operatorExpr.getSourceLocation());
+ switch (opType) {
+ case BETWEEN:
+ return andExpr;
+ case NOT_BETWEEN:
+ CallExpr callExpr = new CallExpr(new FunctionSignature(BuiltinFunctions.NOT),
+ new ArrayList<>(Collections.singletonList(andExpr)));
+ callExpr.setSourceLocation(operatorExpr.getSourceLocation());
+ return callExpr;
+ default:
+ throw new IllegalArgumentException(String.valueOf(opType));
+ }
+ }
+
+ private Expression processDistinctOperator(OperatorExpr operatorExpr, OperatorType opType)
+ throws CompilationException {
+
+ // lhs IS NOT DISTINCT FROM rhs =>
+ // CASE
+ // WHEN (lhs = rhs) OR (lhs IS NULL AND rhs IS NULL) OR (lhs IS MISSING AND rhs IS MISSING)
+ // THEN TRUE
+ // ELSE FALSE
+ // END
+ //
+ // lhs IS DISTINCT FROM rhs => NOT ( lhs IS NOT DISTINCT FROM rhs )
+
+ Expression lhs = operatorExpr.getExprList().get(0);
+ Expression rhs = operatorExpr.getExprList().get(1);
+
+ Expression lhsEqRhs = createOperatorExpression(OperatorType.EQ, lhs, rhs, operatorExpr.getHints(),
+ operatorExpr.getSourceLocation());
+
+ CallExpr lhsIsNull = new CallExpr(new FunctionSignature(BuiltinFunctions.IS_NULL),
+ new ArrayList<>(Collections.singletonList((Expression) SqlppRewriteUtil.deepCopy(lhs))));
+ lhsIsNull.setSourceLocation(operatorExpr.getSourceLocation());
+
+ CallExpr rhsIsNull = new CallExpr(new FunctionSignature(BuiltinFunctions.IS_NULL),
+ new ArrayList<>(Collections.singletonList((Expression) SqlppRewriteUtil.deepCopy(rhs))));
+ rhsIsNull.setSourceLocation(operatorExpr.getSourceLocation());
+
+ CallExpr lhsIsMissing = new CallExpr(new FunctionSignature(BuiltinFunctions.IS_MISSING),
+ new ArrayList<>(Collections.singletonList((Expression) SqlppRewriteUtil.deepCopy(lhs))));
+ lhsIsMissing.setSourceLocation(operatorExpr.getSourceLocation());
+
+ CallExpr rhsIsMissing = new CallExpr(new FunctionSignature(BuiltinFunctions.IS_MISSING),
+ new ArrayList<>(Collections.singletonList((Expression) SqlppRewriteUtil.deepCopy(rhs))));
+ rhsIsMissing.setSourceLocation(operatorExpr.getSourceLocation());
+
+ Expression bothAreNull = createOperatorExpression(OperatorType.AND, lhsIsNull, rhsIsNull, null,
+ operatorExpr.getSourceLocation());
+
+ Expression bothAreMissing = createOperatorExpression(OperatorType.AND, lhsIsMissing, rhsIsMissing, null,
+ operatorExpr.getSourceLocation());
+
+ Expression bothAreNullOrMissing = createOperatorExpression(OperatorType.OR, bothAreNull, bothAreMissing, null,
+ operatorExpr.getSourceLocation());
+
+ Expression eqOrNullOrMissing = createOperatorExpression(OperatorType.OR, lhsEqRhs, bothAreNullOrMissing, null,
+ operatorExpr.getSourceLocation());
+
+ CaseExpression caseExpr = new CaseExpression(new LiteralExpr(TrueLiteral.INSTANCE),
+ new ArrayList<>(Collections.singletonList(eqOrNullOrMissing)),
+ new ArrayList<>(Collections.singletonList(new LiteralExpr(TrueLiteral.INSTANCE))),
+ new LiteralExpr(FalseLiteral.INSTANCE));
+ caseExpr.setSourceLocation(operatorExpr.getSourceLocation());
+
+ switch (opType) {
+ case NOT_DISTINCT:
+ return caseExpr;
+ case DISTINCT:
+ CallExpr callExpr = new CallExpr(new FunctionSignature(BuiltinFunctions.NOT),
+ new ArrayList<>(Collections.singletonList(caseExpr)));
+ callExpr.setSourceLocation(operatorExpr.getSourceLocation());
+ return callExpr;
+ default:
+ throw new IllegalArgumentException(String.valueOf(opType));
}
}
@@ -173,5 +243,4 @@
}
return comparison;
}
-
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index b240779..ca4d903 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -3264,6 +3264,7 @@
{
boolean not = false;
OperatorExpr op = null;
+ Token opToken = null;
Expression operand = null;
IExpressionAnnotation annotation = null;
}
@@ -3271,8 +3272,12 @@
operand = BetweenExpr()
(
- LOOKAHEAD(2)( <LT> | <GT> | <LE> | <GE> | <EQ> | <NE> | <LG> |<SIMILAR> | (<NOT> { not = true; })? <IN>)
+ LOOKAHEAD(3)( <LT> | <GT> | <LE> | <GE> | <EQ> | <NE> | <LG> |<SIMILAR> | (<NOT> { not = true; })? <IN> |
+ <IS> (<NOT> { not = true; })? <DISTINCT> { opToken = token; } <FROM> )
{
+ if (opToken == null) {
+ opToken = token;
+ }
Token hintToken = fetchHint(token,
SqlppHint.HASH_BROADCAST_JOIN_HINT, SqlppHint.INDEXED_NESTED_LOOP_JOIN_HINT,
SqlppHint.SKIP_SECONDARY_INDEX_SEARCH_HINT, SqlppHint.USE_SECONDARY_INDEX_SEARCH_HINT
@@ -3280,7 +3285,7 @@
if (hintToken != null) {
annotation = parseExpressionAnnotation(hintToken);
}
- String operator = token.image.toLowerCase();
+ String operator = opToken.image.toLowerCase();
if (operator.equals("<>")){
operator = "!=";
}
@@ -3382,7 +3387,9 @@
}
{
operand = LikeExpr()
- ( <IS>
+ (
+ LOOKAHEAD(3)
+ <IS>
(<NOT> { not = true; notToken = token; })?
(
<NULL> { fn = BuiltinFunctions.IS_NULL; } |