[ASTERIXDB-2986][COMP] Fix bug in ExtractFunctionsFromJoinConditionRule
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- Fix NullPointerException in ExtractFunctionsFromJoinConditionRule
when one condition could be extracted but another could not
- Add testcase
Change-Id: Ib2cca56f36c9270fc337aab97f5c29fbcbb51543
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/14083
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/optimizerts/queries/joins/query-ASTERIXDB-2986.sqlpp b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/joins/query-ASTERIXDB-2986.sqlpp
new file mode 100644
index 0000000..9507c4b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/joins/query-ASTERIXDB-2986.sqlpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+drop dataverse test1 if exists;
+create dataverse test1;
+use test1;
+
+create type DocumentType as open {
+};
+
+create type MetaType as open {
+ id:string
+};
+
+create dataset customer(DocumentType) with meta(MetaType) primary key meta().id;
+create dataset orders(DocumentType) with meta(MetaType) primary key meta().id;
+create dataset lineitem(DocumentType) with meta(MetaType) primary key meta().id;
+
+select count(*)
+from orders o, lineitem l, customer c
+where tobigint(l.l_orderkey) = o.o_orderkey
+and o.o_custkey + l.l_orderkey = c.c_custkey + l.l_orderkey;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/joins/query-ASTERIXDB-2986.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/joins/query-ASTERIXDB-2986.plan
new file mode 100644
index 0000000..4bbdb3e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/joins/query-ASTERIXDB-2986.plan
@@ -0,0 +1,39 @@
+-- DISTRIBUTE_RESULT |UNPARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |UNPARTITIONED|
+ -- STREAM_PROJECT |UNPARTITIONED|
+ -- ASSIGN |UNPARTITIONED|
+ -- AGGREGATE |UNPARTITIONED|
+ -- RANDOM_MERGE_EXCHANGE |PARTITIONED|
+ -- AGGREGATE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- NESTED_LOOP |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- HYBRID_HASH_JOIN [$$78][$$77] |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$78] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN (test1.orders) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$77] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN (test1.lineitem) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- BROADCAST_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN (test1.customer) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractFunctionsFromJoinConditionRule.java b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractFunctionsFromJoinConditionRule.java
index c615a94..71a8486 100644
--- a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractFunctionsFromJoinConditionRule.java
+++ b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractFunctionsFromJoinConditionRule.java
@@ -104,6 +104,7 @@
} else if (AlgebricksBuiltinFunctions.isComparisonFunction(fi) || isComparisonFunction(fi)) {
for (Mutable<ILogicalExpression> exprRef : fexp.getArguments()) {
if (exprRef.getValue().getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+ boolean argModified = false;
SourceLocation exprRefSourceLoc = exprRef.getValue().getSourceLocation();
LogicalVariable newVar = context.newVar();
AssignOperator newAssign = new AssignOperator(newVar,
@@ -123,7 +124,7 @@
// place assign on left branch
newAssign.getInputs().add(new MutableObject<ILogicalOperator>(leftBranch));
leftBranchRef.setValue(newAssign);
- modified = true;
+ argModified = true;
} else {
Mutable<ILogicalOperator> rightBranchRef = joinOp.getInputs().get(1);
ILogicalOperator rightBranch = rightBranchRef.getValue();
@@ -133,17 +134,18 @@
// place assign on right branch
newAssign.getInputs().add(new MutableObject<ILogicalOperator>(rightBranch));
rightBranchRef.setValue(newAssign);
- modified = true;
+ argModified = true;
}
}
- if (modified) {
+ if (argModified) {
// Replace original expr with variable reference.
VariableReferenceExpression newVarRef = new VariableReferenceExpression(newVar);
newVarRef.setSourceLocation(exprRefSourceLoc);
exprRef.setValue(newVarRef);
context.computeAndSetTypeEnvironmentForOperator(newAssign);
context.computeAndSetTypeEnvironmentForOperator(joinOp);
+ modified = true;
}
}
}