>From Ritik Raj <[email protected]>:
Ritik Raj has uploaded this change for review. (
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19314 )
Change subject: [ASTERIXDB-3548][COMP] Handled merged expected schema, while
projection consolidation
......................................................................
[ASTERIXDB-3548][COMP] Handled merged expected schema, while projection
consolidation
- user model changes: no
- storage format changes: no
- interface changes: yes
Details:
Added SchemaCloner to clone the mergedSchema created after project consolidation
Patch-seq: 3
Ext-ref: MB-63032
Change-Id: I5541a4f21edd50665e91a2f443118d705f0f1724
---
M
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/PushdownExpressionReplaceVariableVisitor.java
A
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/visitor/ExpectedSchemaTreeVisitor.java
A
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/visitor/ExpectedSchemaVariablesSubstituteVisitor.java
M
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/IExpectedSchemaNode.java
A
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/ExpectedSchemaCloneVisitor.java
A
hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/ExpectedSchemaSubstituteVariablesVisitor.java
M
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ConsolidateProjectionAndFilterExpressionsProcessor.java
M
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractExpectedSchemaNode.java
8 files changed, 599 insertions(+), 6 deletions(-)
git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb
refs/changes/14/19314/1
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ConsolidateProjectionAndFilterExpressionsProcessor.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ConsolidateProjectionAndFilterExpressionsProcessor.java
index f9136d2..088bb36 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ConsolidateProjectionAndFilterExpressionsProcessor.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ConsolidateProjectionAndFilterExpressionsProcessor.java
@@ -20,6 +20,7 @@
import static
org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression.TRUE;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -30,8 +31,11 @@
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.optimizer.rules.pushdown.PushdownContext;
import
org.apache.asterix.optimizer.rules.pushdown.descriptor.ScanDefineDescriptor;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.ExpectedSchemaCloneVisitor;
+import org.apache.asterix.optimizer.rules.pushdown.schema.IExpectedSchemaNode;
import
org.apache.asterix.optimizer.rules.pushdown.schema.RootExpectedSchemaNode;
import
org.apache.asterix.optimizer.rules.pushdown.visitor.ExpectedSchemaMergerVisitor;
+import
org.apache.asterix.optimizer.rules.pushdown.visitor.ExpectedSchemaVariablesSubstituteVisitor;
import org.apache.asterix.runtime.projection.FunctionCallInformation;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -48,13 +52,21 @@
*/
public class ConsolidateProjectionAndFilterExpressionsProcessor extends
AbstractPushdownProcessor {
private final AllVariablesSubstituteVisitor substituteVisitor;
+ private final ExpectedSchemaCloneVisitor schemaCloneVisitor;
+ private final ExpectedSchemaVariablesSubstituteVisitor
schemaSubstituteVisitor;
private final ExpectedSchemaMergerVisitor schemaMergerVisitor;
+ private final List<LogicalVariable> scanVariables;
+ private final boolean assemblyAvoidanceEnabled;
public ConsolidateProjectionAndFilterExpressionsProcessor(PushdownContext
pushdownContext,
IOptimizationContext context) {
super(pushdownContext, context);
+ scanVariables = new ArrayList<>();
substituteVisitor = new AllVariablesSubstituteVisitor();
schemaMergerVisitor = new ExpectedSchemaMergerVisitor();
+ schemaCloneVisitor = new ExpectedSchemaCloneVisitor();
+ schemaSubstituteVisitor = new
ExpectedSchemaVariablesSubstituteVisitor(scanVariables);
+ assemblyAvoidanceEnabled =
context.getPhysicalOptimizationConfig().isColumnAssemblyAvoidanceEnabled();
}
@Override
@@ -79,6 +91,7 @@
RootExpectedSchemaNode mergedRoot = null;
RootExpectedSchemaNode mergedMetaRoot = null;
+ scanVariables.clear();
// First combine filters and projected fields
for (ScanDefineDescriptor descriptor : scanDefineDescriptors) {
Map<ILogicalExpression, ARecordType> scanPaths =
descriptor.getFilterPaths();
@@ -90,6 +103,7 @@
filterExpr = or(filterExpr, descriptor.getFilterExpression());
+ scanVariables.add(descriptor.getVariable());
mergedRoot = schemaMergerVisitor.merge(mergedRoot,
descriptor.getRecordNode());
mergedMetaRoot = schemaMergerVisitor.merge(mergedMetaRoot,
descriptor.getMetaNode());
}
@@ -107,8 +121,21 @@
descriptor.setRangeFilterExpression(cloneAndSubstituteVariable(scanVariable,
rangeFilterExpr));
descriptor.setFilterExpression(cloneAndSubstituteVariable(scanVariable,
filterExpr));
- descriptor.setRecordNode(mergedRoot);
- descriptor.setMetaNode(mergedMetaRoot);
+
+ if (assemblyAvoidanceEnabled) {
+ IExpectedSchemaNode clonedMergedRoot =
mergedRoot.accept(schemaCloneVisitor, null);
+ schemaSubstituteVisitor.traverse(scanVariable,
clonedMergedRoot, descriptor.getRecordNode());
+ descriptor.setRecordNode((RootExpectedSchemaNode)
clonedMergedRoot);
+
+ if (mergedMetaRoot != null) {
+ IExpectedSchemaNode clonedMetaMergedRoot =
mergedMetaRoot.accept(schemaCloneVisitor, null);
+ schemaSubstituteVisitor.traverse(scanVariable,
clonedMetaMergedRoot, descriptor.getMetaNode());
+ descriptor.setMetaNode((RootExpectedSchemaNode)
clonedMetaMergedRoot);
+ }
+ } else {
+ descriptor.setRecordNode(mergedRoot);
+ descriptor.setMetaNode(mergedMetaRoot);
+ }
}
return true;
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractExpectedSchemaNode.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractExpectedSchemaNode.java
index c7ee270..3766c4d 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractExpectedSchemaNode.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractExpectedSchemaNode.java
@@ -24,8 +24,8 @@
import org.apache.hyracks.api.exceptions.SourceLocation;
abstract class AbstractExpectedSchemaNode implements IExpectedSchemaNode {
- protected final AbstractFunctionCallExpression parentExpression;
- protected final ILogicalExpression expression;
+ protected AbstractFunctionCallExpression parentExpression;
+ protected ILogicalExpression expression;
private AbstractComplexExpectedSchemaNode parent;
// fieldOrdinal determines the strict ordering in which
@@ -49,6 +49,16 @@
}
@Override
+ public void setExpression(ILogicalExpression expression) {
+ this.expression = expression;
+ }
+
+ @Override
+ public void setParentExpression(AbstractFunctionCallExpression
parentExpression) {
+ this.parentExpression = parentExpression;
+ }
+
+ @Override
public final AbstractComplexExpectedSchemaNode getParent() {
return parent;
}
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/ExpectedSchemaCloneVisitor.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/ExpectedSchemaCloneVisitor.java
new file mode 100644
index 0000000..787d112
--- /dev/null
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/ExpectedSchemaCloneVisitor.java
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.optimizer.rules.pushdown.schema;
+
+import java.util.Map;
+
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+
+/**
+ * A special case of MergeVisitor, with cloning the pExpr and expr in node
+ */
+public class ExpectedSchemaCloneVisitor implements
IExpectedSchemaNodeVisitor<IExpectedSchemaNode, Void> {
+ private AbstractComplexExpectedSchemaNode currentParent;
+
+ @Override
+ public IExpectedSchemaNode visit(RootExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ if (node.isAllFields() || node.isEmpty()) {
+ return node;
+ }
+
+ RootExpectedSchemaNode clonedRoot = (RootExpectedSchemaNode)
RootExpectedSchemaNode.ALL_FIELDS_ROOT_NODE
+ .replaceIfNeeded(ExpectedSchemaNodeType.OBJECT, null, null);
+ cloneObjectFields(clonedRoot, node.getChildren());
+ clonedRoot.addAllFieldNameIds(node);
+ return clonedRoot;
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(ObjectExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ ILogicalExpression clonedParentExpr =
node.getParentExpression().cloneExpression();
+ ILogicalExpression clonedExpr;
+ if (node.getParentExpression() == node.getExpression()) {
+ clonedExpr = clonedParentExpr;
+ } else {
+ clonedExpr = node.getExpression().cloneExpression();
+ }
+ ObjectExpectedSchemaNode clonedObject = new
ObjectExpectedSchemaNode(currentParent,
+ (AbstractFunctionCallExpression) clonedParentExpr, clonedExpr);
+ clonedObject.addAllFieldNameIds(node);
+ cloneObjectFields(clonedObject, node.getChildren());
+ return clonedObject;
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(ArrayExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ ILogicalExpression clonedParentExpr =
node.getParentExpression().cloneExpression();
+ ILogicalExpression clonedExpr;
+ if (node.getParentExpression() == node.getExpression()) {
+ clonedExpr = clonedParentExpr;
+ } else {
+ clonedExpr = node.getExpression().cloneExpression();
+ }
+ ArrayExpectedSchemaNode clonedArray = new
ArrayExpectedSchemaNode(currentParent,
+ (AbstractFunctionCallExpression) clonedParentExpr, clonedExpr);
+ AbstractComplexExpectedSchemaNode previousParent = currentParent;
+ currentParent = clonedArray;
+ IExpectedSchemaNode clonedItem = node.getChild().accept(this, null);
+ clonedArray.addChild(clonedItem);
+ currentParent = previousParent;
+
+ return clonedArray;
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(UnionExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ ILogicalExpression clonedParentExpr =
node.getParentExpression().cloneExpression();
+ UnionExpectedSchemaNode clonedUnion =
+ new UnionExpectedSchemaNode(currentParent,
(AbstractFunctionCallExpression) clonedParentExpr);
+ AbstractComplexExpectedSchemaNode previousParent = currentParent;
+ currentParent = clonedUnion;
+ for (Map.Entry<ExpectedSchemaNodeType,
AbstractComplexExpectedSchemaNode> nodeChild : node.getChildren()) {
+ IExpectedSchemaNode mergedChild =
nodeChild.getValue().accept(this, null);
+ clonedUnion.addChild((AbstractComplexExpectedSchemaNode)
mergedChild);
+ }
+ currentParent = previousParent;
+ return clonedUnion;
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(AnyExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ return new AnyExpectedSchemaNode(currentParent,
+ (AbstractFunctionCallExpression)
node.getParentExpression().cloneExpression());
+ }
+
+ private void cloneObjectFields(ObjectExpectedSchemaNode objectNode,
Map<String, IExpectedSchemaNode> children)
+ throws AlgebricksException {
+ for (Map.Entry<String, IExpectedSchemaNode> child :
children.entrySet()) {
+ String fieldName = child.getKey();
+ IExpectedSchemaNode clonedChild = child.getValue().accept(this,
null);
+ objectNode.addChild(fieldName, -1, clonedChild);
+ }
+ }
+}
\ No newline at end of file
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/IExpectedSchemaNode.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/IExpectedSchemaNode.java
index 78766b0..4c25e86 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/IExpectedSchemaNode.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/IExpectedSchemaNode.java
@@ -59,6 +59,20 @@
ILogicalExpression getExpression();
/**
+ * Set expression of a node
+ *
+ * @param expression new expression
+ */
+ void setExpression(ILogicalExpression expression);
+
+ /**
+ * Set parent expression of a node
+ *
+ * @param parentExpression new parent expression
+ */
+ void setParentExpression(AbstractFunctionCallExpression parentExpression);
+
+ /**
* Set parent of a node
*
* @param parent new parent
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/visitor/ExpectedSchemaTreeVisitor.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/visitor/ExpectedSchemaTreeVisitor.java
new file mode 100644
index 0000000..8b40403
--- /dev/null
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/visitor/ExpectedSchemaTreeVisitor.java
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.optimizer.rules.pushdown.visitor;
+
+import java.util.List;
+import java.util.Map;
+
+import
org.apache.asterix.optimizer.rules.pushdown.schema.AbstractComplexExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.AnyExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.ArrayExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.ExpectedSchemaNodeType;
+import org.apache.asterix.optimizer.rules.pushdown.schema.IExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.IExpectedSchemaNodeVisitor;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.ObjectExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.RootExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.UnionExpectedSchemaNode;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.ExpectedSchemaSubstituteVariablesVisitor;
+
+public class ExpectedSchemaTreeVisitor implements
IExpectedSchemaNodeVisitor<IExpectedSchemaNode, Void> {
+
+ private final ExpectedSchemaSubstituteVariablesVisitor variablesVisitor;
+
+ public ExpectedSchemaTreeVisitor(Map<LogicalVariable, LogicalVariable>
mappedVariables,
+ List<LogicalVariable> scanVariables) {
+ this.variablesVisitor = new
ExpectedSchemaSubstituteVariablesVisitor(mappedVariables, scanVariables);
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(RootExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ replacer(node.getExpression());
+ replacer(node.getParentExpression());
+ for (Map.Entry<String, IExpectedSchemaNode> childNode :
node.getChildren().entrySet()) {
+ childNode.getValue().accept(this, arg);
+ }
+ return node;
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(ObjectExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ replacer(node.getExpression());
+ replacer(node.getParentExpression());
+ for (Map.Entry<String, IExpectedSchemaNode> childNode :
node.getChildren().entrySet()) {
+ childNode.getValue().accept(this, arg);
+ }
+ return node;
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(ArrayExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ replacer(node.getParentExpression());
+ replacer(node.getExpression());
+ node.getChild().accept(this, arg);
+ return node;
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(UnionExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ replacer(node.getParentExpression());
+ replacer(node.getExpression());
+ for (Map.Entry<ExpectedSchemaNodeType,
AbstractComplexExpectedSchemaNode> nodeChild : node.getChildren()) {
+ nodeChild.getValue().accept(this, arg);
+ }
+ return node;
+ }
+
+ @Override
+ public IExpectedSchemaNode visit(AnyExpectedSchemaNode node, Void arg)
throws AlgebricksException {
+ replacer(node.getParentExpression());
+ replacer(node.getExpression());
+ return node;
+ }
+
+ private void replacer(ILogicalExpression expr) throws AlgebricksException {
+ if (expr == null) {
+ return;
+ }
+ expr.accept(variablesVisitor, null);
+ }
+
+ public void setCurrentScanVariable(LogicalVariable currentScanVariable) {
+ variablesVisitor.setCurrentScanVariable(currentScanVariable);
+ }
+}
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/visitor/ExpectedSchemaVariablesSubstituteVisitor.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/visitor/ExpectedSchemaVariablesSubstituteVisitor.java
new file mode 100644
index 0000000..e47316e
--- /dev/null
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/visitor/ExpectedSchemaVariablesSubstituteVisitor.java
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.optimizer.rules.pushdown.visitor;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import
org.apache.asterix.optimizer.rules.pushdown.schema.AbstractComplexExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.AnyExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.ArrayExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.ExpectedSchemaNodeType;
+import org.apache.asterix.optimizer.rules.pushdown.schema.IExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.IExpectedSchemaNodeVisitor;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.ObjectExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.RootExpectedSchemaNode;
+import
org.apache.asterix.optimizer.rules.pushdown.schema.UnionExpectedSchemaNode;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.ExpectedSchemaSubstituteVariablesVisitor;
+
+public class ExpectedSchemaVariablesSubstituteVisitor implements
IExpectedSchemaNodeVisitor<Void, IExpectedSchemaNode> {
+ private final Map<LogicalVariable, LogicalVariable> mappedVariables;
+ private final ExpectedSchemaTreeVisitor schemaTreeVisitor;
+ private final ExpectedSchemaSubstituteVariablesVisitor
substituteVariablesVisitor;
+
+ public ExpectedSchemaVariablesSubstituteVisitor(List<LogicalVariable>
scanVariables) {
+ this.mappedVariables = new HashMap<>();
+ this.schemaTreeVisitor = new
ExpectedSchemaTreeVisitor(mappedVariables, scanVariables);
+ this.substituteVariablesVisitor = new
ExpectedSchemaSubstituteVariablesVisitor(mappedVariables, scanVariables);
+ }
+
+ public void traverse(LogicalVariable currentScanVariable,
IExpectedSchemaNode schemaNode,
+ IExpectedSchemaNode recordNode) throws AlgebricksException {
+ substituteVariablesVisitor.setCurrentScanVariable(currentScanVariable);
+ schemaTreeVisitor.setCurrentScanVariable(currentScanVariable);
+ schemaNode.accept(this, recordNode);
+ }
+
+ @Override
+ public Void visit(RootExpectedSchemaNode mergedNode, IExpectedSchemaNode
arg) throws AlgebricksException {
+ if (!(arg instanceof RootExpectedSchemaNode)) {
+ throw new IllegalArgumentException("Cannot substitute root node
with non-root node");
+ }
+
+ RootExpectedSchemaNode argRoot = (RootExpectedSchemaNode) arg;
+ if (mergedNode.isAllFields() || argRoot.isAllFields()) {
+ return null;
+ }
+
+ if (argRoot.isEmpty()) {
+ // I don't think, there should be a replacement
+ // because noVariable must be being used.
+ }
+
+ substitute(mergedNode, argRoot);
+ traverseObjectFields(mergedNode.getChildren(), argRoot.getChildren());
+ return null;
+ }
+
+ @Override
+ public Void visit(ObjectExpectedSchemaNode mergedNode, IExpectedSchemaNode
arg) throws AlgebricksException {
+ if (arg == null) {
+ // should we traverse down and use the mapped expression
+ mergedNode.accept(schemaTreeVisitor, null);
+ return null;
+ }
+ if (!(arg instanceof ObjectExpectedSchemaNode)) {
+ throw new IllegalArgumentException("Should have been an object
node");
+ }
+ ObjectExpectedSchemaNode argRoot = (ObjectExpectedSchemaNode) arg;
+ substitute(mergedNode, argRoot);
+ traverseObjectFields(mergedNode.getChildren(), argRoot.getChildren());
+ return null;
+ }
+
+ @Override
+ public Void visit(ArrayExpectedSchemaNode mergedNode, IExpectedSchemaNode
arg) throws AlgebricksException {
+ if (arg == null) {
+ // should we traverse down and use the mapped expression
+ mergedNode.accept(schemaTreeVisitor, null);
+ return null;
+ }
+ if (!(arg instanceof ArrayExpectedSchemaNode)) {
+ throw new IllegalArgumentException("Should have been an array
node");
+ }
+ ArrayExpectedSchemaNode argRoot = (ArrayExpectedSchemaNode) arg;
+ substitute(mergedNode, argRoot);
+ mergedNode.getChild().accept(this, argRoot.getChild());
+ return null;
+ }
+
+ @Override
+ public Void visit(UnionExpectedSchemaNode mergedNode, IExpectedSchemaNode
arg) throws AlgebricksException {
+ if (arg == null) {
+ // should we traverse down and use the mapped expression
+ mergedNode.accept(schemaTreeVisitor, null);
+ return null;
+ }
+ mergedNode.getParentExpression().accept(substituteVariablesVisitor,
null);
+ mergedNode.getExpression().accept(substituteVariablesVisitor, null);
+ if (arg instanceof UnionExpectedSchemaNode) {
+ UnionExpectedSchemaNode argRoot = (UnionExpectedSchemaNode) arg;
+ substitute(mergedNode, argRoot);
+ for (Map.Entry<ExpectedSchemaNodeType,
AbstractComplexExpectedSchemaNode> nodeChild : mergedNode
+ .getChildren()) {
+ IExpectedSchemaNode mergedChild = nodeChild.getValue();
+ IExpectedSchemaNode argChild =
argRoot.getChild(mergedChild.getType());
+ substitute(mergedChild, argChild);
+ mergedChild.accept(this, argChild);
+ }
+ } else {
+ ExpectedSchemaNodeType nodeType = arg.getType();
+ IExpectedSchemaNode childNode = mergedNode.getChild(nodeType);
+ substitute(childNode, arg);
+ childNode.accept(this, arg);
+ // once this branch has been done, replace all other branches.
+ for (Map.Entry<ExpectedSchemaNodeType,
AbstractComplexExpectedSchemaNode> nodeChild : mergedNode
+ .getChildren()) {
+ IExpectedSchemaNode mergedChild = nodeChild.getValue();
+ if (mergedChild.getType() == nodeType) {
+ continue;
+ }
+ mergedChild.accept(schemaTreeVisitor, null);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(AnyExpectedSchemaNode mergedNode, IExpectedSchemaNode
arg) throws AlgebricksException {
+ if (arg == null) {
+ // should we traverse down and use the mapped expression
+
mergedNode.getParentExpression().accept(substituteVariablesVisitor, null);
+ mergedNode.getExpression().accept(substituteVariablesVisitor,
null);
+ return null;
+ }
+ substitute(mergedNode, arg);
+ return null;
+ }
+
+ private void traverseObjectFields(Map<String, IExpectedSchemaNode>
mergedFields,
+ Map<String, IExpectedSchemaNode> argFields) throws
AlgebricksException {
+ for (Map.Entry<String, IExpectedSchemaNode> mergedChild :
mergedFields.entrySet()) {
+ IExpectedSchemaNode argChild = argFields.get(mergedChild.getKey());
+ mergedChild.getValue().accept(this, argChild);
+ }
+ }
+
+ private void substitute(IExpectedSchemaNode mergedNode,
IExpectedSchemaNode arg) {
+ mapVariables(mergedNode.getParentExpression(),
arg.getParentExpression());
+ mergedNode.setParentExpression(arg.getParentExpression());
+ mergedNode.setExpression(arg.getExpression());
+ }
+
+ private void mapVariables(ILogicalExpression left, ILogicalExpression
right) {
+ if (left == null || right == null) {
+ return;
+ }
+ if (left.getExpressionTag() == LogicalExpressionTag.VARIABLE
+ && right.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+ LogicalVariable leftVar = ((VariableReferenceExpression)
left).getVariableReference();
+ LogicalVariable rightVar = ((VariableReferenceExpression)
right).getVariableReference();
+ if (leftVar != rightVar) {
+ mappedVariables.put(leftVar, rightVar);
+ }
+ return;
+ }
+ if (left.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL
+ && right.getExpressionTag() ==
LogicalExpressionTag.FUNCTION_CALL) {
+ AbstractFunctionCallExpression leftFunction =
(AbstractFunctionCallExpression) left;
+ AbstractFunctionCallExpression rightFunction =
(AbstractFunctionCallExpression) right;
+ if (leftFunction.getFunctionIdentifier() ==
rightFunction.getFunctionIdentifier()) {
+ if (leftFunction.getArguments().size() < 2) {
+ return;
+ }
+ int argSize = leftFunction.getArguments().size();
+ ILogicalExpression leftLastArg =
leftFunction.getArguments().get(argSize - 1).getValue();
+ ILogicalExpression rightLastArg =
rightFunction.getArguments().get(argSize - 1).getValue();
+ if (leftLastArg.equals(rightLastArg)) {
+ mapVariables(leftFunction.getArguments().get(argSize -
2).getValue(),
+ rightFunction.getArguments().get(argSize -
2).getValue());
+ }
+ }
+ }
+ }
+}
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/PushdownExpressionReplaceVariableVisitor.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/PushdownExpressionReplaceVariableVisitor.java
index b6b9a3e..c47a222 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/PushdownExpressionReplaceVariableVisitor.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/visitor/PushdownExpressionReplaceVariableVisitor.java
@@ -308,8 +308,6 @@
context.computeAndSetTypeEnvironmentForOperator(op);
// removing all the projections, and added IntroduceProjectsRule after
this to add back the necessary ones.
parentOperator.getInputs().get(childIndex).setValue(op.getInputs().get(0).getValue());
- context.computeAndSetTypeEnvironmentForOperator(parentOperator);
- parentOperator.recomputeSchema();
return true;
}
diff --git
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/ExpectedSchemaSubstituteVariablesVisitor.java
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/ExpectedSchemaSubstituteVariablesVisitor.java
new file mode 100644
index 0000000..1ceaf7f
--- /dev/null
+++
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/ExpectedSchemaSubstituteVariablesVisitor.java
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+package org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.AggregateFunctionCallExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.StatefulFunctionCallExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import
org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalExpressionVisitor;
+
+public class ExpectedSchemaSubstituteVariablesVisitor implements
ILogicalExpressionVisitor<Void, Void> {
+ private final Map<LogicalVariable, LogicalVariable> mappedVariables;
+ private final List<LogicalVariable> scanVariables;
+ private LogicalVariable currentScanVariable;
+
+ public ExpectedSchemaSubstituteVariablesVisitor(Map<LogicalVariable,
LogicalVariable> mappedVariables,
+ List<LogicalVariable> scanVariables) {
+ this.mappedVariables = mappedVariables;
+ this.scanVariables = scanVariables;
+ }
+
+ @Override
+ public Void visitConstantExpression(ConstantExpression expr, Void arg)
throws AlgebricksException {
+ return null;
+ }
+
+ @Override
+ public Void visitVariableReferenceExpression(VariableReferenceExpression
expr, Void arg)
+ throws AlgebricksException {
+ LogicalVariable var = expr.getVariableReference();
+ // check first for scanVariable
+ if (scanVariables.contains(var)) {
+ expr.setVariable(currentScanVariable);
+ return null;
+ }
+ LogicalVariable mappedVar = mappedVariables.get(var);
+ if (mappedVar != null) {
+ expr.setVariable(mappedVar);
+ }
+ return null;
+ }
+
+ @Override
+ public Void
visitAggregateFunctionCallExpression(AggregateFunctionCallExpression expr, Void
arg)
+ throws AlgebricksException {
+ visitArgs(expr.getArguments(), arg);
+ return null;
+ }
+
+ @Override
+ public Void visitScalarFunctionCallExpression(ScalarFunctionCallExpression
expr, Void arg)
+ throws AlgebricksException {
+ visitArgs(expr.getArguments(), arg);
+ return null;
+ }
+
+ @Override
+ public Void
visitStatefulFunctionCallExpression(StatefulFunctionCallExpression expr, Void
arg)
+ throws AlgebricksException {
+ visitArgs(expr.getArguments(), arg);
+ return null;
+ }
+
+ @Override
+ public Void
visitUnnestingFunctionCallExpression(UnnestingFunctionCallExpression expr, Void
arg)
+ throws AlgebricksException {
+ visitArgs(expr.getArguments(), arg);
+ return null;
+ }
+
+ private void visitArgs(List<Mutable<ILogicalExpression>> args, Void
variable) throws AlgebricksException {
+ for (Mutable<ILogicalExpression> funcArg : args) {
+ funcArg.getValue().accept(this, null);
+ }
+ }
+
+ public void setCurrentScanVariable(LogicalVariable currentScanVariable) {
+ this.currentScanVariable = currentScanVariable;
+ }
+}
\ No newline at end of file
--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19314
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: I5541a4f21edd50665e91a2f443118d705f0f1724
Gerrit-Change-Number: 19314
Gerrit-PatchSet: 1
Gerrit-Owner: Ritik Raj <[email protected]>
Gerrit-MessageType: newchange