Merge branch 'alamouda/adding-external-indexes'
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/base/LogicalOperatorTag.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/base/LogicalOperatorTag.java
index bee4906..b9596be 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/base/LogicalOperatorTag.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/base/LogicalOperatorTag.java
@@ -45,5 +45,6 @@
     INSERT_DELETE,
     INDEX_INSERT_DELETE,
     UPDATE,
-    EXTENSION_OPERATOR
+    EXTENSION_OPERATOR,
+    EXTERNAL_DATA_ACCESS_BY_RID
 }
\ No newline at end of file
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/base/PhysicalOperatorTag.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/base/PhysicalOperatorTag.java
index c9ef2f3..f166f6f 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/base/PhysicalOperatorTag.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/base/PhysicalOperatorTag.java
@@ -60,5 +60,6 @@
     SINGLE_PARTITION_INVERTED_INDEX_SEARCH,
     LENGTH_PARTITIONED_INVERTED_INDEX_SEARCH,
     PARTITIONINGSPLIT,
-    EXTENSION_OPERATOR
+    EXTENSION_OPERATOR,
+    EXTERNAL_ACCESS_BY_RID
 }
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/ExternalDataAccessByRIDOperator.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/ExternalDataAccessByRIDOperator.java
new file mode 100644
index 0000000..875c6b1
--- /dev/null
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/ExternalDataAccessByRIDOperator.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed 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 from
+ * 
+ *     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 edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical;
+
+import java.util.List;
+
+import org.apache.commons.lang3.mutable.Mutable;
+
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
+import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IOperatorSchema;
+import edu.uci.ics.hyracks.algebricks.core.algebra.properties.VariablePropagationPolicy;
+import edu.uci.ics.hyracks.algebricks.core.algebra.typing.ITypingContext;
+import edu.uci.ics.hyracks.algebricks.core.algebra.typing.NonPropagatingTypeEnvironment;
+import edu.uci.ics.hyracks.algebricks.core.algebra.visitors.ILogicalExpressionReferenceTransform;
+import edu.uci.ics.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
+
+public class ExternalDataAccessByRIDOperator extends AbstractScanOperator{
+
+	private final List<Object> variableTypes; // TODO: get rid of this and
+	protected final Mutable<ILogicalExpression> expression;
+    
+    public ExternalDataAccessByRIDOperator(List<LogicalVariable> variables, Mutable<ILogicalExpression> expression,
+            List<Object> variableTypes) {
+        super(variables);
+        this.expression = expression;
+        this.variableTypes = variableTypes;
+    }
+
+    @Override
+    public LogicalOperatorTag getOperatorTag() {
+        return LogicalOperatorTag.EXTERNAL_DATA_ACCESS_BY_RID;
+    }
+
+    @Override
+    public IVariableTypeEnvironment computeOutputTypeEnvironment(ITypingContext ctx) throws AlgebricksException {
+        IVariableTypeEnvironment env = new NonPropagatingTypeEnvironment(ctx.getExpressionTypeComputer(), ctx.getMetadataProvider());
+            env.setVarType(variables.get(0), variableTypes.get(0));
+        return env;
+    }
+    
+    public List<Object> getVariableTypes() {
+        return variableTypes;
+    }
+    
+    @Override
+    public <R, T> R accept(ILogicalOperatorVisitor<R, T> visitor, T arg) throws AlgebricksException {
+        return visitor.visitExternalDataAccessByRIDOperator(this, arg);
+    }
+    
+    @Override
+    public boolean isMap() {
+        return false;
+    }
+    
+    @Override
+    public VariablePropagationPolicy getVariablePropagationPolicy() {
+        return new VariablePropagationPolicy() {
+            @Override
+            public void propagateVariables(IOperatorSchema target, IOperatorSchema... sources)
+                    throws AlgebricksException {
+            	target.addVariable(variables.get(0));
+            }
+        };
+    }
+
+    public Mutable<ILogicalExpression> getExpressionRef() {
+        return expression;
+    }
+    
+	@Override
+	public boolean acceptExpressionTransform(
+			ILogicalExpressionReferenceTransform visitor)
+			throws AlgebricksException {
+		return visitor.transform(expression);
+	}
+}
\ No newline at end of file
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/FDsAndEquivClassesVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/FDsAndEquivClassesVisitor.java
index cebddee..c739b23 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/FDsAndEquivClassesVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/FDsAndEquivClassesVisitor.java
@@ -50,6 +50,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
@@ -78,572 +79,593 @@
 
 public class FDsAndEquivClassesVisitor implements ILogicalOperatorVisitor<Void, IOptimizationContext> {
 
-    @Override
-    public Void visitAggregateOperator(AggregateOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        ctx.putEquivalenceClassMap(op, new HashMap<LogicalVariable, EquivalenceClass>());
-        ctx.putFDList(op, new ArrayList<FunctionalDependency>());
-        return null;
-    }
+	@Override
+	public Void visitAggregateOperator(AggregateOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		ctx.putEquivalenceClassMap(op, new HashMap<LogicalVariable, EquivalenceClass>());
+		ctx.putFDList(op, new ArrayList<FunctionalDependency>());
+		return null;
+	}
 
-    @Override
-    public Void visitAssignOperator(AssignOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        ILogicalOperator inp1 = op.getInputs().get(0).getValue();
-        Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
-        ctx.putEquivalenceClassMap(op, eqClasses);
-        List<LogicalVariable> used = new ArrayList<LogicalVariable>();
-        VariableUtilities.getUsedVariables(op, used);
-        List<FunctionalDependency> fds1 = getOrComputeFDs(inp1, ctx);
-        List<FunctionalDependency> eFds = new ArrayList<FunctionalDependency>(fds1.size());
-        for (FunctionalDependency fd : fds1) {
-            if (fd.getTail().containsAll(used)) {
-                List<LogicalVariable> hd = new ArrayList<LogicalVariable>(fd.getHead());
-                List<LogicalVariable> tl = new ArrayList<LogicalVariable>(fd.getTail());
-                tl.addAll(op.getVariables());
-                FunctionalDependency fd2 = new FunctionalDependency(hd, tl);
-                eFds.add(fd2);
-            } else {
-                eFds.add(fd);
-            }
-        }
-        ctx.putFDList(op, eFds);
-        return null;
-    }
+	@Override
+	public Void visitAssignOperator(AssignOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		ILogicalOperator inp1 = op.getInputs().get(0).getValue();
+		Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
+		ctx.putEquivalenceClassMap(op, eqClasses);
+		List<LogicalVariable> used = new ArrayList<LogicalVariable>();
+		VariableUtilities.getUsedVariables(op, used);
+		List<FunctionalDependency> fds1 = getOrComputeFDs(inp1, ctx);
+		List<FunctionalDependency> eFds = new ArrayList<FunctionalDependency>(fds1.size());
+		for (FunctionalDependency fd : fds1) {
+			if (fd.getTail().containsAll(used)) {
+				List<LogicalVariable> hd = new ArrayList<LogicalVariable>(fd.getHead());
+				List<LogicalVariable> tl = new ArrayList<LogicalVariable>(fd.getTail());
+				tl.addAll(op.getVariables());
+				FunctionalDependency fd2 = new FunctionalDependency(hd, tl);
+				eFds.add(fd2);
+			} else {
+				eFds.add(fd);
+			}
+		}
+		ctx.putFDList(op, eFds);
+		return null;
+	}
 
-    @Override
-    public Void visitDataScanOperator(DataSourceScanOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        ILogicalOperator inp1 = op.getInputs().get(0).getValue();
-        Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
-        ctx.putEquivalenceClassMap(op, eqClasses);
-        List<FunctionalDependency> fds = new ArrayList<FunctionalDependency>(getOrComputeFDs(inp1, ctx));
-        ctx.putFDList(op, fds);
-        op.getDataSource().computeFDs(op.getVariables(), fds);
-        return null;
-    }
+	@Override
+	public Void visitDataScanOperator(DataSourceScanOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		ILogicalOperator inp1 = op.getInputs().get(0).getValue();
+		Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
+		ctx.putEquivalenceClassMap(op, eqClasses);
+		List<FunctionalDependency> fds = new ArrayList<FunctionalDependency>(getOrComputeFDs(inp1, ctx));
+		ctx.putFDList(op, fds);
+		op.getDataSource().computeFDs(op.getVariables(), fds);
+		return null;
+	}
 
-    @Override
-    public Void visitDistinctOperator(DistinctOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        ILogicalOperator op0 = op.getInputs().get(0).getValue();
-        List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
-        ctx.putFDList(op, functionalDependencies);
-        for (FunctionalDependency inherited : getOrComputeFDs(op0, ctx)) {
-            boolean isCoveredByDistinctByVars = true;
-            for (LogicalVariable v : inherited.getHead()) {
-                if (!op.isDistinctByVar(v)) {
-                    isCoveredByDistinctByVars = false;
-                }
-            }
-            if (isCoveredByDistinctByVars) {
-                List<LogicalVariable> newTail = new ArrayList<LogicalVariable>();
-                for (LogicalVariable v2 : inherited.getTail()) {
-                    if (op.isDistinctByVar(v2)) {
-                        newTail.add(v2);
-                    }
-                }
-                if (!newTail.isEmpty()) {
-                    List<LogicalVariable> newHead = new ArrayList<LogicalVariable>(inherited.getHead());
-                    FunctionalDependency newFd = new FunctionalDependency(newHead, newTail);
-                    functionalDependencies.add(newFd);
-                }
-            }
-        }
-        Set<LogicalVariable> gbySet = new HashSet<LogicalVariable>();
-        List<Mutable<ILogicalExpression>> expressions = op.getExpressions();
-        for (Mutable<ILogicalExpression> pRef : expressions) {
-            ILogicalExpression p = pRef.getValue();
-            if (p.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
-                VariableReferenceExpression v = (VariableReferenceExpression) p;
-                gbySet.add(v.getVariableReference());
-            }
-        }
-        LocalGroupingProperty lgp = new LocalGroupingProperty(gbySet);
+	@Override
+	public Void visitDistinctOperator(DistinctOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		ILogicalOperator op0 = op.getInputs().get(0).getValue();
+		List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
+		ctx.putFDList(op, functionalDependencies);
+		for (FunctionalDependency inherited : getOrComputeFDs(op0, ctx)) {
+			boolean isCoveredByDistinctByVars = true;
+			for (LogicalVariable v : inherited.getHead()) {
+				if (!op.isDistinctByVar(v)) {
+					isCoveredByDistinctByVars = false;
+				}
+			}
+			if (isCoveredByDistinctByVars) {
+				List<LogicalVariable> newTail = new ArrayList<LogicalVariable>();
+				for (LogicalVariable v2 : inherited.getTail()) {
+					if (op.isDistinctByVar(v2)) {
+						newTail.add(v2);
+					}
+				}
+				if (!newTail.isEmpty()) {
+					List<LogicalVariable> newHead = new ArrayList<LogicalVariable>(inherited.getHead());
+					FunctionalDependency newFd = new FunctionalDependency(newHead, newTail);
+					functionalDependencies.add(newFd);
+				}
+			}
+		}
+		Set<LogicalVariable> gbySet = new HashSet<LogicalVariable>();
+		List<Mutable<ILogicalExpression>> expressions = op.getExpressions();
+		for (Mutable<ILogicalExpression> pRef : expressions) {
+			ILogicalExpression p = pRef.getValue();
+			if (p.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+				VariableReferenceExpression v = (VariableReferenceExpression) p;
+				gbySet.add(v.getVariableReference());
+			}
+		}
+		LocalGroupingProperty lgp = new LocalGroupingProperty(gbySet);
 
-        Map<LogicalVariable, EquivalenceClass> equivalenceClasses = getOrComputeEqClasses(op0, ctx);
-        ctx.putEquivalenceClassMap(op, equivalenceClasses);
+		Map<LogicalVariable, EquivalenceClass> equivalenceClasses = getOrComputeEqClasses(op0, ctx);
+		ctx.putEquivalenceClassMap(op, equivalenceClasses);
 
-        lgp.normalizeGroupingColumns(equivalenceClasses, functionalDependencies);
-        Set<LogicalVariable> normSet = lgp.getColumnSet();
-        List<Mutable<ILogicalExpression>> newDistinctByList = new ArrayList<Mutable<ILogicalExpression>>();
-        for (Mutable<ILogicalExpression> p2Ref : expressions) {
-            ILogicalExpression p2 = p2Ref.getValue();
-            if (p2.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
-                VariableReferenceExpression var2 = (VariableReferenceExpression) p2;
-                LogicalVariable v2 = var2.getVariableReference();
-                if (normSet.contains(v2)) {
-                    newDistinctByList.add(p2Ref);
-                }
-            } else {
-                newDistinctByList.add(p2Ref);
-            }
-        }
-        expressions.clear();
-        expressions.addAll(newDistinctByList);
-        return null;
-    }
+		lgp.normalizeGroupingColumns(equivalenceClasses, functionalDependencies);
+		Set<LogicalVariable> normSet = lgp.getColumnSet();
+		List<Mutable<ILogicalExpression>> newDistinctByList = new ArrayList<Mutable<ILogicalExpression>>();
+		for (Mutable<ILogicalExpression> p2Ref : expressions) {
+			ILogicalExpression p2 = p2Ref.getValue();
+			if (p2.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+				VariableReferenceExpression var2 = (VariableReferenceExpression) p2;
+				LogicalVariable v2 = var2.getVariableReference();
+				if (normSet.contains(v2)) {
+					newDistinctByList.add(p2Ref);
+				}
+			} else {
+				newDistinctByList.add(p2Ref);
+			}
+		}
+		expressions.clear();
+		expressions.addAll(newDistinctByList);
+		return null;
+	}
 
-    @Override
-    public Void visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        ctx.putEquivalenceClassMap(op, new HashMap<LogicalVariable, EquivalenceClass>());
-        ctx.putFDList(op, new ArrayList<FunctionalDependency>());
-        return null;
-    }
+	@Override
+	public Void visitEmptyTupleSourceOperator(EmptyTupleSourceOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		ctx.putEquivalenceClassMap(op, new HashMap<LogicalVariable, EquivalenceClass>());
+		ctx.putFDList(op, new ArrayList<FunctionalDependency>());
+		return null;
+	}
 
-    @Override
-    public Void visitExchangeOperator(ExchangeOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        propagateFDsAndEquivClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitExchangeOperator(ExchangeOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		propagateFDsAndEquivClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitGroupByOperator(GroupByOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
-        List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
-        ctx.putEquivalenceClassMap(op, equivalenceClasses);
-        ctx.putFDList(op, functionalDependencies);
+	@Override
+	public Void visitGroupByOperator(GroupByOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
+		List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
+		ctx.putEquivalenceClassMap(op, equivalenceClasses);
+		ctx.putFDList(op, functionalDependencies);
 
-        List<FunctionalDependency> inheritedFDs = new ArrayList<FunctionalDependency>();
-        for (ILogicalPlan p : op.getNestedPlans()) {
-            for (Mutable<ILogicalOperator> r : p.getRoots()) {
-                ILogicalOperator op2 = r.getValue();
-                equivalenceClasses.putAll(getOrComputeEqClasses(op2, ctx));
-                inheritedFDs.addAll(getOrComputeFDs(op2, ctx));
-            }
-        }
+		List<FunctionalDependency> inheritedFDs = new ArrayList<FunctionalDependency>();
+		for (ILogicalPlan p : op.getNestedPlans()) {
+			for (Mutable<ILogicalOperator> r : p.getRoots()) {
+				ILogicalOperator op2 = r.getValue();
+				equivalenceClasses.putAll(getOrComputeEqClasses(op2, ctx));
+				inheritedFDs.addAll(getOrComputeFDs(op2, ctx));
+			}
+		}
 
-        ILogicalOperator op0 = op.getInputs().get(0).getValue();
-        inheritedFDs.addAll(getOrComputeFDs(op0, ctx));
-        Map<LogicalVariable, EquivalenceClass> inheritedEcs = getOrComputeEqClasses(op0, ctx);
-        for (FunctionalDependency inherited : inheritedFDs) {
-            boolean isCoveredByGbyOrDecorVars = true;
-            List<LogicalVariable> newHead = new ArrayList<LogicalVariable>(inherited.getHead().size());
-            for (LogicalVariable v : inherited.getHead()) {
-                LogicalVariable vnew = getNewGbyVar(op, v);
-                if (vnew == null) {
-                    vnew = getNewDecorVar(op, v);
-                    if (vnew == null) {
-                        isCoveredByGbyOrDecorVars = false;
-                    }
-                    break;
-                }
-                newHead.add(vnew);
-            }
+		ILogicalOperator op0 = op.getInputs().get(0).getValue();
+		inheritedFDs.addAll(getOrComputeFDs(op0, ctx));
+		Map<LogicalVariable, EquivalenceClass> inheritedEcs = getOrComputeEqClasses(op0, ctx);
+		for (FunctionalDependency inherited : inheritedFDs) {
+			boolean isCoveredByGbyOrDecorVars = true;
+			List<LogicalVariable> newHead = new ArrayList<LogicalVariable>(inherited.getHead().size());
+			for (LogicalVariable v : inherited.getHead()) {
+				LogicalVariable vnew = getNewGbyVar(op, v);
+				if (vnew == null) {
+					vnew = getNewDecorVar(op, v);
+					if (vnew == null) {
+						isCoveredByGbyOrDecorVars = false;
+					}
+					break;
+				}
+				newHead.add(vnew);
+			}
 
-            if (isCoveredByGbyOrDecorVars) {
-                List<LogicalVariable> newTail = new ArrayList<LogicalVariable>();
-                for (LogicalVariable v2 : inherited.getTail()) {
-                    LogicalVariable v3 = getNewGbyVar(op, v2);
-                    if (v3 != null) {
-                        newTail.add(v3);
-                    }
-                }
-                if (!newTail.isEmpty()) {
-                    FunctionalDependency newFd = new FunctionalDependency(newHead, newTail);
-                    functionalDependencies.add(newFd);
-                }
-            }
-        }
+			if (isCoveredByGbyOrDecorVars) {
+				List<LogicalVariable> newTail = new ArrayList<LogicalVariable>();
+				for (LogicalVariable v2 : inherited.getTail()) {
+					LogicalVariable v3 = getNewGbyVar(op, v2);
+					if (v3 != null) {
+						newTail.add(v3);
+					}
+				}
+				if (!newTail.isEmpty()) {
+					FunctionalDependency newFd = new FunctionalDependency(newHead, newTail);
+					functionalDependencies.add(newFd);
+				}
+			}
+		}
 
-        List<LogicalVariable> premiseGby = new LinkedList<LogicalVariable>();
-        List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> gByList = op.getGroupByList();
-        for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
-            premiseGby.add(p.first);
-        }
+		List<LogicalVariable> premiseGby = new LinkedList<LogicalVariable>();
+		List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> gByList = op.getGroupByList();
+		for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
+			premiseGby.add(p.first);
+		}
 
-        List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> decorList = op.getDecorList();
+		List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> decorList = op.getDecorList();
 
-        LinkedList<LogicalVariable> conclDecor = new LinkedList<LogicalVariable>();
-        for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : decorList) {
-            conclDecor.add(GroupByOperator.getDecorVariable(p));
-        }
-        if (!conclDecor.isEmpty()) {
-            functionalDependencies.add(new FunctionalDependency(premiseGby, conclDecor));
-        }
+		LinkedList<LogicalVariable> conclDecor = new LinkedList<LogicalVariable>();
+		for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : decorList) {
+			conclDecor.add(GroupByOperator.getDecorVariable(p));
+		}
+		if (!conclDecor.isEmpty()) {
+			functionalDependencies.add(new FunctionalDependency(premiseGby, conclDecor));
+		}
 
-        Set<LogicalVariable> gbySet = new HashSet<LogicalVariable>();
-        for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
-            ILogicalExpression expr = p.second.getValue();
-            if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
-                VariableReferenceExpression v = (VariableReferenceExpression) expr;
-                gbySet.add(v.getVariableReference());
-            }
-        }
-        LocalGroupingProperty lgp = new LocalGroupingProperty(gbySet);
-        lgp.normalizeGroupingColumns(inheritedEcs, inheritedFDs);
-        Set<LogicalVariable> normSet = lgp.getColumnSet();
-        List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> newGbyList = new ArrayList<Pair<LogicalVariable, Mutable<ILogicalExpression>>>();
-        boolean changed = false;
-        for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
-            ILogicalExpression expr = p.second.getValue();
-            if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
-                VariableReferenceExpression varRef = (VariableReferenceExpression) expr;
-                LogicalVariable v2 = varRef.getVariableReference();
-                EquivalenceClass ec2 = inheritedEcs.get(v2);
-                LogicalVariable v3;
-                if (ec2 != null && !ec2.representativeIsConst()) {
-                    v3 = ec2.getVariableRepresentative();
-                } else {
-                    v3 = v2;
-                }
-                if (normSet.contains(v3)) {
-                    newGbyList.add(p);
-                } else {
-                    changed = true;
-                    decorList.add(p);
-                }
-            } else {
-                newGbyList.add(p);
-            }
-        }
-        if (changed) {
-            AlgebricksConfig.ALGEBRICKS_LOGGER.fine(">>>> Group-by list changed from "
-                    + GroupByOperator.veListToString(gByList) + " to " + GroupByOperator.veListToString(newGbyList)
-                    + ".\n");
-        }
-        gByList.clear();
-        gByList.addAll(newGbyList);
-        return null;
-    }
+		Set<LogicalVariable> gbySet = new HashSet<LogicalVariable>();
+		for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
+			ILogicalExpression expr = p.second.getValue();
+			if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+				VariableReferenceExpression v = (VariableReferenceExpression) expr;
+				gbySet.add(v.getVariableReference());
+			}
+		}
+		LocalGroupingProperty lgp = new LocalGroupingProperty(gbySet);
+		lgp.normalizeGroupingColumns(inheritedEcs, inheritedFDs);
+		Set<LogicalVariable> normSet = lgp.getColumnSet();
+		List<Pair<LogicalVariable, Mutable<ILogicalExpression>>> newGbyList = new ArrayList<Pair<LogicalVariable, Mutable<ILogicalExpression>>>();
+		boolean changed = false;
+		for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : gByList) {
+			ILogicalExpression expr = p.second.getValue();
+			if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+				VariableReferenceExpression varRef = (VariableReferenceExpression) expr;
+				LogicalVariable v2 = varRef.getVariableReference();
+				EquivalenceClass ec2 = inheritedEcs.get(v2);
+				LogicalVariable v3;
+				if (ec2 != null && !ec2.representativeIsConst()) {
+					v3 = ec2.getVariableRepresentative();
+				} else {
+					v3 = v2;
+				}
+				if (normSet.contains(v3)) {
+					newGbyList.add(p);
+				} else {
+					changed = true;
+					decorList.add(p);
+				}
+			} else {
+				newGbyList.add(p);
+			}
+		}
+		if (changed) {
+			AlgebricksConfig.ALGEBRICKS_LOGGER.fine(">>>> Group-by list changed from "
+					+ GroupByOperator.veListToString(gByList) + " to " + GroupByOperator.veListToString(newGbyList)
+					+ ".\n");
+		}
+		gByList.clear();
+		gByList.addAll(newGbyList);
+		return null;
+	}
 
-    @Override
-    public Void visitInnerJoinOperator(InnerJoinOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
-        List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
-        ctx.putEquivalenceClassMap(op, equivalenceClasses);
-        ctx.putFDList(op, functionalDependencies);
-        ILogicalOperator op0 = op.getInputs().get(0).getValue();
-        ILogicalOperator op1 = op.getInputs().get(1).getValue();
-        functionalDependencies.addAll(getOrComputeFDs(op0, ctx));
-        functionalDependencies.addAll(getOrComputeFDs(op1, ctx));
-        equivalenceClasses.putAll(getOrComputeEqClasses(op0, ctx));
-        equivalenceClasses.putAll(getOrComputeEqClasses(op1, ctx));
-        ILogicalExpression expr = op.getCondition().getValue();
-        expr.getConstraintsAndEquivClasses(functionalDependencies, equivalenceClasses);
-        return null;
-    }
+	@Override
+	public Void visitInnerJoinOperator(InnerJoinOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
+		List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
+		ctx.putEquivalenceClassMap(op, equivalenceClasses);
+		ctx.putFDList(op, functionalDependencies);
+		ILogicalOperator op0 = op.getInputs().get(0).getValue();
+		ILogicalOperator op1 = op.getInputs().get(1).getValue();
+		functionalDependencies.addAll(getOrComputeFDs(op0, ctx));
+		functionalDependencies.addAll(getOrComputeFDs(op1, ctx));
+		equivalenceClasses.putAll(getOrComputeEqClasses(op0, ctx));
+		equivalenceClasses.putAll(getOrComputeEqClasses(op1, ctx));
+		ILogicalExpression expr = op.getCondition().getValue();
+		expr.getConstraintsAndEquivClasses(functionalDependencies, equivalenceClasses);
+		return null;
+	}
 
-    @Override
-    public Void visitLeftOuterJoinOperator(LeftOuterJoinOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
-        List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
-        ctx.putEquivalenceClassMap(op, equivalenceClasses);
-        ctx.putFDList(op, functionalDependencies);
-        ILogicalOperator opLeft = op.getInputs().get(0).getValue();
-        ILogicalOperator opRight = op.getInputs().get(1).getValue();
-        functionalDependencies.addAll(getOrComputeFDs(opLeft, ctx));
-        functionalDependencies.addAll(getOrComputeFDs(opRight, ctx));
-        equivalenceClasses.putAll(getOrComputeEqClasses(opLeft, ctx));
-        equivalenceClasses.putAll(getOrComputeEqClasses(opRight, ctx));
+	@Override
+	public Void visitLeftOuterJoinOperator(LeftOuterJoinOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
+		List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
+		ctx.putEquivalenceClassMap(op, equivalenceClasses);
+		ctx.putFDList(op, functionalDependencies);
+		ILogicalOperator opLeft = op.getInputs().get(0).getValue();
+		ILogicalOperator opRight = op.getInputs().get(1).getValue();
+		functionalDependencies.addAll(getOrComputeFDs(opLeft, ctx));
+		functionalDependencies.addAll(getOrComputeFDs(opRight, ctx));
+		equivalenceClasses.putAll(getOrComputeEqClasses(opLeft, ctx));
+		equivalenceClasses.putAll(getOrComputeEqClasses(opRight, ctx));
 
-        Collection<LogicalVariable> leftSideVars;
-        if (opLeft.getSchema() == null) {
-            leftSideVars = new LinkedList<LogicalVariable>();
-            VariableUtilities.getLiveVariables(opLeft, leftSideVars);
-            // actually, not all produced vars. are visible (due to projection)
-            // so using cached schema is better and faster
-        } else {
-            leftSideVars = opLeft.getSchema();
-        }
-        ILogicalExpression expr = op.getCondition().getValue();
-        expr.getConstraintsForOuterJoin(functionalDependencies, leftSideVars);
-        return null;
-    }
+		Collection<LogicalVariable> leftSideVars;
+		if (opLeft.getSchema() == null) {
+			leftSideVars = new LinkedList<LogicalVariable>();
+			VariableUtilities.getLiveVariables(opLeft, leftSideVars);
+			// actually, not all produced vars. are visible (due to projection)
+			// so using cached schema is better and faster
+		} else {
+			leftSideVars = opLeft.getSchema();
+		}
+		ILogicalExpression expr = op.getCondition().getValue();
+		expr.getConstraintsForOuterJoin(functionalDependencies, leftSideVars);
+		return null;
+	}
 
-    @Override
-    public Void visitLimitOperator(LimitOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        propagateFDsAndEquivClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitLimitOperator(LimitOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		propagateFDsAndEquivClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitNestedTupleSourceOperator(NestedTupleSourceOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        AbstractLogicalOperator op1 = (AbstractLogicalOperator) op.getDataSourceReference().getValue();
-        ILogicalOperator inp1 = op1.getInputs().get(0).getValue();
-        Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
-        ctx.putEquivalenceClassMap(op, eqClasses);
-        List<FunctionalDependency> fds = new ArrayList<FunctionalDependency>(getOrComputeFDs(inp1, ctx));
-        if (op1.getOperatorTag() == LogicalOperatorTag.GROUP) {
-            GroupByOperator gby = (GroupByOperator) op1;
-            LinkedList<LogicalVariable> tail = new LinkedList<LogicalVariable>();
-            for (LogicalVariable v : gby.getGbyVarList()) {
-                tail.add(v);
-                // all values for gby vars. are the same
-            }
-            FunctionalDependency gbyfd = new FunctionalDependency(new LinkedList<LogicalVariable>(), tail);
-            fds.add(gbyfd);
-        }
-        ctx.putFDList(op, fds);
-        return null;
-    }
+	@Override
+	public Void visitNestedTupleSourceOperator(NestedTupleSourceOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		AbstractLogicalOperator op1 = (AbstractLogicalOperator) op.getDataSourceReference().getValue();
+		ILogicalOperator inp1 = op1.getInputs().get(0).getValue();
+		Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
+		ctx.putEquivalenceClassMap(op, eqClasses);
+		List<FunctionalDependency> fds = new ArrayList<FunctionalDependency>(getOrComputeFDs(inp1, ctx));
+		if (op1.getOperatorTag() == LogicalOperatorTag.GROUP) {
+			GroupByOperator gby = (GroupByOperator) op1;
+			LinkedList<LogicalVariable> tail = new LinkedList<LogicalVariable>();
+			for (LogicalVariable v : gby.getGbyVarList()) {
+				tail.add(v);
+				// all values for gby vars. are the same
+			}
+			FunctionalDependency gbyfd = new FunctionalDependency(new LinkedList<LogicalVariable>(), tail);
+			fds.add(gbyfd);
+		}
+		ctx.putFDList(op, fds);
+		return null;
+	}
 
-    @Override
-    public Void visitOrderOperator(OrderOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        propagateFDsAndEquivClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitOrderOperator(OrderOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		propagateFDsAndEquivClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitPartitioningSplitOperator(PartitioningSplitOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        throw new NotImplementedException();
-    }
+	@Override
+	public Void visitPartitioningSplitOperator(PartitioningSplitOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		throw new NotImplementedException();
+	}
 
-    @Override
-    public Void visitProjectOperator(ProjectOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        propagateFDsAndEquivClassesForUsedVars(op, ctx, op.getVariables());
-        return null;
-    }
+	@Override
+	public Void visitProjectOperator(ProjectOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		propagateFDsAndEquivClassesForUsedVars(op, ctx, op.getVariables());
+		return null;
+	}
 
-    @Override
-    public Void visitReplicateOperator(ReplicateOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        propagateFDsAndEquivClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitReplicateOperator(ReplicateOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		propagateFDsAndEquivClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitRunningAggregateOperator(RunningAggregateOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        propagateFDsAndEquivClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitRunningAggregateOperator(RunningAggregateOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		propagateFDsAndEquivClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitScriptOperator(ScriptOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        propagateFDsAndEquivClassesForUsedVars(op, ctx, op.getInputVariables());
-        return null;
-    }
+	@Override
+	public Void visitScriptOperator(ScriptOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		propagateFDsAndEquivClassesForUsedVars(op, ctx, op.getInputVariables());
+		return null;
+	}
 
-    @Override
-    public Void visitSelectOperator(SelectOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
-        List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
-        ctx.putEquivalenceClassMap(op, equivalenceClasses);
-        ctx.putFDList(op, functionalDependencies);
-        ILogicalOperator op0 = op.getInputs().get(0).getValue();
-        functionalDependencies.addAll(getOrComputeFDs(op0, ctx));
-        equivalenceClasses.putAll(getOrComputeEqClasses(op0, ctx));
-        ILogicalExpression expr = op.getCondition().getValue();
-        expr.getConstraintsAndEquivClasses(functionalDependencies, equivalenceClasses);
-        return null;
-    }
+	@Override
+	public Void visitSelectOperator(SelectOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
+		List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
+		ctx.putEquivalenceClassMap(op, equivalenceClasses);
+		ctx.putFDList(op, functionalDependencies);
+		ILogicalOperator op0 = op.getInputs().get(0).getValue();
+		functionalDependencies.addAll(getOrComputeFDs(op0, ctx));
+		equivalenceClasses.putAll(getOrComputeEqClasses(op0, ctx));
+		ILogicalExpression expr = op.getCondition().getValue();
+		expr.getConstraintsAndEquivClasses(functionalDependencies, equivalenceClasses);
+		return null;
+	}
 
-    @Override
-    public Void visitSubplanOperator(SubplanOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
-        List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
-        ctx.putEquivalenceClassMap(op, equivalenceClasses);
-        ctx.putFDList(op, functionalDependencies);
-        for (ILogicalPlan p : op.getNestedPlans()) {
-            for (Mutable<ILogicalOperator> r : p.getRoots()) {
-                ILogicalOperator op2 = r.getValue();
-                equivalenceClasses.putAll(getOrComputeEqClasses(op2, ctx));
-                functionalDependencies.addAll(getOrComputeFDs(op2, ctx));
-            }
-        }
-        return null;
-    }
+	@Override
+	public Void visitSubplanOperator(SubplanOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		Map<LogicalVariable, EquivalenceClass> equivalenceClasses = new HashMap<LogicalVariable, EquivalenceClass>();
+		List<FunctionalDependency> functionalDependencies = new ArrayList<FunctionalDependency>();
+		ctx.putEquivalenceClassMap(op, equivalenceClasses);
+		ctx.putFDList(op, functionalDependencies);
+		for (ILogicalPlan p : op.getNestedPlans()) {
+			for (Mutable<ILogicalOperator> r : p.getRoots()) {
+				ILogicalOperator op2 = r.getValue();
+				equivalenceClasses.putAll(getOrComputeEqClasses(op2, ctx));
+				functionalDependencies.addAll(getOrComputeFDs(op2, ctx));
+			}
+		}
+		return null;
+	}
 
-    @Override
-    public Void visitUnionOperator(UnionAllOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        setEmptyFDsEqClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitUnionOperator(UnionAllOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		setEmptyFDsEqClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitUnnestMapOperator(UnnestMapOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        fdsEqClassesForAbstractUnnestOperator(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitUnnestMapOperator(UnnestMapOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		fdsEqClassesForAbstractUnnestOperator(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitUnnestOperator(UnnestOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        fdsEqClassesForAbstractUnnestOperator(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitExternalDataAccessByRIDOperator(ExternalDataAccessByRIDOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		fdsEqClassesForExternalAccessOperator(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitWriteOperator(WriteOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        // propagateFDsAndEquivClasses(op, ctx);
-        setEmptyFDsEqClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitUnnestOperator(UnnestOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		fdsEqClassesForAbstractUnnestOperator(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitDistributeResultOperator(DistributeResultOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        // propagateFDsAndEquivClasses(op, ctx);
-        setEmptyFDsEqClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitWriteOperator(WriteOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		// propagateFDsAndEquivClasses(op, ctx);
+		setEmptyFDsEqClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitWriteResultOperator(WriteResultOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        // propagateFDsAndEquivClasses(op, ctx);
-        setEmptyFDsEqClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitDistributeResultOperator(DistributeResultOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		// propagateFDsAndEquivClasses(op, ctx);
+		setEmptyFDsEqClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitInsertDeleteOperator(InsertDeleteOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        setEmptyFDsEqClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitWriteResultOperator(WriteResultOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		// propagateFDsAndEquivClasses(op, ctx);
+		setEmptyFDsEqClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitIndexInsertDeleteOperator(IndexInsertDeleteOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        setEmptyFDsEqClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitInsertDeleteOperator(InsertDeleteOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		setEmptyFDsEqClasses(op, ctx);
+		return null;
+	}
 
-    @Override
-    public Void visitSinkOperator(SinkOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        setEmptyFDsEqClasses(op, ctx);
-        return null;
-    }
+	@Override
+	public Void visitIndexInsertDeleteOperator(IndexInsertDeleteOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		setEmptyFDsEqClasses(op, ctx);
+		return null;
+	}
 
-    private void propagateFDsAndEquivClasses(ILogicalOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        ILogicalOperator inp1 = op.getInputs().get(0).getValue();
-        Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
-        ctx.putEquivalenceClassMap(op, eqClasses);
-        List<FunctionalDependency> fds = getOrComputeFDs(inp1, ctx);
-        ctx.putFDList(op, fds);
-    }
+	@Override
+	public Void visitSinkOperator(SinkOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		setEmptyFDsEqClasses(op, ctx);
+		return null;
+	}
 
-    private Map<LogicalVariable, EquivalenceClass> getOrComputeEqClasses(ILogicalOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        Map<LogicalVariable, EquivalenceClass> eqClasses = ctx.getEquivalenceClassMap(op);
-        if (eqClasses == null) {
-            op.accept(this, ctx);
-            eqClasses = ctx.getEquivalenceClassMap(op);
-        }
-        return eqClasses;
-    }
+	private void propagateFDsAndEquivClasses(ILogicalOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		ILogicalOperator inp1 = op.getInputs().get(0).getValue();
+		Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
+		ctx.putEquivalenceClassMap(op, eqClasses);
+		List<FunctionalDependency> fds = getOrComputeFDs(inp1, ctx);
+		ctx.putFDList(op, fds);
+	}
 
-    private List<FunctionalDependency> getOrComputeFDs(ILogicalOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        List<FunctionalDependency> fds = ctx.getFDList(op);
-        if (fds == null) {
-            op.accept(this, ctx);
-            fds = ctx.getFDList(op);
-        }
-        return fds;
-    }
+	private Map<LogicalVariable, EquivalenceClass> getOrComputeEqClasses(ILogicalOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		Map<LogicalVariable, EquivalenceClass> eqClasses = ctx.getEquivalenceClassMap(op);
+		if (eqClasses == null) {
+			op.accept(this, ctx);
+			eqClasses = ctx.getEquivalenceClassMap(op);
+		}
+		return eqClasses;
+	}
 
-    private void propagateFDsAndEquivClassesForUsedVars(ILogicalOperator op, IOptimizationContext ctx,
-            List<LogicalVariable> usedVariables) throws AlgebricksException {
-        ILogicalOperator op2 = op.getInputs().get(0).getValue();
-        Map<LogicalVariable, EquivalenceClass> eqClasses = new HashMap<LogicalVariable, EquivalenceClass>();
-        ctx.putEquivalenceClassMap(op, eqClasses);
-        List<FunctionalDependency> fds = new ArrayList<FunctionalDependency>();
-        ctx.putFDList(op, fds);
+	private List<FunctionalDependency> getOrComputeFDs(ILogicalOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		List<FunctionalDependency> fds = ctx.getFDList(op);
+		if (fds == null) {
+			op.accept(this, ctx);
+			fds = ctx.getFDList(op);
+		}
+		return fds;
+	}
 
-        Map<LogicalVariable, EquivalenceClass> chldClasses = getOrComputeEqClasses(op2, ctx);
-        for (LogicalVariable v : usedVariables) {
-            EquivalenceClass ec = eqClasses.get(v);
-            if (ec == null) {
-                EquivalenceClass oc = chldClasses.get(v);
-                if (oc == null) {
-                    continue;
-                }
-                List<LogicalVariable> m = new LinkedList<LogicalVariable>();
-                for (LogicalVariable v2 : oc.getMembers()) {
-                    if (usedVariables.contains(v2)) {
-                        m.add(v2);
-                    }
-                }
-                EquivalenceClass nc;
-                if (oc.representativeIsConst()) {
-                    nc = new EquivalenceClass(m, oc.getConstRepresentative());
-                } else if (m.contains(oc.getVariableRepresentative())) {
-                    nc = new EquivalenceClass(m, oc.getVariableRepresentative());
-                } else {
-                    nc = new EquivalenceClass(m, v);
-                }
-                for (LogicalVariable v3 : m) {
-                    eqClasses.put(v3, nc);
-                }
-            }
-        }
+	private void propagateFDsAndEquivClassesForUsedVars(ILogicalOperator op, IOptimizationContext ctx,
+			List<LogicalVariable> usedVariables) throws AlgebricksException {
+		ILogicalOperator op2 = op.getInputs().get(0).getValue();
+		Map<LogicalVariable, EquivalenceClass> eqClasses = new HashMap<LogicalVariable, EquivalenceClass>();
+		ctx.putEquivalenceClassMap(op, eqClasses);
+		List<FunctionalDependency> fds = new ArrayList<FunctionalDependency>();
+		ctx.putFDList(op, fds);
 
-        List<FunctionalDependency> chldFds = getOrComputeFDs(op2, ctx);
-        for (FunctionalDependency fd : chldFds) {
-            if (!usedVariables.containsAll(fd.getHead())) {
-                continue;
-            }
-            List<LogicalVariable> tl = new LinkedList<LogicalVariable>();
-            for (LogicalVariable v : fd.getTail()) {
-                if (usedVariables.contains(v)) {
-                    tl.add(v);
-                }
-            }
-            if (!tl.isEmpty()) {
-                FunctionalDependency newFd = new FunctionalDependency(fd.getHead(), tl);
-                fds.add(newFd);
-            }
-        }
-    }
+		Map<LogicalVariable, EquivalenceClass> chldClasses = getOrComputeEqClasses(op2, ctx);
+		for (LogicalVariable v : usedVariables) {
+			EquivalenceClass ec = eqClasses.get(v);
+			if (ec == null) {
+				EquivalenceClass oc = chldClasses.get(v);
+				if (oc == null) {
+					continue;
+				}
+				List<LogicalVariable> m = new LinkedList<LogicalVariable>();
+				for (LogicalVariable v2 : oc.getMembers()) {
+					if (usedVariables.contains(v2)) {
+						m.add(v2);
+					}
+				}
+				EquivalenceClass nc;
+				if (oc.representativeIsConst()) {
+					nc = new EquivalenceClass(m, oc.getConstRepresentative());
+				} else if (m.contains(oc.getVariableRepresentative())) {
+					nc = new EquivalenceClass(m, oc.getVariableRepresentative());
+				} else {
+					nc = new EquivalenceClass(m, v);
+				}
+				for (LogicalVariable v3 : m) {
+					eqClasses.put(v3, nc);
+				}
+			}
+		}
 
-    private void fdsEqClassesForAbstractUnnestOperator(AbstractUnnestOperator op, IOptimizationContext ctx)
-            throws AlgebricksException {
-        ILogicalOperator inp1 = op.getInputs().get(0).getValue();
-        Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
-        ctx.putEquivalenceClassMap(op, eqClasses);
-        List<FunctionalDependency> fds = getOrComputeFDs(inp1, ctx);
-        ctx.putFDList(op, fds);
+		List<FunctionalDependency> chldFds = getOrComputeFDs(op2, ctx);
+		for (FunctionalDependency fd : chldFds) {
+			if (!usedVariables.containsAll(fd.getHead())) {
+				continue;
+			}
+			List<LogicalVariable> tl = new LinkedList<LogicalVariable>();
+			for (LogicalVariable v : fd.getTail()) {
+				if (usedVariables.contains(v)) {
+					tl.add(v);
+				}
+			}
+			if (!tl.isEmpty()) {
+				FunctionalDependency newFd = new FunctionalDependency(fd.getHead(), tl);
+				fds.add(newFd);
+			}
+		}
+	}
 
-        ILogicalExpression expr = op.getExpressionRef().getValue();
-        if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
-            AbstractFunctionCallExpression afe = (AbstractFunctionCallExpression) expr;
-            if (afe.getKind() == FunctionKind.UNNEST && ((UnnestingFunctionCallExpression) afe).returnsUniqueValues()) {
-                List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
-                VariableUtilities.getLiveVariables(op, vars);
-                ArrayList<LogicalVariable> h = new ArrayList<LogicalVariable>();
-                h.addAll(op.getVariables());
-                FunctionalDependency fd = new FunctionalDependency(h, vars);
-                fds.add(fd);
-            }
-        }
-    }
+	private void fdsEqClassesForAbstractUnnestOperator(AbstractUnnestOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		ILogicalOperator inp1 = op.getInputs().get(0).getValue();
+		Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
+		ctx.putEquivalenceClassMap(op, eqClasses);
+		List<FunctionalDependency> fds = getOrComputeFDs(inp1, ctx);
+		ctx.putFDList(op, fds);
 
-    public static void setEmptyFDsEqClasses(ILogicalOperator op, IOptimizationContext ctx) {
-        Map<LogicalVariable, EquivalenceClass> eqClasses = new HashMap<LogicalVariable, EquivalenceClass>();
-        ctx.putEquivalenceClassMap(op, eqClasses);
-        List<FunctionalDependency> fds = new ArrayList<FunctionalDependency>();
-        ctx.putFDList(op, fds);
-    }
+		ILogicalExpression expr = op.getExpressionRef().getValue();
+		if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+			AbstractFunctionCallExpression afe = (AbstractFunctionCallExpression) expr;
+			if (afe.getKind() == FunctionKind.UNNEST && ((UnnestingFunctionCallExpression) afe).returnsUniqueValues()) {
+				List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
+				VariableUtilities.getLiveVariables(op, vars);
+				ArrayList<LogicalVariable> h = new ArrayList<LogicalVariable>();
+				h.addAll(op.getVariables());
+				FunctionalDependency fd = new FunctionalDependency(h, vars);
+				fds.add(fd);
+			}
+		}
+	}
 
-    private LogicalVariable getNewGbyVar(GroupByOperator g, LogicalVariable v) {
-        for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : g.getGroupByList()) {
-            ILogicalExpression e = p.second.getValue();
-            if (e.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
-                LogicalVariable v2 = ((VariableReferenceExpression) e).getVariableReference();
-                if (v2 == v) {
-                    return p.first;
-                }
-            }
-        }
-        return null;
-    }
+	private void fdsEqClassesForExternalAccessOperator(ExternalDataAccessByRIDOperator op, IOptimizationContext ctx)
+			throws AlgebricksException {
+		ILogicalOperator inp1 = op.getInputs().get(0).getValue();
+		Map<LogicalVariable, EquivalenceClass> eqClasses = getOrComputeEqClasses(inp1, ctx);
+		ctx.putEquivalenceClassMap(op, eqClasses);
+		List<FunctionalDependency> fds = getOrComputeFDs(inp1, ctx);
+		ctx.putFDList(op, fds);
+		List<LogicalVariable> vars = new ArrayList<LogicalVariable>();
+		VariableUtilities.getLiveVariables(op, vars);
+		ArrayList<LogicalVariable> h = new ArrayList<LogicalVariable>();
+		h.addAll(op.getVariables());
+		FunctionalDependency fd = new FunctionalDependency(h, vars);
+		fds.add(fd);
+	}
 
-    private LogicalVariable getNewDecorVar(GroupByOperator g, LogicalVariable v) {
-        for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : g.getDecorList()) {
-            ILogicalExpression e = p.second.getValue();
-            if (e.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
-                LogicalVariable v2 = ((VariableReferenceExpression) e).getVariableReference();
-                if (v2 == v) {
-                    return (p.first != null) ? p.first : v2;
-                }
-            }
-        }
-        return null;
-    }
+	public static void setEmptyFDsEqClasses(ILogicalOperator op, IOptimizationContext ctx) {
+		Map<LogicalVariable, EquivalenceClass> eqClasses = new HashMap<LogicalVariable, EquivalenceClass>();
+		ctx.putEquivalenceClassMap(op, eqClasses);
+		List<FunctionalDependency> fds = new ArrayList<FunctionalDependency>();
+		ctx.putFDList(op, fds);
+	}
 
-    @Override
-    public Void visitExtensionOperator(ExtensionOperator op, IOptimizationContext ctx) throws AlgebricksException {
-        propagateFDsAndEquivClasses(op, ctx);
-        return null;
-    }
+	private LogicalVariable getNewGbyVar(GroupByOperator g, LogicalVariable v) {
+		for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : g.getGroupByList()) {
+			ILogicalExpression e = p.second.getValue();
+			if (e.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+				LogicalVariable v2 = ((VariableReferenceExpression) e).getVariableReference();
+				if (v2 == v) {
+					return p.first;
+				}
+			}
+		}
+		return null;
+	}
+
+	private LogicalVariable getNewDecorVar(GroupByOperator g, LogicalVariable v) {
+		for (Pair<LogicalVariable, Mutable<ILogicalExpression>> p : g.getDecorList()) {
+			ILogicalExpression e = p.second.getValue();
+			if (e.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+				LogicalVariable v2 = ((VariableReferenceExpression) e).getVariableReference();
+				if (v2 == v) {
+					return (p.first != null) ? p.first : v2;
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public Void visitExtensionOperator(ExtensionOperator op, IOptimizationContext ctx) throws AlgebricksException {
+		propagateFDsAndEquivClasses(op, ctx);
+		return null;
+	}
 
 }
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/IsomorphismOperatorVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/IsomorphismOperatorVisitor.java
index 97d257a..0561091 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/IsomorphismOperatorVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/IsomorphismOperatorVisitor.java
@@ -41,6 +41,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
@@ -342,6 +343,14 @@
         isomorphic = op.getExpressionRef().getValue().equals(unnestOpArg.getExpressionRef().getValue());
         return isomorphic;
     }
+    
+    //not sure if this is correct!
+    @Override
+	public Boolean visitExternalDataAccessByRIDOperator(
+			ExternalDataAccessByRIDOperator op, ILogicalOperator arg)
+			throws AlgebricksException {
+    	return Boolean.FALSE;
+	}
 
     @Override
     public Boolean visitDataScanOperator(DataSourceScanOperator op, ILogicalOperator arg) throws AlgebricksException {
@@ -730,6 +739,16 @@
             return new UnnestMapOperator(newInputList, deepCopyExpressionRef(op.getExpressionRef()),
                     new ArrayList<Object>(op.getVariableTypes()), op.propagatesInput());
         }
+        
+        @Override
+		public ILogicalOperator visitExternalDataAccessByRIDOperator(
+				ExternalDataAccessByRIDOperator op, Void arg)
+        {
+        ArrayList<LogicalVariable> newInputList = new ArrayList<LogicalVariable>();
+        newInputList.addAll(op.getVariables());
+        return new ExternalDataAccessByRIDOperator(newInputList, deepCopyExpressionRef(op.getExpressionRef()),
+                new ArrayList<Object>(op.getVariableTypes()));
+		}
 
         @Override
         public ILogicalOperator visitDataScanOperator(DataSourceScanOperator op, Void arg) throws AlgebricksException {
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/IsomorphismVariableMappingVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/IsomorphismVariableMappingVisitor.java
index eecace7..407f7dc8 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/IsomorphismVariableMappingVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/IsomorphismVariableMappingVisitor.java
@@ -40,6 +40,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
@@ -198,6 +199,13 @@
         mapVariablesStandard(op, arg);
         return null;
     }
+    
+    @Override
+	public Void visitExternalDataAccessByRIDOperator(
+			ExternalDataAccessByRIDOperator op, ILogicalOperator arg)
+			throws AlgebricksException {
+		return null;
+	}
 
     @Override
     public Void visitDataScanOperator(DataSourceScanOperator op, ILogicalOperator arg) throws AlgebricksException {
@@ -422,4 +430,5 @@
         return null;
     }
 
+
 }
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalPropertiesVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalPropertiesVisitor.java
index 277b5a3..c978bac 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalPropertiesVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/LogicalPropertiesVisitor.java
@@ -32,6 +32,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
@@ -325,4 +326,12 @@
         return null;
     }
 
+	@Override
+	public Void visitExternalDataAccessByRIDOperator(
+			ExternalDataAccessByRIDOperator op, IOptimizationContext arg)
+			throws AlgebricksException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
 }
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/ProducedVariableVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/ProducedVariableVisitor.java
index 8673a77..b76078e 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/ProducedVariableVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/ProducedVariableVisitor.java
@@ -35,6 +35,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;

+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;

@@ -199,6 +200,12 @@
     public Void visitUnnestMapOperator(UnnestMapOperator op, Void arg) throws AlgebricksException {

         producedVariables.addAll(op.getVariables());

         return null;

+    }
+    
+    @Override
+    public Void visitExternalDataAccessByRIDOperator(ExternalDataAccessByRIDOperator op, Void arg) throws AlgebricksException {
+        producedVariables.add(op.getVariables().get(0));
+        return null;
     }

 

     @Override

diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/SchemaVariableVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/SchemaVariableVisitor.java
index 5606e72..82ea1a7 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/SchemaVariableVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/SchemaVariableVisitor.java
@@ -36,6 +36,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;

+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;

@@ -226,7 +227,13 @@
         standardLayout(op);

         return null;

     }

-

+
+    @Override
+    public Void visitExternalDataAccessByRIDOperator(ExternalDataAccessByRIDOperator op, Void arg) throws AlgebricksException {
+    	VariableUtilities.getProducedVariables(op, schemaVariables);
+        return null;
+    }
+    

     @Override

     public Void visitUnnestOperator(UnnestOperator op, Void arg) throws AlgebricksException {

         standardLayout(op);

diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java
index 3d6b989..3964e56 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/SubstituteVariableVisitor.java
@@ -36,6 +36,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;

+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;

@@ -299,6 +300,21 @@
         op.getExpressionRef().getValue().substituteVar(pair.first, pair.second);

         substVarTypes(op, pair);

         return null;

+    }
+    
+    @Override
+    public Void visitExternalDataAccessByRIDOperator(ExternalDataAccessByRIDOperator op, Pair<LogicalVariable, LogicalVariable> pair)
+            throws AlgebricksException {
+        List<LogicalVariable> variables = op.getVariables();
+        for (int i = 0; i < variables.size(); i++) {
+            if (variables.get(i) == pair.first) {
+                variables.set(i, pair.second);
+                return null;
+            }
+        }
+        op.getExpressionRef().getValue().substituteVar(pair.first, pair.second);
+        substVarTypes(op, pair);
+        return null;
     }

 

     @Override

diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java
index d05adfb..9b4164a 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java
@@ -35,6 +35,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;

+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;

 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;

@@ -279,7 +280,13 @@
         op.getExpressionRef().getValue().getUsedVariables(usedVariables);

         return null;

     }

-

+
+    @Override
+    public Void visitExternalDataAccessByRIDOperator(ExternalDataAccessByRIDOperator op, Void arg) {
+        op.getExpressionRef().getValue().getUsedVariables(usedVariables);
+        return null;
+    }
+    

     @Override

     public Void visitUnnestOperator(UnnestOperator op, Void arg) {

         op.getExpressionRef().getValue().getUsedVariables(usedVariables);

diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java
index 49ec269..a20d20d 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/prettyprint/LogicalOperatorPrettyPrintVisitor.java
@@ -33,6 +33,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
@@ -234,6 +235,13 @@
         addIndent(buffer, indent).append("unnest-map " + op.getVariables() + " <- " + op.getExpressionRef().getValue());
         return buffer.toString();
     }
+    
+    @Override
+    public String visitExternalDataAccessByRIDOperator(ExternalDataAccessByRIDOperator op, Integer indent) throws AlgebricksException {
+    	StringBuilder buffer = new StringBuilder();
+        addIndent(buffer, indent).append("external-access-by-rid " + op.getVariables() + " <- " + op.getExpressionRef().getValue());
+        return buffer.toString();
+    }
 
     @Override
     public String visitDataScanOperator(DataSourceScanOperator op, Integer indent) {
diff --git a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/visitors/ILogicalOperatorVisitor.java b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/visitors/ILogicalOperatorVisitor.java
index 0467d63..ca7d21b 100644
--- a/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/visitors/ILogicalOperatorVisitor.java
+++ b/algebricks/algebricks-core/src/main/java/edu/uci/ics/hyracks/algebricks/core/algebra/visitors/ILogicalOperatorVisitor.java
@@ -23,6 +23,7 @@
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.EmptyTupleSourceOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExtensionOperator;
+import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.ExternalDataAccessByRIDOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.IndexInsertDeleteOperator;
 import edu.uci.ics.hyracks.algebricks.core.algebra.operators.logical.InnerJoinOperator;
@@ -88,6 +89,8 @@
     public R visitUnnestOperator(UnnestOperator op, T arg) throws AlgebricksException;
 
     public R visitUnnestMapOperator(UnnestMapOperator op, T arg) throws AlgebricksException;
+    
+    public R visitExternalDataAccessByRIDOperator(ExternalDataAccessByRIDOperator op, T arg) throws AlgebricksException;
 
     public R visitDataScanOperator(DataSourceScanOperator op, T arg) throws AlgebricksException;