[ASTERIXDB-3180][COMP][RT] Apply filter before assembling columnar datasets

- user model changes: no
- storage format changes: no
- interface changes: yes

Details:
This patch implements an idea by Mike Carey, which says
let's use the columns as a "poorman" index. The condition
expression of SELECT is pushed down to data-scan and
the following is performed for each mega-leaf node:

1- Read all the columns involved in the SELECT condition expression.
2- Look for a tuple that satisfies the condition
  - If none exists, skip reading the rest of the columns
  - If at least one exists, read the rest of the columns
3- For each subsequent call to next() in the LSM cursor,
   check whether the returned tuple satisfies the condition
  - If yes, assemble and return the tuple
  - If no, skip and go to the next tuple and repeat

Change-Id: Ia83b839633d83ac6e3ffb4340a1d144daa0b299d
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17510
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Wail Alkowaileet <wael.y.k@gmail.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java
index 6c6b2aa..249173a 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/BTreeSearchPOperator.java
@@ -149,7 +149,7 @@
                     ARecordType metaItemType = (ARecordType) metadataProvider.findMetaType(dataset);
                     datasetType = (ARecordType) metadataProvider.findTypeForDatasetWithoutType(datasetType,
                             metaItemType, dataset);
-                    tupleProjectorFactory = IndexUtil.createTupleProjectorFactory(formatInfo, projectionInfo,
+                    tupleProjectorFactory = IndexUtil.createTupleProjectorFactory(context, formatInfo, projectionInfo,
                             metaProjectionInfo, datasetType, metaItemType, dataset.getPrimaryKeys().size());
                 }
                 break;
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpectedSchemaBuilder.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpectedSchemaBuilder.java
index f972677..3f83d1a 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpectedSchemaBuilder.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpectedSchemaBuilder.java
@@ -70,19 +70,20 @@
     }
 
     public DataProjectionFiltrationInfo createProjectionInfo(LogicalVariable recordVariable) {
-        return createProjectionInfo(recordVariable, Collections.emptyMap(), null, null);
+        return createProjectionInfo(recordVariable, Collections.emptyMap(), Collections.emptyMap(), null, null);
     }
 
     public DataProjectionFiltrationInfo createProjectionInfo(LogicalVariable recordVariable,
-            Map<ILogicalExpression, ARecordType> filterPaths, ILogicalExpression filterExpression,
-            Map<String, FunctionCallInformation> sourceInformationMap) {
+            Map<ILogicalExpression, ARecordType> normalizedPaths, Map<ILogicalExpression, ARecordType> actualPaths,
+            ILogicalExpression filterExpression, Map<String, FunctionCallInformation> sourceInformationMap) {
         IExpectedSchemaNode rootNode = varToNode.get(recordVariable);
 
         ExpectedSchemaNodeToIATypeTranslatorVisitor typeBuilder =
                 new ExpectedSchemaNodeToIATypeTranslatorVisitor(sourceInformationMap);
         ARecordType recordType = (ARecordType) rootNode.accept(typeBuilder, null);
 
-        return new DataProjectionFiltrationInfo(recordType, sourceInformationMap, filterPaths, filterExpression);
+        return new DataProjectionFiltrationInfo(recordType, sourceInformationMap, normalizedPaths, actualPaths,
+                filterExpression);
     }
 
     public boolean setSchemaFromExpression(AbstractFunctionCallExpression expr, LogicalVariable producedVar,
@@ -116,13 +117,17 @@
             //It is a root node. Request the entire record
             varToNode.put(variable, RootExpectedSchemaNode.ALL_FIELDS_ROOT_NODE);
         } else {
-            //It is a nested node. Replace the node to a LEAF node
-            node.replaceIfNeeded(ExpectedSchemaNodeType.ANY, parent.getSourceLocation(), parent.getFunctionName());
+            // If it is a nested node, replace it to a LEAF node
+            AnyExpectedSchemaNode leafNode = (AnyExpectedSchemaNode) node.replaceIfNeeded(ExpectedSchemaNodeType.ANY,
+                    parent.getSourceLocation(), parent.getFunctionName());
+            // make the leaf node irreplaceable
+            leafNode.preventReplacing();
+            varToNode.put(variable, leafNode);
         }
     }
 
-    public boolean isVariableRegistered(LogicalVariable recordVar) {
-        return varToNode.containsKey(recordVar);
+    public boolean isVariableRegistered(LogicalVariable variable) {
+        return varToNode.containsKey(variable);
     }
 
     public boolean containsRegisteredDatasets() {
@@ -133,8 +138,11 @@
         return varToNode.get(variable);
     }
 
-    IExpectedSchemaNode getNode(AbstractFunctionCallExpression expr) {
-        return exprToNode.get(expr);
+    IExpectedSchemaNode getNode(ILogicalExpression expr) {
+        if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+            return getNode(VariableUtilities.getVariable(expr));
+        }
+        return exprToNode.get((AbstractFunctionCallExpression) expr);
     }
 
     private IExpectedSchemaNode buildNestedNode(ILogicalExpression expr, IVariableTypeEnvironment typeEnv)
@@ -185,8 +193,9 @@
             AbstractFunctionCallExpression myExpr) {
         //Get the associated node with the sourceVar (if any)
         IExpectedSchemaNode oldNode = varToNode.get(sourceVar);
-        if (oldNode == null) {
-            //Variable is not associated with a node. No pushdown is possible
+        if (oldNode == null || !oldNode.allowsReplacing()) {
+            // Variable is not associated with a node. No pushdown is possible
+            // Or its associated node cannot be replaced
             return null;
         }
         //What is the expected type of the variable
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpressionValueAccessPushdownVisitor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpressionValueAccessPushdownVisitor.java
index 8096b04..b71dcb4 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpressionValueAccessPushdownVisitor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpressionValueAccessPushdownVisitor.java
@@ -99,7 +99,7 @@
         }
 
         //Check nested arguments if contains any pushable value access
-        pushValueAccessExpressionArg(funcExpr.getArguments());
+        pushValueAccessExpressionArg(funcExpr.getArguments(), producedVar);
     }
 
     /**
@@ -147,13 +147,14 @@
                 && funcExpr.getArguments().get(0).getValue().getExpressionTag() == LogicalExpressionTag.VARIABLE;
     }
 
-    private void pushValueAccessExpressionArg(List<Mutable<ILogicalExpression>> exprList) throws AlgebricksException {
+    private void pushValueAccessExpressionArg(List<Mutable<ILogicalExpression>> exprList, LogicalVariable producedVar)
+            throws AlgebricksException {
         for (Mutable<ILogicalExpression> exprRef : exprList) {
             /*
              * We need to set the produced variable as null here as the produced variable will not correspond to the
              * nested expression.
              */
-            pushValueAccessExpression(exprRef, null, typeEnv);
+            pushValueAccessExpression(exprRef, producedVar, typeEnv);
         }
     }
 
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpressionValueFilterPushdown.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpressionValueFilterPushdown.java
index 8ca2372..bff8bff 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpressionValueFilterPushdown.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/ExpressionValueFilterPushdown.java
@@ -18,9 +18,10 @@
  */
 package org.apache.asterix.optimizer.rules.pushdown;
 
-import static org.apache.asterix.metadata.utils.ColumnFilterBuilder.COMPARE_FUNCTIONS;
-import static org.apache.asterix.metadata.utils.ColumnFilterBuilder.PUSHABLE_FUNCTIONS;
+import static org.apache.asterix.metadata.utils.filter.NormalizedColumnFilterBuilder.COMPARE_FUNCTIONS;
+import static org.apache.asterix.metadata.utils.filter.NormalizedColumnFilterBuilder.NORMALIZED_PUSHABLE_FUNCTIONS;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -31,8 +32,10 @@
 import org.apache.asterix.common.config.DatasetConfig;
 import org.apache.asterix.metadata.declared.DatasetDataSource;
 import org.apache.asterix.metadata.entities.Dataset;
+import org.apache.asterix.metadata.utils.filter.ColumnFilterBuilder;
 import org.apache.asterix.om.base.IAObject;
 import org.apache.asterix.om.constants.AsterixConstantValue;
+import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.optimizer.rules.pushdown.schema.AnyExpectedSchemaNode;
 import org.apache.asterix.optimizer.rules.pushdown.schema.ColumnFilterPathBuilderVisitor;
@@ -41,40 +44,49 @@
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
 import org.apache.asterix.runtime.projection.ProjectionFiltrationWarningFactoryProvider;
 import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
 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.ConstantExpression;
-import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractScanOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
 import org.apache.hyracks.api.exceptions.SourceLocation;
 
 /**
  * Pushdown {@link SelectOperator} condition to the dataset to allow filtering mega leaf nodes.
  * This is currently only allowed for {@link DatasetConfig.DatasetFormat#COLUMN}
- * TODO allow partial filter with AND (e.g., lowercase(stringVal) == "some_text" AND intVal > 10 --push--> intVal > 10 )
  * TODO Filter could prevent REPLICATE (i.e., we can scan a dataset twice due to the fact one scan is filtered and
- * TODO the other is not) or (both have different filters)
+ * TODO the other is not or both have different filters)
  * TODO part of this class could potentially be used for external data dynamic prefixes
  */
 class ExpressionValueFilterPushdown {
     private final ExpectedSchemaBuilder builder;
     private final ColumnFilterPathBuilderVisitor pathBuilder;
-    private final Map<AbstractScanOperator, Map<ILogicalExpression, ARecordType>> datasetFilterPaths;
+    private final Map<AbstractScanOperator, Map<ILogicalExpression, ARecordType>> normalizedFilterPaths;
+    private final Map<AbstractScanOperator, Map<ILogicalExpression, ARecordType>> actualFilterPaths;
     private final Map<AbstractScanOperator, ILogicalExpression> datasetFilterExpression;
     private final Map<AbstractScanOperator, Map<String, FunctionCallInformation>> scanSourceInformationMaps;
     private final Set<AbstractScanOperator> registeredScans;
+    private final HashMap<LogicalVariable, ILogicalExpression> registeredExpressions;
     private final boolean columnFilterEnabled;
 
     ExpressionValueFilterPushdown(ExpectedSchemaBuilder builder, boolean columnFilterEnabled) {
         this.builder = builder;
         pathBuilder = new ColumnFilterPathBuilderVisitor();
-        datasetFilterPaths = new HashMap<>();
+        normalizedFilterPaths = new HashMap<>();
+        actualFilterPaths = new HashMap<>();
         datasetFilterExpression = new HashMap<>();
         scanSourceInformationMaps = new HashMap<>();
         registeredScans = new HashSet<>();
+        registeredExpressions = new HashMap<>();
         this.columnFilterEnabled = columnFilterEnabled;
     }
 
@@ -90,28 +102,68 @@
         }
     }
 
+    public void registerExpression(LogicalVariable producedVar, ILogicalExpression expr) {
+        if (builder.getNode(expr) == null) {
+            // we only register expressions that do not correspond to a schema node
+            registeredExpressions.put(producedVar, expr);
+        }
+    }
+
     /**
      * Try to push the condition down to dataset scan/access
      *
      * @param selectOp the select operator
      */
-    public void addFilterExpression(SelectOperator selectOp, AbstractScanOperator scanOp) {
-        if (datasetFilterPaths.containsKey(scanOp)) {
-            // Most bottom SELECT was applied, other selects should be ignored
-            return;
-        }
-        Map<ILogicalExpression, ARecordType> filterPaths = new HashMap<>();
+    public void addFilterExpression(IOptimizationContext context, SelectOperator selectOp,
+            AbstractScanOperator scanOp) {
+        Map<ILogicalExpression, ARecordType> normalizedPaths = new HashMap<>();
+        Map<ILogicalExpression, ARecordType> actualPaths = new HashMap<>();
         Map<String, FunctionCallInformation> sourceInformationMap = new HashMap<>();
-        Mutable<ILogicalExpression> conditionRef = selectOp.getCondition();
-        if (addPaths(conditionRef, filterPaths, sourceInformationMap)) {
-            datasetFilterPaths.put(scanOp, filterPaths);
-            datasetFilterExpression.put(scanOp, conditionRef.getValue());
+        ILogicalExpression conditionClone = selectOp.getCondition().getValue().cloneExpression();
+        Mutable<ILogicalExpression> conditionRef = new MutableObject<>(conditionClone);
+        if (addPaths(conditionRef, normalizedPaths, actualPaths, sourceInformationMap, true)) {
+            // Normalized paths
+            Map<ILogicalExpression, ARecordType> allNormalizedPaths =
+                    normalizedFilterPaths.computeIfAbsent(scanOp, k -> new HashMap<>());
+            allNormalizedPaths.putAll(normalizedPaths);
+
+            // Actual paths
+            Map<ILogicalExpression, ARecordType> allActualPaths =
+                    actualFilterPaths.computeIfAbsent(scanOp, k -> new HashMap<>());
+            allActualPaths.putAll(actualPaths);
+
+            // OR the previous condition with the current condition (if any)
+            // This might bring more than what's actually satisfies the predicate
+            putExpression(context, scanOp, conditionClone);
             scanSourceInformationMaps.put(scanOp, sourceInformationMap);
         }
     }
 
-    public Map<ILogicalExpression, ARecordType> getFilterPaths(AbstractScanOperator scanOp) {
-        return datasetFilterPaths.getOrDefault(scanOp, Collections.emptyMap());
+    private void putExpression(IOptimizationContext context, AbstractScanOperator scanOp,
+            ILogicalExpression conditionExpr) {
+        ILogicalExpression filterExpr = datasetFilterExpression.get(scanOp);
+        if (filterExpr != null) {
+            AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) filterExpr;
+            if (!BuiltinFunctions.OR.equals(funcExpr.getFunctionIdentifier())) {
+                IFunctionInfo fInfo = context.getMetadataProvider().lookupFunction(AlgebricksBuiltinFunctions.OR);
+                List<Mutable<ILogicalExpression>> args = new ArrayList<>();
+                args.add(new MutableObject<>(filterExpr));
+                funcExpr = new ScalarFunctionCallExpression(fInfo, args);
+                filterExpr = funcExpr;
+            }
+            funcExpr.getArguments().add(new MutableObject<>(conditionExpr));
+        } else {
+            filterExpr = conditionExpr;
+        }
+        datasetFilterExpression.put(scanOp, filterExpr);
+    }
+
+    public Map<ILogicalExpression, ARecordType> getNormalizedFilterPaths(AbstractScanOperator scanOp) {
+        return normalizedFilterPaths.getOrDefault(scanOp, Collections.emptyMap());
+    }
+
+    public Map<ILogicalExpression, ARecordType> getActualFilterPaths(AbstractScanOperator scanOp) {
+        return actualFilterPaths.getOrDefault(scanOp, Collections.emptyMap());
     }
 
     public ILogicalExpression getFilterExpression(AbstractScanOperator scanOp) {
@@ -122,62 +174,89 @@
         return scanSourceInformationMaps.getOrDefault(scanOp, new HashMap<>());
     }
 
-    private boolean addPaths(Mutable<ILogicalExpression> exprRef, Map<ILogicalExpression, ARecordType> filterPaths,
-            Map<String, FunctionCallInformation> sourceInformationMap) {
+    private boolean addPaths(Mutable<ILogicalExpression> exprRef, Map<ILogicalExpression, ARecordType> normalizedPaths,
+            Map<ILogicalExpression, ARecordType> actualPaths, Map<String, FunctionCallInformation> sourceInformationMap,
+            boolean includeNormalized) {
         ILogicalExpression expr = exprRef.getValue();
+        if (expr.getExpressionTag() == LogicalExpressionTag.CONSTANT) {
+            IAObject constantValue = ((AsterixConstantValue) ((ConstantExpression) expr).getValue()).getObject();
+            // Continue if a primitive constant is encountered
+            return !constantValue.getType().getTypeTag().isDerivedType();
+        }
+
+        LogicalVariable variable = VariableUtilities.getVariable(expr);
+        if (variable != null && registeredExpressions.containsKey(variable)) {
+            // Inline the expression
+            ILogicalExpression currentExpr = registeredExpressions.get(variable);
+            exprRef.setValue(currentExpr);
+            return addPaths(exprRef, normalizedPaths, actualPaths, sourceInformationMap, false);
+        }
+
+        IExpectedSchemaNode node = builder.getNode(expr);
+        if (node != null) {
+            return addPath(node, expr, actualPaths);
+        }
+
         if (!isFunctionExpression(expr)) {
             return false;
         }
 
         AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;
         FunctionIdentifier fid = ((AbstractFunctionCallExpression) expr).getFunctionIdentifier();
-
-        if (!PUSHABLE_FUNCTIONS.contains(fid)) {
+        if (!ColumnFilterBuilder.isPushable(fid)) {
             return false;
         }
 
+        boolean normalizedIncluded = includeNormalized && NORMALIZED_PUSHABLE_FUNCTIONS.contains(fid);
+
         if (COMPARE_FUNCTIONS.contains(fid)) {
-            return addPaths(funcExpr, filterPaths, sourceInformationMap);
+            return handleCompare(funcExpr, normalizedPaths, actualPaths, sourceInformationMap, normalizedIncluded);
         }
         //AND/OR descend to the expression tree
-        return addPathsForArgs(funcExpr, filterPaths, sourceInformationMap);
+        return handleArgs(funcExpr, normalizedPaths, actualPaths, sourceInformationMap, includeNormalized);
     }
 
-    private boolean addPaths(AbstractFunctionCallExpression funcExpr, Map<ILogicalExpression, ARecordType> filterPaths,
-            Map<String, FunctionCallInformation> sourceInformationMap) {
+    private boolean handleCompare(AbstractFunctionCallExpression funcExpr,
+            Map<ILogicalExpression, ARecordType> normalizedPaths, Map<ILogicalExpression, ARecordType> actualPaths,
+            Map<String, FunctionCallInformation> sourceInformationMap, boolean includeNormalized) {
         List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
 
-        ILogicalExpression left = args.get(0).getValue();
-        ILogicalExpression right = args.get(1).getValue();
+        Mutable<ILogicalExpression> leftRef = args.get(0);
+        Mutable<ILogicalExpression> rightRef = args.get(1);
+
+        ILogicalExpression left = leftRef.getValue();
+        ILogicalExpression right = rightRef.getValue();
 
         if (isConstantExpression(left)) {
-            return addPaths(funcExpr, right, left, filterPaths, sourceInformationMap, true);
+            return handleCompare(funcExpr, rightRef, left, normalizedPaths, actualPaths, sourceInformationMap,
+                    includeNormalized, true);
         } else if (isConstantExpression(right)) {
-            return addPaths(funcExpr, left, right, filterPaths, sourceInformationMap, false);
+            return handleCompare(funcExpr, leftRef, right, normalizedPaths, actualPaths, sourceInformationMap,
+                    includeNormalized, false);
         }
         // No constants, return false
         return false;
     }
 
-    private boolean addPaths(AbstractFunctionCallExpression funcExpr, ILogicalExpression columnExpr,
-            ILogicalExpression constExpr, Map<ILogicalExpression, ARecordType> filterPaths,
-            Map<String, FunctionCallInformation> sourceInformationMap, boolean leftConstant) {
-        IExpectedSchemaNode node;
-        if (isFunctionExpression(columnExpr)) {
-            node = builder.getNode((AbstractFunctionCallExpression) columnExpr);
-        } else {
-            //Variable
-            node = builder.getNode(((VariableReferenceExpression) columnExpr).getVariableReference());
-        }
+    private boolean handleCompare(AbstractFunctionCallExpression funcExpr, Mutable<ILogicalExpression> columnExprRef,
+            ILogicalExpression constExpr, Map<ILogicalExpression, ARecordType> normalizedPaths,
+            Map<ILogicalExpression, ARecordType> actualPaths, Map<String, FunctionCallInformation> sourceInformationMap,
+            boolean includeNormalized, boolean leftConstant) {
 
-        if (node == null || node.getType() != ExpectedSchemaNodeType.ANY) {
-            // Expression cannot be pushed (e.g., $$r.getField("x") + 1) or had been accessed as a nested value
-            // Bail out
+        IAObject constantValue = ((AsterixConstantValue) ((ConstantExpression) constExpr).getValue()).getObject();
+        if (constantValue.getType().getTypeTag().isDerivedType()) {
+            // Cannot compare against nested values
             return false;
         }
 
+        ILogicalExpression columnExpr = columnExprRef.getValue();
+        IExpectedSchemaNode node = builder.getNode(columnExpr);
+        if (node == null || node.getType() != ExpectedSchemaNodeType.ANY) {
+            // Handle as a nested function call (e.g., numeric-add($$x, 1) > 10) where $$x is a value path
+            return addPaths(columnExprRef, normalizedPaths, actualPaths, null, false);
+        }
+
         AnyExpectedSchemaNode leafNode = (AnyExpectedSchemaNode) node;
-        IAObject constantValue = ((AsterixConstantValue) ((ConstantExpression) constExpr).getValue()).getObject();
 
         String functionName = funcExpr.getFunctionIdentifier().getName();
         SourceLocation sourceLocation = funcExpr.getSourceLocation();
@@ -185,17 +264,34 @@
                 ProjectionFiltrationWarningFactoryProvider.getIncomparableTypesFactory(leftConstant));
 
         ARecordType path = pathBuilder.buildPath(leafNode, constantValue, sourceInformationMap, functionCallInfo);
-        filterPaths.put(columnExpr, path);
+        if (includeNormalized
+                && (!normalizedPaths.containsKey(columnExpr) || path.equals(normalizedPaths.get(columnExpr)))) {
+            normalizedPaths.put(columnExpr, path);
+        } else {
+            normalizedPaths.clear();
+        }
+        actualPaths.put(columnExpr, path);
         return true;
     }
 
-    private boolean addPathsForArgs(AbstractFunctionCallExpression funcExpr,
-            Map<ILogicalExpression, ARecordType> filterPaths,
-            Map<String, FunctionCallInformation> sourceInformationMap) {
+    private boolean addPath(IExpectedSchemaNode node, ILogicalExpression columnExpr,
+            Map<ILogicalExpression, ARecordType> actualPaths) {
+        if (node.getType() != ExpectedSchemaNodeType.ANY) {
+            return false;
+        }
+        AnyExpectedSchemaNode leafNode = (AnyExpectedSchemaNode) node;
+        ARecordType path = pathBuilder.buildPath(leafNode, null, null, null);
+        actualPaths.put(columnExpr, path);
+        return true;
+    }
+
+    private boolean handleArgs(AbstractFunctionCallExpression funcExpr,
+            Map<ILogicalExpression, ARecordType> normalizedPaths, Map<ILogicalExpression, ARecordType> actualPaths,
+            Map<String, FunctionCallInformation> sourceInformationMap, boolean includeNormalized) {
         List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
         boolean add = true;
         for (int i = 0; add && i < args.size(); i++) {
-            add = addPaths(args.get(i), filterPaths, sourceInformationMap);
+            add = addPaths(args.get(i), normalizedPaths, actualPaths, sourceInformationMap, includeNormalized);
         }
         return add;
     }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/OperatorValueAccessPushdownVisitor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/OperatorValueAccessPushdownVisitor.java
index 3ab07fd..ae7b919 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/OperatorValueAccessPushdownVisitor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/OperatorValueAccessPushdownVisitor.java
@@ -126,17 +126,18 @@
     public void finish() {
         for (Map.Entry<LogicalVariable, AbstractScanOperator> entry : registeredDatasets.entrySet()) {
             AbstractScanOperator scanOp = entry.getValue();
-            Map<ILogicalExpression, ARecordType> filterPaths = filterPushdown.getFilterPaths(scanOp);
+            Map<ILogicalExpression, ARecordType> normalizedPaths = filterPushdown.getNormalizedFilterPaths(scanOp);
+            Map<ILogicalExpression, ARecordType> actualPaths = filterPushdown.getActualFilterPaths(scanOp);
             ILogicalExpression filterExpression = filterPushdown.getFilterExpression(scanOp);
             Map<String, FunctionCallInformation> sourceInformationMap = filterPushdown.getSourceInformationMap(scanOp);
             if (scanOp.getOperatorTag() == LogicalOperatorTag.DATASOURCESCAN) {
                 DataSourceScanOperator scan = (DataSourceScanOperator) scanOp;
-                scan.setDatasetProjectionInfo(builder.createProjectionInfo(entry.getKey(), filterPaths,
+                scan.setDatasetProjectionInfo(builder.createProjectionInfo(entry.getKey(), normalizedPaths, actualPaths,
                         filterExpression, sourceInformationMap));
             } else {
                 UnnestMapOperator unnest = (UnnestMapOperator) scanOp;
-                unnest.setDatasetProjectionInfo(builder.createProjectionInfo(entry.getKey(), filterPaths,
-                        filterExpression, sourceInformationMap));
+                unnest.setDatasetProjectionInfo(builder.createProjectionInfo(entry.getKey(), normalizedPaths,
+                        actualPaths, filterExpression, sourceInformationMap));
             }
         }
 
@@ -175,7 +176,7 @@
 
         if (filterPushdown.allowsPushdown(lastSeenScan) && op.getOperatorTag() == LogicalOperatorTag.SELECT) {
             //Push filters down
-            filterPushdown.addFilterExpression((SelectOperator) op, lastSeenScan);
+            filterPushdown.addFilterExpression(context, (SelectOperator) op, lastSeenScan);
         }
 
         pushdownVisitor.end();
@@ -233,6 +234,20 @@
         return null;
     }
 
+    @Override
+    public Void visitAssignOperator(AssignOperator op, Void arg) throws AlgebricksException {
+        visitInputs(op, op.getVariables());
+        if (filterPushdown.allowsPushdown(lastSeenScan)) {
+            List<LogicalVariable> variables = op.getVariables();
+            List<Mutable<ILogicalExpression>> exprs = op.getExpressions();
+            for (int i = 0; i < variables.size(); i++) {
+                // Register any potential expression that can be used by the pushed down to filter
+                filterPushdown.registerExpression(variables.get(i), exprs.get(i).getValue());
+            }
+        }
+        return null;
+    }
+
     /*
      * ******************************************************************************
      * Helper methods
@@ -295,7 +310,10 @@
                  * Initially, we will request the entire record.
                  */
                 builder.registerRoot(recordVar, RootExpectedSchemaNode.ALL_FIELDS_ROOT_NODE);
-                filterPushdown.registerDataset(op, datasetDataSource);
+                if (op.getOperatorTag() == LogicalOperatorTag.DATASOURCESCAN) {
+                    // Not needed for secondary indexes
+                    filterPushdown.registerDataset(op, datasetDataSource);
+                }
                 registeredDatasets.put(recordVar, op);
 
                 if (datasetDataSource.hasMeta()) {
@@ -410,12 +428,6 @@
      */
 
     @Override
-    public Void visitAssignOperator(AssignOperator op, Void arg) throws AlgebricksException {
-        visitInputs(op, op.getVariables());
-        return null;
-    }
-
-    @Override
     public Void visitSelectOperator(SelectOperator op, Void arg) throws AlgebricksException {
         visitInputs(op);
         return null;
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractComplexExpectedSchemaNode.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractComplexExpectedSchemaNode.java
index 5da5149..7184e1f 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractComplexExpectedSchemaNode.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AbstractComplexExpectedSchemaNode.java
@@ -28,6 +28,11 @@
     }
 
     @Override
+    public boolean allowsReplacing() {
+        return true;
+    }
+
+    @Override
     public IExpectedSchemaNode replaceIfNeeded(ExpectedSchemaNodeType expectedNodeType, SourceLocation sourceLocation,
             String functionName) {
         //If no change is required, return the same node
@@ -42,7 +47,7 @@
              * In this case, we first saw (t.hashtags[*].text), but the next expression (t.hashtags) requested
              * the entire hashtags. So, the expected type for hashtags should be ANY
              */
-            node = new AnyExpectedSchemaNode(getParent(), getSourceLocation(), getFunctionName());
+            node = new AnyExpectedSchemaNode(getParent(), getSourceLocation(), getFunctionName(), false);
             getParent().replaceChild(this, node);
         } else if (expectedNodeType != getType()) {
             /*
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AnyExpectedSchemaNode.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AnyExpectedSchemaNode.java
index 834a405..891d744 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AnyExpectedSchemaNode.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/AnyExpectedSchemaNode.java
@@ -21,10 +21,27 @@
 import org.apache.hyracks.api.exceptions.SourceLocation;
 
 public class AnyExpectedSchemaNode extends AbstractExpectedSchemaNode {
+    private boolean replaceable;
 
     public AnyExpectedSchemaNode(AbstractComplexExpectedSchemaNode parent, SourceLocation sourceLocation,
             String functionName) {
         super(parent, sourceLocation, functionName);
+        replaceable = true;
+    }
+
+    protected AnyExpectedSchemaNode(AbstractComplexExpectedSchemaNode parent, SourceLocation sourceLocation,
+            String functionName, boolean replaceable) {
+        super(parent, sourceLocation, functionName);
+        this.replaceable = replaceable;
+    }
+
+    @Override
+    public boolean allowsReplacing() {
+        return replaceable;
+    }
+
+    public void preventReplacing() {
+        replaceable = false;
     }
 
     @Override
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/ColumnFilterPathBuilderVisitor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/ColumnFilterPathBuilderVisitor.java
index 3f83834..492aea7 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/ColumnFilterPathBuilderVisitor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/schema/ColumnFilterPathBuilderVisitor.java
@@ -24,6 +24,7 @@
 import org.apache.asterix.om.types.AOrderedListType;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.BuiltinType;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.types.IATypeVisitor;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
@@ -39,10 +40,13 @@
 
     public ARecordType buildPath(AnyExpectedSchemaNode anyNode, IAObject constant,
             Map<String, FunctionCallInformation> sourceInformationMap, FunctionCallInformation compareFunctionInfo) {
-        this.type = rename(constant.getType());
-        this.sourceInformationMap = sourceInformationMap;
 
-        sourceInformationMap.put(type.getTypeName(), compareFunctionInfo);
+        this.sourceInformationMap = sourceInformationMap;
+        this.type = BuiltinType.ANY;
+        if (sourceInformationMap != null) {
+            this.type = rename(constant.getType());
+            sourceInformationMap.put(type.getTypeName(), compareFunctionInfo);
+        }
         return (ARecordType) anyNode.accept(this, anyNode);
     }
 
@@ -55,20 +59,20 @@
     @Override
     public IAType visit(ObjectExpectedSchemaNode node, IExpectedSchemaNode arg) {
         type = getRecordType(node, type, arg, getTypeName());
-        sourceInformationMap.put(type.getTypeName(), createFunctionCallInformation(arg));
+        putCallInfo(type, arg);
         return node.getParent().accept(this, node);
     }
 
     @Override
     public IAType visit(ArrayExpectedSchemaNode node, IExpectedSchemaNode arg) {
         type = new AOrderedListType(type, getTypeName());
-        sourceInformationMap.put(type.getTypeName(), createFunctionCallInformation(arg));
+        putCallInfo(type, arg);
         return node.getParent().accept(this, node);
     }
 
     @Override
     public IAType visit(UnionExpectedSchemaNode node, IExpectedSchemaNode arg) {
-        sourceInformationMap.put(type.getTypeName(), createFunctionCallInformation(arg));
+        putCallInfo(type, arg);
         return node.getParent().accept(this, arg);
     }
 
@@ -77,6 +81,12 @@
         return node.getParent().accept(this, node);
     }
 
+    private void putCallInfo(IAType type, IExpectedSchemaNode node) {
+        if (sourceInformationMap != null) {
+            sourceInformationMap.put(type.getTypeName(), createFunctionCallInformation(node));
+        }
+    }
+
     private static ARecordType getRecordType(ObjectExpectedSchemaNode objectNode, IAType childType,
             IExpectedSchemaNode childNode, String typeName) {
         String key = objectNode.getChildFieldName(childNode);
@@ -120,6 +130,14 @@
         }
 
         @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof RenamedType) {
+                return originalType.equals(((RenamedType) obj).originalType);
+            }
+            return originalType.equals(obj);
+        }
+
+        @Override
         public int hash() {
             return originalType.hash();
         }
@@ -148,5 +166,10 @@
         public ObjectNode toJSON() {
             return originalType.toJSON();
         }
+
+        @Override
+        public String toString() {
+            return originalType.toString();
+        }
     }
 }
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 454e32e..ed0001a 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
@@ -57,6 +57,11 @@
     <R, T> R accept(IExpectedSchemaNodeVisitor<R, T> visitor, T arg);
 
     /**
+     * @return checks whether a node can be replaced
+     */
+    boolean allowsReplacing();
+
+    /**
      * Replace a node from one type to another
      * Example:
      * - {@link ExpectedSchemaNodeType#ANY} to {@link ExpectedSchemaNodeType#OBJECT}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.024.query.sqlpp
similarity index 79%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.024.query.sqlpp
index bc1f51c..3c99fea 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.024.query.sqlpp
@@ -16,8 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE test;
+SET `compiler.column.filter` "true";
+
+
+
+SELECT d.a, item
+FROM ColumnDataset d, d.array item
+-- First component has the answer
+WHERE item > 10
+  AND d.a = "1"
+ORDER BY d.id, d.a, item;
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.025.query.sqlpp
similarity index 74%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.025.query.sqlpp
index 69abb37..2df6c8a 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.025.query.sqlpp
@@ -16,12 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import org.apache.asterix.om.types.ATypeTag;
-
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+USE test;
+SET `compiler.column.filter` "true";
+SET `compiler.parallelism` "0";
+SET `compiler.sort.parallel` "false";
+EXPLAIN
+SELECT d.a, item
+FROM ColumnDataset d, d.array item
+-- First component has the answer
+WHERE item > 10
+  AND d.a = "1"
+ORDER BY d.id, d.a, item;
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.026.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.026.query.sqlpp
index 69abb37..c284cf7 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/001/001.026.query.sqlpp
@@ -16,12 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+-- param max-warnings:json=1000
+USE test;
+SET `compiler.column.filter` "true";
 
-import org.apache.asterix.om.types.ATypeTag;
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
 
-    ATypeTag getTypeTag();
-}
+SELECT VALUE d
+FROM ColumnDataset d
+-- Should throw a warning (comparing array with bigint)
+WHERE d.array > 10
+ORDER BY d.id;
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/003/003.005.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/003/003.005.query.sqlpp
index 69abb37..12cf536 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/003/003.005.query.sqlpp
@@ -16,12 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import org.apache.asterix.om.types.ATypeTag;
+USE test;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+SELECT VALUE item
+FROM ColumnDataset d, d.array item
+-- Should skip reading columns, as the predicate would yield missing
+WHERE item.notAField > 4
+ORDER BY d.id;
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.001.ddl.sqlpp
similarity index 76%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.001.ddl.sqlpp
index 69abb37..ce257e2 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.001.ddl.sqlpp
@@ -16,12 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import org.apache.asterix.om.types.ATypeTag;
+DROP DATAVERSE TestYelp IF EXISTS;
+CREATE DATAVERSE TestYelp;
+USE TestYelp;
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
+CREATE TYPE CheckinType AS {
+    checkin_id: int
+};
 
-    ATypeTag getTypeTag();
-}
+CREATE DATASET YelpCheckin(CheckinType) PRIMARY KEY checkin_id WITH {
+    "storage-format" : {"format" : "column"}
+};
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.002.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.002.update.sqlpp
new file mode 100644
index 0000000..8ee1570
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.002.update.sqlpp
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+USE TestYelp;
+
+INSERT INTO YelpCheckin (
+    [
+        {
+            "checkin_id": 1,
+            "business_id": "--1UhMGODdWsrMastO9DZw",
+            "dates": [
+                "2016-04-26 19:49:16",
+                "2016-08-30 18:36:57",
+                "2016-10-15 02:45:18",
+                "2016-11-18 01:54:50",
+                "2017-04-20 18:39:06",
+                "2017-05-03 17:58:02",
+                "2019-03-19 22:04:48"
+            ]
+        },
+        {
+            "checkin_id": 2,
+            "business_id": "--EF5N7P70J_UYBTPypYlA",
+            "dates": [
+                "2018-05-25 19:52:07",
+                "2018-09-18 16:09:44",
+                "2019-10-18 21:29:09"
+            ]
+        },
+        {
+            "checkin_id": 3,
+            "business_id": "--Ni3oJ4VOqfOEu7Sj2Vzg",
+            "dates": [
+                "2019-06-07 17:54:58"
+            ]
+        },
+        {
+            "checkin_id": 4,
+            "business_id": "--Y1Adl1YUWfYIRSd8vkmA",
+            "dates": [
+                "2011-05-03 20:54:05",
+                "2011-08-23 20:49:45",
+                "2014-12-04 06:13:01",
+                "2016-11-16 19:25:55"
+            ]
+        },
+        {
+            "checkin_id": 5,
+            "business_id": "--YPwqIlRJrhHkJcjY3eiA",
+            "dates": [
+                "2016-06-18 21:35:45",
+                "2016-10-15 18:17:51"
+            ]
+        },
+        {
+            "checkin_id": 6,
+            "business_id": "--e8PjCNhEz32pprnPhCwQ",
+            "dates": [
+                "2015-04-02 21:45:17"
+            ]
+        },
+        {
+            "checkin_id": 7,
+            "business_id": "--kinfHwmtdjz03g8B8z8Q",
+            "dates": [
+                "2014-08-27 17:49:18",
+                "2015-12-19 21:30:31",
+                "2018-11-27 15:53:50"
+            ]
+        },
+        {
+            "checkin_id": 8,
+            "business_id": "--q6datkI-f0EoVheXNEeQ",
+            "dates": [
+                "2014-01-28 20:56:04",
+                "2014-11-16 16:11:58",
+                "2015-11-15 19:21:53",
+                "2015-11-15 19:33:39"
+            ]
+        },
+        {
+            "checkin_id": 9,
+            "business_id": "--qvQS4MigHPykD2GV0-zw",
+            "dates": [
+                "2019-04-11 18:30:12"
+            ]
+        },
+        {
+            "checkin_id": 10,
+            "business_id": "--wIGbLEhlpl_UeAIyDmZQ",
+            "dates": [
+                "2015-06-06 20:01:06",
+                "2019-03-14 22:01:52"
+            ]
+        },
+        {
+            "checkin_id": 11,
+            "business_id": "-0FA-Qdi3SPYIoJz9UQw-A",
+            "dates": [
+                "2018-09-29 18:55:17",
+                "2018-10-20 16:48:05",
+                "2018-10-20 22:20:24"
+            ]
+        },
+        {
+            "checkin_id": 12,
+            "business_id": "-0Hj1hb_XW6ybWq2M7QhGA",
+            "dates": [
+                "2011-04-23 21:11:22",
+                "2014-05-04 19:42:48",
+                "2014-05-11 19:16:08",
+                "2014-06-04 19:14:18",
+                "2015-12-05 19:22:42",
+                "2017-05-15 23:19:00"
+            ]
+        },
+        {
+            "checkin_id": 13,
+            "business_id": "-0KMvRFwDWdVBeTpT11iHw",
+            "dates": [
+                "2012-07-13 21:43:57",
+                "2016-12-24 02:27:31",
+                "2017-08-31 00:35:26"
+            ]
+        },
+        {
+            "checkin_id": 14,
+            "business_id": "-0LPtgJC31FWMrMv317p0Q",
+            "dates": [
+                "2013-04-13 12:35:33",
+                "2013-08-19 23:35:49",
+                "2013-10-04 19:14:56"
+            ]
+        },
+        {
+            "checkin_id": 15,
+            "business_id": "-0M3o2uWBnQZwd3hmfEwuw",
+            "dates": [
+                "2016-09-10 19:26:19",
+                "2018-09-08 14:15:37",
+                "2019-09-13 22:47:25"
+            ]
+        },
+        {
+            "checkin_id": 16,
+            "business_id": "-0RRiWDtfnS16AKCtfvBZg",
+            "dates": [
+                "2017-05-19 14:30:16",
+                "2017-05-19 14:30:25",
+                "2017-08-28 15:49:37",
+                "2017-09-20 20:19:51",
+                "2017-10-01 16:31:05",
+                "2017-10-01 16:56:27",
+                "2017-12-27 23:33:20"
+            ]
+        },
+        {
+            "checkin_id": 17,
+            "business_id": "-0Soj75v-XoRcf2ERr8Bmg",
+            "dates": [
+                "2019-06-05 18:22:49"
+            ]
+        },
+        {
+            "checkin_id": 18,
+            "business_id": "-0ZumLlFjMh4ZW1z2nXGug",
+            "dates": [
+                "2011-09-24 21:37:32",
+                "2014-03-10 20:20:07",
+                "2015-05-27 00:40:24",
+                "2015-08-29 17:58:15",
+                "2018-03-16 15:03:26"
+            ]
+        },
+        {
+            "checkin_id": 19,
+            "business_id": "-0aOudcaAyac0VJbMX-L1g",
+            "dates": [
+                "2015-03-16 23:51:16",
+                "2015-12-21 04:48:01",
+                "2016-10-28 20:22:42",
+                "2016-10-28 20:23:00"
+            ]
+        },
+        {
+            "checkin_id": 20,
+            "business_id": "-0b86isaXMY0v4g-V8GZ9Q",
+            "dates": [
+                "2013-10-22 16:49:21",
+                "2014-11-21 17:39:24"
+            ]
+        },
+        {
+            "checkin_id": 21,
+            "business_id": "-0d-BfFSU0bwLcnMaGRxYw",
+            "dates": [
+                "2014-08-07 18:30:48",
+                "2014-09-16 20:41:45",
+                "2014-10-12 23:22:27",
+                "2015-07-21 20:43:56",
+                "2015-07-21 20:45:07"
+            ]
+        },
+        {
+            "checkin_id": 22,
+            "business_id": "-0jz6c3C6i7RG7Ag22K-Pg",
+            "dates": [
+                "2015-05-02 19:49:05",
+                "2015-05-06 03:52:18",
+                "2015-09-26 01:13:19"
+            ]
+        },
+        {
+            "checkin_id": 23,
+            "business_id": "-0y3MZU2oYP8r1ruDP1bfQ",
+            "dates": [
+                "2015-04-11 13:14:14",
+                "2015-11-21 16:05:56",
+                "2016-05-06 14:10:04",
+                "2017-08-09 15:15:10",
+                "2017-10-21 15:12:56"
+            ]
+        },
+        {
+            "checkin_id": 24,
+            "business_id": "-1BPe8UjF2_l3nVk-DFUjA",
+            "dates": [
+                "2015-12-03 18:44:00",
+                "2016-03-17 18:19:21",
+                "2016-11-02 15:58:38"
+            ]
+        },
+        {
+            "checkin_id": 25,
+            "business_id": "-1E2CQu_38mkghvmZgCCRw",
+            "dates": []
+        },
+        {
+            "checkin_id": 26,
+            "business_id": "-1wzk43IZ5D9Ysu6kzb5xA",
+            "dates": []
+        },
+        {
+            "checkin_id": 27,
+            "business_id": "-23R9P2eG7VTc6DVLjFKzA",
+            "dates": [
+                "2011-12-21 19:02:51",
+                "2012-04-15 04:21:39",
+                "2012-04-15 14:23:56",
+                "2013-06-30 22:39:51",
+                "2013-10-04 20:34:13",
+                "2014-07-16 02:28:40"
+            ]
+        },
+        {
+            "checkin_id": 28,
+            "business_id": "-26MGfikhJiTfCI-GqmzhQ",
+            "dates": [
+                "2018-06-13 20:16:07"
+            ]
+        },
+        {
+            "checkin_id": 29,
+            "business_id": "-2bLuJsMZ0WhI9daurVQNQ",
+            "dates": [
+                "2015-05-29 16:46:17",
+                "2015-06-01 15:03:53"
+            ]
+        },
+        {
+            "checkin_id": 30,
+            "business_id": "-2hDBMaza_ldqnZdiU06LQ",
+            "dates": [
+                "2011-10-08 12:02:23",
+                "2014-08-18 02:11:11",
+                "2016-01-07 05:27:51",
+                "2016-10-21 20:15:55",
+                "2016-12-01 03:57:10",
+                "2016-12-29 01:54:42",
+                "2018-07-22 19:55:31",
+                "2018-09-07 01:42:54",
+                "2019-03-08 03:41:06"
+            ]
+        }
+    ]
+);
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.003.get.http
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.003.get.http
index bc1f51c..a55ce93 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.003.get.http
@@ -16,8 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+/connector?dataverseName=TestYelp&datasetName=YelpCheckin
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.004.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.004.query.sqlpp
index bc1f51c..14482f6 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.004.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > " ";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.005.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.005.query.sqlpp
index bc1f51c..070ed6c 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.005.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > " ";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.006.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.006.query.sqlpp
index bc1f51c..6caaf79 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.006.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > " ";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.007.update.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.007.update.sqlpp
index bc1f51c..ea1dba3 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.007.update.sqlpp
@@ -16,8 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+
+DELETE FROM YelpCheckin C
+WHERE C.business_id != "--1UhMGODdWsrMastO9DZw";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.008.get.http
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.008.get.http
index bc1f51c..a55ce93 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.008.get.http
@@ -16,8 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+/connector?dataverseName=TestYelp&datasetName=YelpCheckin
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.009.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.009.query.sqlpp
index bc1f51c..14482f6 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.009.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > " ";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.010.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.010.query.sqlpp
index bc1f51c..070ed6c 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.010.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > " ";
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.011.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.011.update.sqlpp
new file mode 100644
index 0000000..3d60aa4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.011.update.sqlpp
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+
+USE TestYelp;
+
+UPSERT INTO YelpCheckin (
+    [
+        {
+            "checkin_id": 1,
+            "business_id": "--1UhMGODdWsrMastO9DZw",
+            "dates": [
+                "2020-04-26 19:49:16",
+                "2020-08-30 18:36:57",
+                "2020-10-15 02:45:18",
+                "2020-11-18 01:54:50",
+                "2021-04-20 18:39:06",
+                "2021-05-03 17:58:02",
+                "2022-03-19 22:04:48"
+            ]
+        },
+        {
+            "checkin_id": 2,
+            "business_id": "--EF5N7P70J_UYBTPypYlA",
+            "dates": [
+                "2018-05-25 19:52:07",
+                "2018-09-18 16:09:44",
+                "2019-10-18 21:29:09"
+            ]
+        },
+        {
+            "checkin_id": 3,
+            "business_id": "--Ni3oJ4VOqfOEu7Sj2Vzg",
+            "dates": [
+                "2019-06-07 17:54:58"
+            ]
+        },
+        {
+            "checkin_id": 4,
+            "business_id": "--Y1Adl1YUWfYIRSd8vkmA",
+            "dates": [
+                "2011-05-03 20:54:05",
+                "2011-08-23 20:49:45",
+                "2014-12-04 06:13:01",
+                "2016-11-16 19:25:55"
+            ]
+        },
+        {
+            "checkin_id": 5,
+            "business_id": "--YPwqIlRJrhHkJcjY3eiA",
+            "dates": [
+                "2016-06-18 21:35:45",
+                "2016-10-15 18:17:51"
+            ]
+        },
+        {
+            "checkin_id": 6,
+            "business_id": "--e8PjCNhEz32pprnPhCwQ",
+            "dates": [
+                "2015-04-02 21:45:17"
+            ]
+        },
+        {
+            "checkin_id": 7,
+            "business_id": "--kinfHwmtdjz03g8B8z8Q",
+            "dates": [
+                "2014-08-27 17:49:18",
+                "2015-12-19 21:30:31",
+                "2018-11-27 15:53:50"
+            ]
+        },
+        {
+            "checkin_id": 8,
+            "business_id": "--q6datkI-f0EoVheXNEeQ",
+            "dates": [
+                "2014-01-28 20:56:04",
+                "2014-11-16 16:11:58",
+                "2015-11-15 19:21:53",
+                "2015-11-15 19:33:39"
+            ]
+        },
+        {
+            "checkin_id": 9,
+            "business_id": "--qvQS4MigHPykD2GV0-zw",
+            "dates": [
+                "2019-04-11 18:30:12"
+            ]
+        },
+        {
+            "checkin_id": 10,
+            "business_id": "--wIGbLEhlpl_UeAIyDmZQ",
+            "dates": [
+                "2015-06-06 20:01:06",
+                "2019-03-14 22:01:52"
+            ]
+        },
+        {
+            "checkin_id": 11,
+            "business_id": "-0FA-Qdi3SPYIoJz9UQw-A",
+            "dates": [
+                "2018-09-29 18:55:17",
+                "2018-10-20 16:48:05",
+                "2018-10-20 22:20:24"
+            ]
+        },
+        {
+            "checkin_id": 12,
+            "business_id": "-0Hj1hb_XW6ybWq2M7QhGA",
+            "dates": [
+                "2011-04-23 21:11:22",
+                "2014-05-04 19:42:48",
+                "2014-05-11 19:16:08",
+                "2014-06-04 19:14:18",
+                "2015-12-05 19:22:42",
+                "2017-05-15 23:19:00"
+            ]
+        },
+        {
+            "checkin_id": 13,
+            "business_id": "-0KMvRFwDWdVBeTpT11iHw",
+            "dates": [
+                "2012-07-13 21:43:57",
+                "2016-12-24 02:27:31",
+                "2017-08-31 00:35:26"
+            ]
+        },
+        {
+            "checkin_id": 14,
+            "business_id": "-0LPtgJC31FWMrMv317p0Q",
+            "dates": [
+                "2013-04-13 12:35:33",
+                "2013-08-19 23:35:49",
+                "2013-10-04 19:14:56"
+            ]
+        },
+        {
+            "checkin_id": 15,
+            "business_id": "-0M3o2uWBnQZwd3hmfEwuw",
+            "dates": [
+                "2016-09-10 19:26:19",
+                "2018-09-08 14:15:37",
+                "2019-09-13 22:47:25"
+            ]
+        },
+        {
+            "checkin_id": 16,
+            "business_id": "-0RRiWDtfnS16AKCtfvBZg",
+            "dates": [
+                "2017-05-19 14:30:16",
+                "2017-05-19 14:30:25",
+                "2017-08-28 15:49:37",
+                "2017-09-20 20:19:51",
+                "2017-10-01 16:31:05",
+                "2017-10-01 16:56:27",
+                "2017-12-27 23:33:20"
+            ]
+        },
+        {
+            "checkin_id": 17,
+            "business_id": "-0Soj75v-XoRcf2ERr8Bmg",
+            "dates": [
+                "2019-06-05 18:22:49"
+            ]
+        },
+        {
+            "checkin_id": 18,
+            "business_id": "-0ZumLlFjMh4ZW1z2nXGug",
+            "dates": [
+                "2011-09-24 21:37:32",
+                "2014-03-10 20:20:07",
+                "2015-05-27 00:40:24",
+                "2015-08-29 17:58:15",
+                "2018-03-16 15:03:26"
+            ]
+        },
+        {
+            "checkin_id": 19,
+            "business_id": "-0aOudcaAyac0VJbMX-L1g",
+            "dates": [
+                "2015-03-16 23:51:16",
+                "2015-12-21 04:48:01",
+                "2016-10-28 20:22:42",
+                "2016-10-28 20:23:00"
+            ]
+        },
+        {
+            "checkin_id": 20,
+            "business_id": "-0b86isaXMY0v4g-V8GZ9Q",
+            "dates": [
+                "2013-10-22 16:49:21",
+                "2014-11-21 17:39:24"
+            ]
+        },
+        {
+            "checkin_id": 21,
+            "business_id": "-0d-BfFSU0bwLcnMaGRxYw",
+            "dates": [
+                "2014-08-07 18:30:48",
+                "2014-09-16 20:41:45",
+                "2014-10-12 23:22:27",
+                "2015-07-21 20:43:56",
+                "2015-07-21 20:45:07"
+            ]
+        },
+        {
+            "checkin_id": 22,
+            "business_id": "-0jz6c3C6i7RG7Ag22K-Pg",
+            "dates": [
+                "2015-05-02 19:49:05",
+                "2015-05-06 03:52:18",
+                "2015-09-26 01:13:19"
+            ]
+        },
+        {
+            "checkin_id": 23,
+            "business_id": "-0y3MZU2oYP8r1ruDP1bfQ",
+            "dates": [
+                "2015-04-11 13:14:14",
+                "2015-11-21 16:05:56",
+                "2016-05-06 14:10:04",
+                "2017-08-09 15:15:10",
+                "2017-10-21 15:12:56"
+            ]
+        },
+        {
+            "checkin_id": 24,
+            "business_id": "-1BPe8UjF2_l3nVk-DFUjA",
+            "dates": [
+                "2015-12-03 18:44:00",
+                "2016-03-17 18:19:21",
+                "2016-11-02 15:58:38"
+            ]
+        },
+        {
+            "checkin_id": 25,
+            "business_id": "-1E2CQu_38mkghvmZgCCRw",
+            "dates": [
+                "2019-04-04 22:02:37"
+            ]
+        },
+        {
+            "checkin_id": 26,
+            "business_id": "-1wzk43IZ5D9Ysu6kzb5xA",
+            "dates": [
+                "2019-02-27 14:03:08"
+            ]
+        },
+        {
+            "checkin_id": 27,
+            "business_id": "-23R9P2eG7VTc6DVLjFKzA",
+            "dates": [
+                "2011-12-21 19:02:51",
+                "2012-04-15 04:21:39",
+                "2012-04-15 14:23:56",
+                "2013-06-30 22:39:51",
+                "2013-10-04 20:34:13",
+                "2014-07-16 02:28:40"
+            ]
+        },
+        {
+            "checkin_id": 28,
+            "business_id": "-26MGfikhJiTfCI-GqmzhQ",
+            "dates": [
+                "2018-06-13 20:16:07"
+            ]
+        },
+        {
+            "checkin_id": 29,
+            "business_id": "-2bLuJsMZ0WhI9daurVQNQ",
+            "dates": [
+                "2015-05-29 16:46:17",
+                "2015-06-01 15:03:53"
+            ]
+        },
+        {
+            "checkin_id": 30,
+            "business_id": "-2hDBMaza_ldqnZdiU06LQ",
+            "dates": [
+                "2011-10-08 12:02:23",
+                "2014-08-18 02:11:11",
+                "2016-01-07 05:27:51",
+                "2016-10-21 20:15:55",
+                "2016-12-01 03:57:10",
+                "2016-12-29 01:54:42",
+                "2018-07-22 19:55:31",
+                "2018-09-07 01:42:54",
+                "2019-03-08 03:41:06"
+            ]
+        }
+    ]
+);
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.012.get.http
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.012.get.http
index bc1f51c..a55ce93 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.012.get.http
@@ -16,8 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+/connector?dataverseName=TestYelp&datasetName=YelpCheckin
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.013.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.013.query.sqlpp
index bc1f51c..14482f6 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.013.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > " ";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.014.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.014.query.sqlpp
index bc1f51c..070ed6c 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.014.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > " ";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.100.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.100.query.sqlpp
index bc1f51c..07bf9df 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.100.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE substring(D, 0, 4) = "2011";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.101.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.101.query.sqlpp
index bc1f51c..90f7854 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.101.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE substring(D, 0, 4) = "2011";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.102.query.sqlpp
similarity index 84%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.102.query.sqlpp
index bc1f51c..ebfdeda 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.102.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE substring(D, 0, 4) = "2011";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.103.query.sqlpp
similarity index 82%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.103.query.sqlpp
index bc1f51c..e52c13b 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.103.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE substring(D, 0, 4) = "2011"
+   OR substring(D, 0, 4) = "2016";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.104.query.sqlpp
similarity index 79%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.104.query.sqlpp
index bc1f51c..b064c42 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.104.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE substring(D, 0, 4) = "2011"
+   OR substring(D, 0, 4) = "2016";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.105.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.105.query.sqlpp
index 69abb37..71cabb2 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.105.query.sqlpp
@@ -16,12 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-import org.apache.asterix.om.types.ATypeTag;
-
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE substring(D, 0, 4) = "2011"
+   OR substring(D, 0, 4) = "2016";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.106.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.106.query.sqlpp
index 69abb37..403a4f1 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.106.query.sqlpp
@@ -16,12 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
 
-import org.apache.asterix.om.types.ATypeTag;
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C
+WHERE (SOME D in C.dates SATISFIES substring(D, 0, 4) = "2011"
+                                OR substring(D, 0, 4) = "2016");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.107.query.sqlpp
similarity index 75%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.107.query.sqlpp
index 69abb37..42d7d1f 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.107.query.sqlpp
@@ -16,12 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
 
-import org.apache.asterix.om.types.ATypeTag;
-
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C
+WHERE (SOME D in C.dates SATISFIES substring(D, 0, 4) = "2011"
+                                OR substring(D, 0, 4) = "2016");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.108.query.sqlpp
similarity index 75%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.108.query.sqlpp
index 69abb37..997eb66 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.108.query.sqlpp
@@ -16,12 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-import org.apache.asterix.om.types.ATypeTag;
-
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+FROM YelpCheckin C
+WHERE (SOME D in C.dates SATISFIES substring(D, 0, 4) = "2011"
+                                OR substring(D, 0, 4) = "2016");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.109.query.sqlpp
similarity index 78%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.109.query.sqlpp
index 69abb37..a5c903c 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.109.query.sqlpp
@@ -16,12 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
 
-import org.apache.asterix.om.types.ATypeTag;
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C
+WHERE (SOME D in C.dates SATISFIES D = "2011-01-01 00:00:00"
+                                OR D = "2016-01-01 00:00:00");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.110.query.sqlpp
similarity index 66%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.110.query.sqlpp
index 62abb92..8622de1 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.110.query.sqlpp
@@ -16,13 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
 
-import java.io.Serializable;
-
-import org.apache.hyracks.api.exceptions.HyracksDataException;
-
-@FunctionalInterface
-public interface IColumnFilterEvaluatorFactory extends Serializable {
-    IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
-}
+SELECT COUNT(*)
+FROM YelpCheckin C
+-- This should pass the normalized filter, but not the actual filter
+-- the log should show: "Filtered 1 disk mega-leaf nodes out of 1 in total"
+WHERE (SOME D in C.dates SATISFIES D = "2011-01-01 00:00:00"
+                                OR D = "2016-01-01 00:00:00");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.111.query.sqlpp
similarity index 79%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.111.query.sqlpp
index bc1f51c..6c20890 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.111.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE starts_with(C.business_id, "-0")
+  AND (substring(D, 0, 4) = "2011"
+    OR substring(D, 0, 4) = "2016");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.112.query.sqlpp
similarity index 76%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.112.query.sqlpp
index 69abb37..085e295 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.112.query.sqlpp
@@ -16,12 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
 
-import org.apache.asterix.om.types.ATypeTag;
-
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE starts_with(C.business_id, "-0")
+  AND (substring(D, 0, 4) = "2011"
+    OR substring(D, 0, 4) = "2016");
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.113.query.sqlpp
similarity index 75%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.113.query.sqlpp
index 69abb37..024c065 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/004/004.113.query.sqlpp
@@ -16,12 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-import org.apache.asterix.om.types.ATypeTag;
-
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE starts_with(C.business_id, "-0")
+  AND (substring(D, 0, 4) = "2011"
+    OR substring(D, 0, 4) = "2016");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.001.ddl.sqlpp
similarity index 76%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.001.ddl.sqlpp
index 69abb37..ce257e2 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.001.ddl.sqlpp
@@ -16,12 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import org.apache.asterix.om.types.ATypeTag;
+DROP DATAVERSE TestYelp IF EXISTS;
+CREATE DATAVERSE TestYelp;
+USE TestYelp;
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
+CREATE TYPE CheckinType AS {
+    checkin_id: int
+};
 
-    ATypeTag getTypeTag();
-}
+CREATE DATASET YelpCheckin(CheckinType) PRIMARY KEY checkin_id WITH {
+    "storage-format" : {"format" : "column"}
+};
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.002.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.002.update.sqlpp
new file mode 100644
index 0000000..533e69d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.002.update.sqlpp
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+USE TestYelp;
+
+INSERT INTO YelpCheckin (
+    [
+        {
+            "checkin_id": 1,
+            "business_id": "--1UhMGODdWsrMastO9DZw",
+            "dates": [
+                2011,
+                2012,
+                2013,
+                2013,
+                2014,
+                2020,
+                2022
+            ]
+        },
+        {
+            "checkin_id": 2,
+            "business_id": "--EF5N7P70J_UYBTPypYlA",
+            "dates": [
+                "2018-05-25 19:52:07",
+                "2018-09-18 16:09:44",
+                "2019-10-18 21:29:09"
+            ]
+        },
+        {
+            "checkin_id": 3,
+            "business_id": "--Ni3oJ4VOqfOEu7Sj2Vzg",
+            "dates": [
+                "2019-06-07 17:54:58"
+            ]
+        },
+        {
+            "checkin_id": 4,
+            "business_id": "--Y1Adl1YUWfYIRSd8vkmA",
+            "dates": [
+                "2011-05-03 20:54:05",
+                "2011-08-23 20:49:45",
+                "2014-12-04 06:13:01",
+                "2016-11-16 19:25:55"
+            ]
+        },
+        {
+            "checkin_id": 5,
+            "business_id": "--YPwqIlRJrhHkJcjY3eiA",
+            "dates": [
+                "2016-06-18 21:35:45",
+                "2016-10-15 18:17:51"
+            ]
+        },
+        {
+            "checkin_id": 6,
+            "business_id": "--e8PjCNhEz32pprnPhCwQ",
+            "dates": [
+                "2015-04-02 21:45:17"
+            ]
+        },
+        {
+            "checkin_id": 7,
+            "business_id": "--kinfHwmtdjz03g8B8z8Q",
+            "dates": [
+                "2014-08-27 17:49:18",
+                "2015-12-19 21:30:31",
+                "2018-11-27 15:53:50"
+            ]
+        },
+        {
+            "checkin_id": 8,
+            "business_id": "--q6datkI-f0EoVheXNEeQ",
+            "dates": [
+                "2014-01-28 20:56:04",
+                "2014-11-16 16:11:58",
+                "2015-11-15 19:21:53",
+                "2015-11-15 19:33:39"
+            ]
+        },
+        {
+            "checkin_id": 9,
+            "business_id": "--qvQS4MigHPykD2GV0-zw",
+            "dates": [
+                "2019-04-11 18:30:12"
+            ]
+        },
+        {
+            "checkin_id": 10,
+            "business_id": "--wIGbLEhlpl_UeAIyDmZQ",
+            "dates": [
+                "2015-06-06 20:01:06",
+                "2019-03-14 22:01:52"
+            ]
+        },
+        {
+            "checkin_id": 11,
+            "business_id": "-0FA-Qdi3SPYIoJz9UQw-A",
+            "dates": [
+                "2018-09-29 18:55:17",
+                "2018-10-20 16:48:05",
+                "2018-10-20 22:20:24"
+            ]
+        },
+        {
+            "checkin_id": 12,
+            "business_id": "-0Hj1hb_XW6ybWq2M7QhGA",
+            "dates": [
+                "2011-04-23 21:11:22",
+                "2014-05-04 19:42:48",
+                "2014-05-11 19:16:08",
+                "2014-06-04 19:14:18",
+                "2015-12-05 19:22:42",
+                "2017-05-15 23:19:00"
+            ]
+        },
+        {
+            "checkin_id": 13,
+            "business_id": "-0KMvRFwDWdVBeTpT11iHw",
+            "dates": [
+                "2012-07-13 21:43:57",
+                "2016-12-24 02:27:31",
+                "2017-08-31 00:35:26"
+            ]
+        },
+        {
+            "checkin_id": 14,
+            "business_id": "-0LPtgJC31FWMrMv317p0Q",
+            "dates": [
+                "2013-04-13 12:35:33",
+                "2013-08-19 23:35:49",
+                "2013-10-04 19:14:56"
+            ]
+        },
+        {
+            "checkin_id": 15,
+            "business_id": "-0M3o2uWBnQZwd3hmfEwuw",
+            "dates": [
+                "2016-09-10 19:26:19",
+                "2018-09-08 14:15:37",
+                "2019-09-13 22:47:25"
+            ]
+        },
+        {
+            "checkin_id": 16,
+            "business_id": "-0RRiWDtfnS16AKCtfvBZg",
+            "dates": [
+                "2017-05-19 14:30:16",
+                "2017-05-19 14:30:25",
+                "2017-08-28 15:49:37",
+                "2017-09-20 20:19:51",
+                "2017-10-01 16:31:05",
+                "2017-10-01 16:56:27",
+                "2017-12-27 23:33:20"
+            ]
+        },
+        {
+            "checkin_id": 17,
+            "business_id": "-0Soj75v-XoRcf2ERr8Bmg",
+            "dates": [
+                "2019-06-05 18:22:49"
+            ]
+        },
+        {
+            "checkin_id": 18,
+            "business_id": "-0ZumLlFjMh4ZW1z2nXGug",
+            "dates": [
+                "2011-09-24 21:37:32",
+                "2014-03-10 20:20:07",
+                "2015-05-27 00:40:24",
+                "2015-08-29 17:58:15",
+                "2018-03-16 15:03:26"
+            ]
+        },
+        {
+            "checkin_id": 19,
+            "business_id": "-0aOudcaAyac0VJbMX-L1g",
+            "dates": [
+                "2015-03-16 23:51:16",
+                "2015-12-21 04:48:01",
+                "2016-10-28 20:22:42",
+                "2016-10-28 20:23:00"
+            ]
+        },
+        {
+            "checkin_id": 20,
+            "business_id": "-0b86isaXMY0v4g-V8GZ9Q",
+            "dates": [
+                "2013-10-22 16:49:21",
+                "2014-11-21 17:39:24"
+            ]
+        },
+        {
+            "checkin_id": 21,
+            "business_id": "-0d-BfFSU0bwLcnMaGRxYw",
+            "dates": [
+                "2014-08-07 18:30:48",
+                "2014-09-16 20:41:45",
+                "2014-10-12 23:22:27",
+                "2015-07-21 20:43:56",
+                "2015-07-21 20:45:07"
+            ]
+        },
+        {
+            "checkin_id": 22,
+            "business_id": "-0jz6c3C6i7RG7Ag22K-Pg",
+            "dates": [
+                "2015-05-02 19:49:05",
+                "2015-05-06 03:52:18",
+                "2015-09-26 01:13:19"
+            ]
+        },
+        {
+            "checkin_id": 23,
+            "business_id": "-0y3MZU2oYP8r1ruDP1bfQ",
+            "dates": [
+                "2015-04-11 13:14:14",
+                "2015-11-21 16:05:56",
+                "2016-05-06 14:10:04",
+                "2017-08-09 15:15:10",
+                "2017-10-21 15:12:56"
+            ]
+        },
+        {
+            "checkin_id": 24,
+            "business_id": "-1BPe8UjF2_l3nVk-DFUjA",
+            "dates": [
+                "2015-12-03 18:44:00",
+                "2016-03-17 18:19:21",
+                "2016-11-02 15:58:38"
+            ]
+        },
+        {
+            "checkin_id": 25,
+            "business_id": "-1E2CQu_38mkghvmZgCCRw",
+            "dates": []
+        },
+        {
+            "checkin_id": 26,
+            "business_id": "-1wzk43IZ5D9Ysu6kzb5xA",
+            "dates": []
+        },
+        {
+            "checkin_id": 27,
+            "business_id": "-23R9P2eG7VTc6DVLjFKzA",
+            "dates": [
+                "2011-12-21 19:02:51",
+                "2012-04-15 04:21:39",
+                "2012-04-15 14:23:56",
+                "2013-06-30 22:39:51",
+                "2013-10-04 20:34:13",
+                "2014-07-16 02:28:40"
+            ]
+        },
+        {
+            "checkin_id": 28,
+            "business_id": "-26MGfikhJiTfCI-GqmzhQ",
+            "dates": [
+                "2018-06-13 20:16:07"
+            ]
+        },
+        {
+            "checkin_id": 29,
+            "business_id": "-2bLuJsMZ0WhI9daurVQNQ",
+            "dates": [
+                "2015-05-29 16:46:17",
+                "2015-06-01 15:03:53"
+            ]
+        },
+        {
+            "checkin_id": 30,
+            "business_id": "-2hDBMaza_ldqnZdiU06LQ",
+            "dates": [
+                "2011-10-08 12:02:23",
+                "2014-08-18 02:11:11",
+                "2016-01-07 05:27:51",
+                "2016-10-21 20:15:55",
+                "2016-12-01 03:57:10",
+                "2016-12-29 01:54:42",
+                "2018-07-22 19:55:31",
+                "2018-09-07 01:42:54",
+                "2019-03-08 03:41:06"
+            ]
+        }
+    ]
+);
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.003.get.http
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.003.get.http
index bc1f51c..a55ce93 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.003.get.http
@@ -16,8 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+/connector?dataverseName=TestYelp&datasetName=YelpCheckin
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.004.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.004.query.sqlpp
index bc1f51c..896ecc7 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.004.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > 2019;
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.005.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.005.query.sqlpp
index bc1f51c..4cb8257 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.005.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D > 2019;
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.006.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.006.query.sqlpp
index bc1f51c..3452d22 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.006.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D + 1 > 2018;
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.007.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.007.query.sqlpp
index bc1f51c..cb8854d 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.007.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D + 1 > 2018;
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.008.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.008.query.sqlpp
index bc1f51c..721dfb9 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.008.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D + 1 > 2018;
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.009.query.sqlpp
similarity index 83%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.009.query.sqlpp
index bc1f51c..97ff3f5 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.009.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D + 1 > 2018
+   OR substring(D, 0, 4) = "2011";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.010.query.sqlpp
similarity index 80%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.010.query.sqlpp
index bc1f51c..6794433 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.010.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D + 1 > 2018
+   OR substring(D, 0, 4) = "2011";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.011.query.sqlpp
similarity index 79%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.011.query.sqlpp
index bc1f51c..a3757b2 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/005/005.011.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+SET `rewrite_or_as_join` "false";
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+FROM YelpCheckin C, C.dates D
+WHERE D + 1 > 2018
+   OR substring(D, 0, 4) = "2011";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.001.ddl.sqlpp
similarity index 78%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.001.ddl.sqlpp
index 69abb37..06d2d97 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.001.ddl.sqlpp
@@ -16,12 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import org.apache.asterix.om.types.ATypeTag;
+DROP DATAVERSE test if exists;
+CREATE DATAVERSE test;
+USE test;
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
+CREATE TYPE ColumnType AS {
+    id: int
+};
 
-    ATypeTag getTypeTag();
-}
+CREATE DATASET ColumnDataset(ColumnType)
+PRIMARY KEY id WITH {
+    "storage-format": {"format" : "column"}
+};
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.002.update.sqlpp
similarity index 60%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.002.update.sqlpp
index 62abb92..20d76d3 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.002.update.sqlpp
@@ -16,13 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import java.io.Serializable;
+USE test;
 
-import org.apache.hyracks.api.exceptions.HyracksDataException;
-
-@FunctionalInterface
-public interface IColumnFilterEvaluatorFactory extends Serializable {
-    IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
-}
+INSERT INTO ColumnDataset (
+    {"id": 1, "geo" : {"coordinates": [{"lon": 1}]}},
+    {"id": 2, "geo" : {"coordinates": [{"lon": 2}]}},
+    {"id": 3, "geo" : {"coordinates": [{"lon": 3}]}},
+    {"id": 4, "geo" : {"coordinates": [{"lon": 4}]}},
+    {"id": 5, "geo" : {"coordinates": [{"lon": [5.1], "lat": 1}]}},
+    {"id": 6, "geo" : {"coordinates": [{"lon": [6], "lat": 2}]}},
+    {"id": 7, "geo" : {"coordinates": [{"lon": 7, "lat": 3}]}},
+    {"id": 8, "geo" : {"coordinates": [{"lat": 4}]}}
+);
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.003.get.http
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.003.get.http
index bc1f51c..57d830a 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.003.get.http
@@ -16,8 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+/connector?dataverseName=test&datasetName=ColumnDataset
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.004.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.004.query.sqlpp
index bc1f51c..a351d7d 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.004.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE test;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM ColumnDataset c
+WHERE (SOME point in c.geo.coordinates SATISFIES point.lon = 4)
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.005.query.sqlpp
similarity index 83%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.005.query.sqlpp
index bc1f51c..caa905d 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.005.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE test;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM ColumnDataset c
+WHERE (SOME point in c.geo.coordinates SATISFIES point.lon = 4)
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.006.query.sqlpp
similarity index 85%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.006.query.sqlpp
index bc1f51c..f60de21 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.006.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE test;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM ColumnDataset c
+WHERE (SOME point in c.geo.coordinates SATISFIES point.lon = 7 AND point.lat = 3)
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.007.query.sqlpp
similarity index 82%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.007.query.sqlpp
index bc1f51c..5455f1d 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.007.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE test;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM ColumnDataset c
+WHERE (SOME point in c.geo.coordinates SATISFIES point.lon = 7 AND point.lat = 3)
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.008.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.008.query.sqlpp
index bc1f51c..1bdab57 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.008.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE test;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+
+SELECT COUNT(*)
+FROM ColumnDataset c
+WHERE (SOME point in c.geo.coordinates SATISFIES point.lon = [5.1])
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.009.query.sqlpp
similarity index 83%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.009.query.sqlpp
index bc1f51c..afc338a 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.009.query.sqlpp
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+USE test;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+SELECT COUNT(*)
+FROM ColumnDataset c
+WHERE (SOME point in c.geo.coordinates SATISFIES point.lon = [5.1])
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.010.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.010.query.sqlpp
index 69abb37..c46566f 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/006/006.010.query.sqlpp
@@ -16,12 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-import org.apache.asterix.om.types.ATypeTag;
-
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+USE test;
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+FROM ColumnDataset c
+-- Filter should not be pushed as we compare nested types
+WHERE (SOME point in c.geo.coordinates SATISFIES point.lon = [5.1])
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.001.ddl.sqlpp
similarity index 61%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.001.ddl.sqlpp
index 62abb92..954294f 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.001.ddl.sqlpp
@@ -16,13 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import java.io.Serializable;
+/*
+ * Description: Verify the following DML actions for an array->atomic index:
+ *     1) Insert into an empty index (non bulk-load operation).
+ *     2) Delete all-but-one entry from the index.
+ *     3) Upsert all entries into the index.
+ */
 
-import org.apache.hyracks.api.exceptions.HyracksDataException;
+DROP DATAVERSE TestYelp IF EXISTS;
+CREATE DATAVERSE TestYelp;
+USE TestYelp;
 
-@FunctionalInterface
-public interface IColumnFilterEvaluatorFactory extends Serializable {
-    IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
-}
+CREATE TYPE CheckinType AS {
+    business_id: string
+};
+
+CREATE DATASET YelpCheckin(CheckinType) PRIMARY KEY business_id WITH {
+    "storage-format" : {"format" : "column"}
+};
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.002.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.002.update.sqlpp
new file mode 100644
index 0000000..2549e8f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.002.update.sqlpp
@@ -0,0 +1,497 @@
+/*
+ * 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.
+ */
+
+USE TestYelp;
+
+INSERT INTO YelpCheckin (
+    [
+        {
+            "business_id": "--1UhMGODdWsrMastO9DZw",
+            "checkin_times": {
+                "dates": [
+                    "2016-04-26",
+                    "2016-08-30",
+                    "2016-10-15",
+                    "2016-11-18",
+                    "2017-04-20",
+                    "2017-05-03",
+                    "2019-03-19"
+                ],
+                "times": [
+                    "19:49:16",
+                    "18:36:57",
+                    "02:45:18",
+                    "01:54:50",
+                    "18:39:06",
+                    "17:58:02",
+                    "22:04:48"
+                ]
+            }
+        },
+        {
+            "business_id": "--EF5N7P70J_UYBTPypYlA",
+            "checkin_times": {
+                "dates": [
+                    "2018-05-25",
+                    "2018-09-18",
+                    "2019-10-18"
+                ],
+                "times": [
+                    "19:52:07",
+                    "16:09:44",
+                    "21:29:09"
+                ]
+            }
+        },
+        {
+            "business_id": "--Ni3oJ4VOqfOEu7Sj2Vzg",
+            "checkin_times": {
+                "dates": [
+                    "2019-06-07"
+                ],
+                "times": [
+                    "17:54:58"
+                ]
+            }
+        },
+        {
+            "business_id": "--Y1Adl1YUWfYIRSd8vkmA",
+            "checkin_times": {
+                "dates": [
+                    "2011-05-03",
+                    "2011-08-23",
+                    "2014-12-04",
+                    "2016-11-16"
+                ],
+                "times": [
+                    "20:54:05",
+                    "20:49:45",
+                    "06:13:01",
+                    "19:25:55"
+                ]
+            }
+        },
+        {
+            "business_id": "--YPwqIlRJrhHkJcjY3eiA",
+            "checkin_times": {
+                "dates": [
+                    "2016-06-18",
+                    "2016-10-15"
+                ],
+                "times": [
+                    "21:35:45",
+                    "18:17:51"
+                ]
+            }
+        },
+        {
+            "business_id": "--e8PjCNhEz32pprnPhCwQ",
+            "checkin_times": {
+                "dates": [
+                    "2015-04-02"
+                ],
+                "times": [
+                    "21:45:17"
+                ]
+            }
+        },
+        {
+            "business_id": "--kinfHwmtdjz03g8B8z8Q",
+            "checkin_times": {
+                "dates": [
+                    "2014-08-27",
+                    "2015-12-19",
+                    "2018-11-27"
+                ],
+                "times": [
+                    "17:49:18",
+                    "21:30:31",
+                    "15:53:50"
+                ]
+            }
+        },
+        {
+            "business_id": "--q6datkI-f0EoVheXNEeQ",
+            "checkin_times": {
+                "dates": [
+                    "2014-01-28",
+                    "2014-11-16",
+                    "2015-11-15",
+                    "2015-11-15"
+                ],
+                "times": [
+                    "20:56:04",
+                    "16:11:58",
+                    "19:21:53",
+                    "19:33:39"
+                ]
+            }
+        },
+        {
+            "business_id": "--qvQS4MigHPykD2GV0-zw",
+            "checkin_times": {
+                "dates": [
+                    "2019-04-11"
+                ],
+                "times": [
+                    "18:30:12"
+                ]
+            }
+        },
+        {
+            "business_id": "--wIGbLEhlpl_UeAIyDmZQ",
+            "checkin_times": {
+                "dates": [
+                    "2015-06-06",
+                    "2019-03-14"
+                ],
+                "times": [
+                    "20:01:06",
+                    "22:01:52"
+                ]
+            }
+        },
+        {
+            "business_id": "-0FA-Qdi3SPYIoJz9UQw-A",
+            "checkin_times": {
+                "dates": [
+                    "2018-09-29",
+                    "2018-10-20",
+                    "2018-10-20"
+                ],
+                "times": [
+                    "18:55:17",
+                    "16:48:05",
+                    "22:20:24"
+                ]
+            }
+        },
+        {
+            "business_id": "-0Hj1hb_XW6ybWq2M7QhGA",
+            "checkin_times": {
+                "dates": [
+                    "2011-04-23",
+                    "2014-05-04",
+                    "2014-05-11",
+                    "2014-06-04",
+                    "2015-12-05",
+                    "2017-05-15"
+                ],
+                "times": [
+                    "21:11:22",
+                    "19:42:48",
+                    "19:16:08",
+                    "19:14:18",
+                    "19:22:42",
+                    "23:19:00"
+                ]
+            }
+        },
+        {
+            "business_id": "-0KMvRFwDWdVBeTpT11iHw",
+            "checkin_times": {
+                "dates": [
+                    "2012-07-13",
+                    "2016-12-24",
+                    "2017-08-31"
+                ],
+                "times": [
+                    "21:43:57",
+                    "02:27:31",
+                    "00:35:26"
+                ]
+            }
+        },
+        {
+            "business_id": "-0LPtgJC31FWMrMv317p0Q",
+            "checkin_times": {
+                "dates": [
+                    "2013-04-13",
+                    "2013-08-19",
+                    "2013-10-04"
+                ],
+                "times": [
+                    "12:35:33",
+                    "23:35:49",
+                    "19:14:56"
+                ]
+            }
+        },
+        {
+            "business_id": "-0M3o2uWBnQZwd3hmfEwuw",
+            "checkin_times": {
+                "dates": [
+                    "2016-09-10",
+                    "2018-09-08",
+                    "2019-09-13"
+                ],
+                "times": [
+                    "19:26:19",
+                    "14:15:37",
+                    "22:47:25"
+                ]
+            }
+        },
+        {
+            "business_id": "-0RRiWDtfnS16AKCtfvBZg",
+            "checkin_times": {
+                "dates": [
+                    "2017-05-19",
+                    "2017-05-19",
+                    "2017-08-28",
+                    "2017-09-20",
+                    "2017-10-01",
+                    "2017-10-01",
+                    "2017-12-27"
+                ],
+                "times": [
+                    "14:30:16",
+                    "14:30:25",
+                    "15:49:37",
+                    "20:19:51",
+                    "16:31:05",
+                    "16:56:27",
+                    "23:33:20"
+                ]
+            }
+        },
+        {
+            "business_id": "-0Soj75v-XoRcf2ERr8Bmg",
+            "checkin_times": {
+                "dates": [
+                    "2019-06-05"
+                ],
+                "times": [
+                    "18:22:49"
+                ]
+            }
+        },
+        {
+            "business_id": "-0ZumLlFjMh4ZW1z2nXGug",
+            "checkin_times": {
+                "dates": [
+                    "2011-09-24",
+                    "2014-03-10",
+                    "2015-05-27",
+                    "2015-08-29",
+                    "2018-03-16"
+                ],
+                "times": [
+                    "21:37:32",
+                    "20:20:07",
+                    "00:40:24",
+                    "17:58:15",
+                    "15:03:26"
+                ]
+            }
+        },
+        {
+            "business_id": "-0aOudcaAyac0VJbMX-L1g",
+            "checkin_times": {
+                "dates": [
+                    "2015-03-16",
+                    "2015-12-21",
+                    "2016-10-28",
+                    "2016-10-28"
+                ],
+                "times": [
+                    "23:51:16",
+                    "04:48:01",
+                    "20:22:42",
+                    "20:23:00"
+                ]
+            }
+        },
+        {
+            "business_id": "-0b86isaXMY0v4g-V8GZ9Q",
+            "checkin_times": {
+                "dates": [
+                    "2013-10-22",
+                    "2014-11-21"
+                ],
+                "times": [
+                    "16:49:21",
+                    "17:39:24"
+                ]
+            }
+        },
+        {
+            "business_id": "-0d-BfFSU0bwLcnMaGRxYw",
+            "checkin_times": {
+                "dates": [
+                    "2014-08-07",
+                    "2014-09-16",
+                    "2014-10-12",
+                    "2015-07-21",
+                    "2015-07-21"
+                ],
+                "times": [
+                    "18:30:48",
+                    "20:41:45",
+                    "23:22:27",
+                    "20:43:56",
+                    "20:45:07"
+                ]
+            }
+        },
+        {
+            "business_id": "-0jz6c3C6i7RG7Ag22K-Pg",
+            "checkin_times": {
+                "dates": [
+                    "2015-05-02",
+                    "2015-05-06",
+                    "2015-09-26"
+                ],
+                "times": [
+                    "19:49:05",
+                    "03:52:18",
+                    "01:13:19"
+                ]
+            }
+        },
+        {
+            "business_id": "-0y3MZU2oYP8r1ruDP1bfQ",
+            "checkin_times": {
+                "dates": [
+                    "2015-04-11",
+                    "2015-11-21",
+                    "2016-05-06",
+                    "2017-08-09",
+                    "2017-10-21"
+                ],
+                "times": [
+                    "13:14:14",
+                    "16:05:56",
+                    "14:10:04",
+                    "15:15:10",
+                    "15:12:56"
+                ]
+            }
+        },
+        {
+            "business_id": "-1BPe8UjF2_l3nVk-DFUjA",
+            "checkin_times": {
+                "dates": [
+                    "2015-12-03",
+                    "2016-03-17",
+                    "2016-11-02"
+                ],
+                "times": [
+                    "18:44:00",
+                    "18:19:21",
+                    "15:58:38"
+                ]
+            }
+        },
+        {
+            "business_id": "-1E2CQu_38mkghvmZgCCRw",
+            "checkin_times": {
+                "dates": [
+                    "2019-04-04"
+                ],
+                "times": [
+                    "22:02:37"
+                ]
+            }
+        },
+        {
+            "business_id": "-1wzk43IZ5D9Ysu6kzb5xA",
+            "checkin_times": {
+                "dates": [
+                    "2019-02-27"
+                ],
+                "times": [
+                    "14:03:08"
+                ]
+            }
+        },
+        {
+            "business_id": "-23R9P2eG7VTc6DVLjFKzA",
+            "checkin_times": {
+                "dates": [
+                    "2011-12-21",
+                    "2012-04-15",
+                    "2012-04-15",
+                    "2013-06-30",
+                    "2013-10-04",
+                    "2014-07-16"
+                ],
+                "times": [
+                    "19:02:51",
+                    "04:21:39",
+                    "14:23:56",
+                    "22:39:51",
+                    "20:34:13",
+                    "02:28:40"
+                ]
+            }
+        },
+        {
+            "business_id": "-26MGfikhJiTfCI-GqmzhQ",
+            "checkin_times": {
+                "dates": [
+                    "2018-06-13"
+                ],
+                "times": [
+                    "20:16:07"
+                ]
+            }
+        },
+        {
+            "business_id": "-2bLuJsMZ0WhI9daurVQNQ",
+            "checkin_times": {
+                "dates": [
+                    "2015-05-29",
+                    "2015-06-01"
+                ],
+                "times": [
+                    "16:46:17",
+                    "15:03:53"
+                ]
+            }
+        },
+        {
+            "business_id": "-2hDBMaza_ldqnZdiU06LQ",
+            "checkin_times": {
+                "dates": [
+                    "2011-10-08",
+                    "2014-08-18",
+                    "2016-01-07",
+                    "2016-10-21",
+                    "2016-12-01",
+                    "2016-12-29",
+                    "2018-07-22",
+                    "2018-09-07",
+                    "2019-03-08"
+                ],
+                "times": [
+                    "12:02:23",
+                    "02:11:11",
+                    "05:27:51",
+                    "20:15:55",
+                    "03:57:10",
+                    "01:54:42",
+                    "19:55:31",
+                    "01:42:54",
+                    "03:41:06"
+                ]
+            }
+        }
+    ]
+);
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.003.get.http
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.003.get.http
index bc1f51c..a55ce93 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.003.get.http
@@ -16,8 +16,4 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
-
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+/connector?dataverseName=TestYelp&datasetName=YelpCheckin
\ No newline at end of file
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.004.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.004.query.sqlpp
index bc1f51c..e1fced3 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.004.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.checkin_times.dates D, C.checkin_times.times T
+WHERE D > " "
+  AND T > " ";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.005.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.005.query.sqlpp
index 69abb37..5f27784 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.005.query.sqlpp
@@ -16,12 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import org.apache.asterix.om.types.ATypeTag;
+USE TestYelp;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+SELECT COUNT(*)
+-- only the normalized filter should be applied here
+FROM YelpCheckin C, C.checkin_times.dates D, C.checkin_times.times T
+WHERE D > " "
+  AND T > " ";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.006.query.sqlpp
similarity index 84%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.006.query.sqlpp
index bc1f51c..2601f56 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.006.query.sqlpp
@@ -16,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+
+
+SELECT COUNT(*)
+FROM YelpCheckin C, C.checkin_times.dates D, C.checkin_times.times T
+WHERE substring(D, 0, 4) = "2016";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.007.query.sqlpp
similarity index 78%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.007.query.sqlpp
index 69abb37..6ad32d4 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.007.query.sqlpp
@@ -16,12 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-import org.apache.asterix.om.types.ATypeTag;
+USE TestYelp;
+SET `compiler.column.filter` "true";
 
-public interface IColumnFilterValueAccessor {
-    long getNormalizedValue();
-
-    ATypeTag getTypeTag();
-}
+SELECT COUNT(*)
+-- both filters should be applied
+FROM YelpCheckin C, C.checkin_times.dates D, C.checkin_times.times T
+WHERE substring(D, 0, 4) = "2016";
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.008.query.sqlpp
similarity index 85%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.008.query.sqlpp
index bc1f51c..0a04233 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.008.query.sqlpp
@@ -16,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+
+
+SELECT COUNT(*)
+FROM YelpCheckin C
+WHERE array_contains(C.checkin_times.dates, "2018-05-25");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.009.query.sqlpp
similarity index 80%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.009.query.sqlpp
index bc1f51c..379f7bc 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.009.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+SET `compiler.column.filter` "true";
+
+SELECT COUNT(*)
+-- both filter should not be applied
+FROM YelpCheckin C
+WHERE array_contains(C.checkin_times.dates, "2018-05-25");
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.010.query.sqlpp
similarity index 80%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.010.query.sqlpp
index bc1f51c..10e5e64 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluator.java
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/007/007.010.query.sqlpp
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
 
-public interface IColumnFilterEvaluator {
-    boolean evaluate();
-}
+USE TestYelp;
+SET `compiler.column.filter` "true";
+EXPLAIN
+SELECT COUNT(*)
+-- both filter should not be applied
+FROM YelpCheckin C
+WHERE array_contains(C.checkin_times.dates, "2018-05-25");
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.024.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.024.adm
new file mode 100644
index 0000000..90fc33f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.024.adm
@@ -0,0 +1,2 @@
+{ "a": "1", "item": 20 }
+{ "a": "1", "item": 30 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.025.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.025.plan
new file mode 100644
index 0000000..71e57f5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.025.plan
@@ -0,0 +1,36 @@
+distribute result [$$31] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    project ([$$31]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |PARTITIONED|
+      assign [$$31] <- [{"a": $$34, "item": $$item}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |PARTITIONED|
+        project ([$$34, $$item]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- STREAM_PROJECT  |PARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- SORT_MERGE_EXCHANGE [$$35(ASC), $$34(ASC), $$item(ASC) ]  |PARTITIONED|
+            order (ASC, $$35) (ASC, $$34) (ASC, $$item) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- STABLE_SORT [$$35(ASC), $$34(ASC), $$item(ASC)]  |PARTITIONED|
+              exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                select (gt($$item, 10)) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_SELECT  |PARTITIONED|
+                  project ([$$35, $$34, $$item]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    unnest $$item <- scan-collection($$36) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- UNNEST  |PARTITIONED|
+                      select (eq($$34, "1")) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- STREAM_SELECT  |PARTITIONED|
+                        project ([$$35, $$34, $$36]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          assign [$$34, $$36] <- [$$d.getField("a"), $$d.getField("array")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                          -- ASSIGN  |PARTITIONED|
+                            exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              data-scan []<-[$$35, $$d] <- test.ColumnDataset project ({a:any,array:[any]}) filter on (or(eq($$34, "1"), gt($$item, 10))) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.026.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.026.adm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/001/001.026.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/003/003.005.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/003/003.005.adm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/003/003.005.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.003.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.003.regexadm
new file mode 100644
index 0000000..980ba38
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.003.regexadm
@@ -0,0 +1 @@
+\Q{"keys":"checkin_id","type":{"type":"org.apache.asterix.om.types.ARecordType","name":"CheckinType","open":true,"fields":[{"checkin_id":{"type":"AInt64"}}]},"splits":[\E.*\Q]}\E
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.004.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.004.adm
new file mode 100644
index 0000000..fcc26c8
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.004.adm
@@ -0,0 +1 @@
+{ "$1": 99 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.005.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.005.adm
new file mode 100644
index 0000000..fcc26c8
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.005.adm
@@ -0,0 +1 @@
+{ "$1": 99 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.006.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.006.plan
new file mode 100644
index 0000000..ade1d22
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.006.plan
@@ -0,0 +1,34 @@
+distribute result [$$47] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$47]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$47] <- [{"$1": $$49}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$49] <- [agg-sql-sum($$51)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$51] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select (gt($$D, " ")) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$D]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  unnest $$D <- scan-collection($$50) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- UNNEST  |PARTITIONED|
+                    project ([$$50]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      assign [$$50] <- [$$C.getField("dates")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                      -- ASSIGN  |PARTITIONED|
+                        project ([$$C]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            data-scan []<-[$$48, $$C] <- TestYelp.YelpCheckin project ({dates:[any]}) filter on (gt($$D, " ")) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                            -- DATASOURCE_SCAN  |PARTITIONED|
+                              exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.008.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.008.regexadm
new file mode 100644
index 0000000..980ba38
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.008.regexadm
@@ -0,0 +1 @@
+\Q{"keys":"checkin_id","type":{"type":"org.apache.asterix.om.types.ARecordType","name":"CheckinType","open":true,"fields":[{"checkin_id":{"type":"AInt64"}}]},"splits":[\E.*\Q]}\E
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.009.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.009.adm
new file mode 100644
index 0000000..3e1a847
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.009.adm
@@ -0,0 +1 @@
+{ "$1": 7 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.010.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.010.adm
new file mode 100644
index 0000000..3e1a847
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.010.adm
@@ -0,0 +1 @@
+{ "$1": 7 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.012.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.012.regexadm
new file mode 100644
index 0000000..980ba38
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.012.regexadm
@@ -0,0 +1 @@
+\Q{"keys":"checkin_id","type":{"type":"org.apache.asterix.om.types.ARecordType","name":"CheckinType","open":true,"fields":[{"checkin_id":{"type":"AInt64"}}]},"splits":[\E.*\Q]}\E
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.013.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.013.adm
new file mode 100644
index 0000000..dc7ba8b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.013.adm
@@ -0,0 +1 @@
+{ "$1": 101 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.014.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.014.adm
new file mode 100644
index 0000000..dc7ba8b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.014.adm
@@ -0,0 +1 @@
+{ "$1": 101 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.100.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.100.adm
new file mode 100644
index 0000000..0e12992
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.100.adm
@@ -0,0 +1 @@
+{ "$1": 6 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.101.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.101.adm
new file mode 100644
index 0000000..0e12992
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.101.adm
@@ -0,0 +1 @@
+{ "$1": 6 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.102.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.102.plan
new file mode 100644
index 0000000..2e1acc5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.102.plan
@@ -0,0 +1,34 @@
+distribute result [$$48] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$48]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$48] <- [{"$1": $$50}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$50] <- [agg-sql-sum($$52)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$52] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select (eq(substring($$D, 0, 4), "2011")) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$D]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  unnest $$D <- scan-collection($$51) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- UNNEST  |PARTITIONED|
+                    project ([$$51]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      assign [$$51] <- [$$C.getField("dates")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                      -- ASSIGN  |PARTITIONED|
+                        project ([$$C]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            data-scan []<-[$$49, $$C] <- TestYelp.YelpCheckin project ({dates:[any]}) filter on (eq(substring($$D, 0, 4), "2011")) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                            -- DATASOURCE_SCAN  |PARTITIONED|
+                              exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.103.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.103.adm
new file mode 100644
index 0000000..7ed187a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.103.adm
@@ -0,0 +1 @@
+{ "$1": 20 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.104.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.104.adm
new file mode 100644
index 0000000..7ed187a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.104.adm
@@ -0,0 +1 @@
+{ "$1": 20 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.105.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.105.plan
new file mode 100644
index 0000000..7a074af
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.105.plan
@@ -0,0 +1,38 @@
+distribute result [$$51] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$51]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$51] <- [{"$1": $$54}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$54] <- [agg-sql-sum($$57)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$57] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select (or(eq($$58, "2011"), eq($$58, "2016"))) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$58]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  assign [$$58] <- [substring($$D, 0, 4)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- ASSIGN  |PARTITIONED|
+                    project ([$$D]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      unnest $$D <- scan-collection($$55) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                      -- UNNEST  |PARTITIONED|
+                        project ([$$55]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          assign [$$55] <- [$$C.getField("dates")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                          -- ASSIGN  |PARTITIONED|
+                            project ([$$C]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                            -- STREAM_PROJECT  |PARTITIONED|
+                              exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                data-scan []<-[$$53, $$C] <- TestYelp.YelpCheckin project ({dates:[any]}) filter on (or(eq(substring($$D, 0, 4), "2011"), eq(substring($$D, 0, 4), "2016"))) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                                -- DATASOURCE_SCAN  |PARTITIONED|
+                                  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                    empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                    -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.106.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.106.adm
new file mode 100644
index 0000000..6988da1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.106.adm
@@ -0,0 +1 @@
+{ "$1": 11 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.107.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.107.adm
new file mode 100644
index 0000000..6988da1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.107.adm
@@ -0,0 +1 @@
+{ "$1": 11 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.108.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.108.plan
new file mode 100644
index 0000000..248598b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.108.plan
@@ -0,0 +1,45 @@
+distribute result [$$52] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$52]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$52] <- [{"$1": $$55}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$55] <- [agg-sql-sum($$58)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$58] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select ($$45) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$45]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  subplan {
+                            aggregate [$$45] <- [non-empty-stream()] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                            -- AGGREGATE  |LOCAL|
+                              select (or(eq($$59, "2011"), eq($$59, "2016"))) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- STREAM_SELECT  |LOCAL|
+                                assign [$$59] <- [substring($$D, 0, 4)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- ASSIGN  |LOCAL|
+                                  unnest $$D <- scan-collection($$56) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- UNNEST  |LOCAL|
+                                    nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                    -- NESTED_TUPLE_SOURCE  |LOCAL|
+                         } [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- SUBPLAN  |PARTITIONED|
+                    project ([$$56]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      assign [$$56] <- [$$C.getField("dates")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                      -- ASSIGN  |PARTITIONED|
+                        project ([$$C]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            data-scan []<-[$$54, $$C] <- TestYelp.YelpCheckin project ({dates:[any]}) filter on (or(eq(substring($$D, 0, 4), "2011"), eq(substring($$D, 0, 4), "2016"))) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                            -- DATASOURCE_SCAN  |PARTITIONED|
+                              exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.109.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.109.adm
new file mode 100644
index 0000000..267992b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.109.adm
@@ -0,0 +1 @@
+{ "$1": 0 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.110.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.110.adm
new file mode 100644
index 0000000..267992b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.110.adm
@@ -0,0 +1 @@
+{ "$1": 0 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.111.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.111.adm
new file mode 100644
index 0000000..3e1a847
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.111.adm
@@ -0,0 +1 @@
+{ "$1": 7 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.112.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.112.adm
new file mode 100644
index 0000000..3e1a847
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.112.adm
@@ -0,0 +1 @@
+{ "$1": 7 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.113.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.113.plan
new file mode 100644
index 0000000..9d6667c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/004/004.113.plan
@@ -0,0 +1,40 @@
+distribute result [$$54] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$54]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$54] <- [{"$1": $$57}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$57] <- [agg-sql-sum($$61)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$61] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select (or(eq($$62, "2011"), eq($$62, "2016"))) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$62]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  assign [$$62] <- [substring($$D, 0, 4)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- ASSIGN  |PARTITIONED|
+                    project ([$$D]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      unnest $$D <- scan-collection($$59) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                      -- UNNEST  |PARTITIONED|
+                        project ([$$59]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          select (starts-with($$C.getField("business_id"), "-0")) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                          -- STREAM_SELECT  |PARTITIONED|
+                            assign [$$59] <- [$$C.getField("dates")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                            -- ASSIGN  |PARTITIONED|
+                              project ([$$C]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- STREAM_PROJECT  |PARTITIONED|
+                                exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  data-scan []<-[$$56, $$C] <- TestYelp.YelpCheckin project ({dates:[any],business_id:any}) filter on (or(starts-with($$C.getField("business_id"), "-0"), or(eq(substring($$D, 0, 4), "2011"), eq(substring($$D, 0, 4), "2016")))) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                                  -- DATASOURCE_SCAN  |PARTITIONED|
+                                    exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                      empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                      -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.003.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.003.regexadm
new file mode 100644
index 0000000..980ba38
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.003.regexadm
@@ -0,0 +1 @@
+\Q{"keys":"checkin_id","type":{"type":"org.apache.asterix.om.types.ARecordType","name":"CheckinType","open":true,"fields":[{"checkin_id":{"type":"AInt64"}}]},"splits":[\E.*\Q]}\E
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.004.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.004.adm
new file mode 100644
index 0000000..a5593dc
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.004.adm
@@ -0,0 +1 @@
+{ "$1": 2 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.005.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.005.adm
new file mode 100644
index 0000000..a5593dc
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.005.adm
@@ -0,0 +1 @@
+{ "$1": 2 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.006.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.006.adm
new file mode 100644
index 0000000..a5593dc
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.006.adm
@@ -0,0 +1 @@
+{ "$1": 2 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.007.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.007.adm
new file mode 100644
index 0000000..a5593dc
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.007.adm
@@ -0,0 +1 @@
+{ "$1": 2 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.008.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.008.plan
new file mode 100644
index 0000000..0a5304b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.008.plan
@@ -0,0 +1,34 @@
+distribute result [$$48] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$48]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$48] <- [{"$1": $$50}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$50] <- [agg-sql-sum($$52)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$52] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select (gt(numeric-add($$D, 1), 2018)) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$D]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  unnest $$D <- scan-collection($$51) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- UNNEST  |PARTITIONED|
+                    project ([$$51]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      assign [$$51] <- [$$C.getField("dates")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                      -- ASSIGN  |PARTITIONED|
+                        project ([$$C]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            data-scan []<-[$$49, $$C] <- TestYelp.YelpCheckin project ({dates:[any]}) filter on (gt(numeric-add($$D, 1), 2018)) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                            -- DATASOURCE_SCAN  |PARTITIONED|
+                              exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.009.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.009.adm
new file mode 100644
index 0000000..b62c7dd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.009.adm
@@ -0,0 +1 @@
+{ "$1": 8 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.010.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.010.adm
new file mode 100644
index 0000000..b62c7dd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.010.adm
@@ -0,0 +1 @@
+{ "$1": 8 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.011.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.011.plan
new file mode 100644
index 0000000..5048170
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/005/005.011.plan
@@ -0,0 +1,34 @@
+distribute result [$$51] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$51]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$51] <- [{"$1": $$53}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$53] <- [agg-sql-sum($$55)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$55] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select (or(gt(numeric-add($$D, 1), 2018), eq(substring($$D, 0, 4), "2011"))) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$D]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  unnest $$D <- scan-collection($$54) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- UNNEST  |PARTITIONED|
+                    project ([$$54]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      assign [$$54] <- [$$C.getField("dates")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                      -- ASSIGN  |PARTITIONED|
+                        project ([$$C]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            data-scan []<-[$$52, $$C] <- TestYelp.YelpCheckin project ({dates:[any]}) filter on (or(gt(numeric-add($$D, 1), 2018), eq(substring($$D, 0, 4), "2011"))) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                            -- DATASOURCE_SCAN  |PARTITIONED|
+                              exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.003.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.003.regexadm
new file mode 100644
index 0000000..81882d4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.003.regexadm
@@ -0,0 +1 @@
+\Q{"keys":"id","type":{"type":"org.apache.asterix.om.types.ARecordType","name":"ColumnType","open":true,"fields":[{"id":{"type":"AInt64"}}]},"splits":[\E.*\Q]}\E
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.004.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.004.adm
new file mode 100644
index 0000000..7cc3573
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.004.adm
@@ -0,0 +1 @@
+{ "$1": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.005.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.005.adm
new file mode 100644
index 0000000..7cc3573
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.005.adm
@@ -0,0 +1 @@
+{ "$1": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.006.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.006.adm
new file mode 100644
index 0000000..7cc3573
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.006.adm
@@ -0,0 +1 @@
+{ "$1": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.007.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.007.adm
new file mode 100644
index 0000000..7cc3573
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.007.adm
@@ -0,0 +1 @@
+{ "$1": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.008.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.008.adm
new file mode 100644
index 0000000..7cc3573
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.008.adm
@@ -0,0 +1 @@
+{ "$1": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.009.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.009.adm
new file mode 100644
index 0000000..7cc3573
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.009.adm
@@ -0,0 +1 @@
+{ "$1": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.010.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.010.plan
new file mode 100644
index 0000000..a1bba22
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/006/006.010.plan
@@ -0,0 +1,45 @@
+distribute result [$$51] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$51]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$51] <- [{"$1": $$53}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$53] <- [agg-sql-sum($$57)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$57] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select ($$44) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$44]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  subplan {
+                            aggregate [$$44] <- [non-empty-stream()] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                            -- AGGREGATE  |LOCAL|
+                              select (eq($$55, array: [ 5.1 ])) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- STREAM_SELECT  |LOCAL|
+                                assign [$$55] <- [$$point.getField("lon")] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- ASSIGN  |LOCAL|
+                                  unnest $$point <- scan-collection($$54) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- UNNEST  |LOCAL|
+                                    nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                    -- NESTED_TUPLE_SOURCE  |LOCAL|
+                         } [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- SUBPLAN  |PARTITIONED|
+                    project ([$$54]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      assign [$$54] <- [$$c.getField("geo").getField("coordinates")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                      -- ASSIGN  |PARTITIONED|
+                        project ([$$c]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                        -- STREAM_PROJECT  |PARTITIONED|
+                          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            data-scan []<-[$$52, $$c] <- test.ColumnDataset project ({geo:{coordinates:[{lon:any}]}}) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                            -- DATASOURCE_SCAN  |PARTITIONED|
+                              exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.003.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.003.regexadm
new file mode 100644
index 0000000..7f7e0cd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.003.regexadm
@@ -0,0 +1 @@
+\Q{"keys":"business_id","type":{"type":"org.apache.asterix.om.types.ARecordType","name":"CheckinType","open":true,"fields":[{"business_id":{"type":"AString"}}]},"splits":[\E.*\Q]}\E
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.004.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.004.adm
new file mode 100644
index 0000000..d369ddd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.004.adm
@@ -0,0 +1 @@
+{ "$1": 469 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.005.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.005.adm
new file mode 100644
index 0000000..d369ddd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.005.adm
@@ -0,0 +1 @@
+{ "$1": 469 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.006.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.006.adm
new file mode 100644
index 0000000..fe3f956
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.006.adm
@@ -0,0 +1 @@
+{ "$1": 97 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.007.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.007.adm
new file mode 100644
index 0000000..fe3f956
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.007.adm
@@ -0,0 +1 @@
+{ "$1": 97 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.008.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.008.adm
new file mode 100644
index 0000000..7cc3573
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.008.adm
@@ -0,0 +1 @@
+{ "$1": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.009.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.009.adm
new file mode 100644
index 0000000..7cc3573
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.009.adm
@@ -0,0 +1 @@
+{ "$1": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.010.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.010.plan
new file mode 100644
index 0000000..9620bd0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/007/007.010.plan
@@ -0,0 +1,26 @@
+distribute result [$$37] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    project ([$$37]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+    -- STREAM_PROJECT  |UNPARTITIONED|
+      assign [$$37] <- [{"$1": $$39}] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+      -- ASSIGN  |UNPARTITIONED|
+        aggregate [$$39] <- [agg-sql-sum($$42)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+        -- AGGREGATE  |UNPARTITIONED|
+          exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+          -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+            aggregate [$$42] <- [agg-sql-count(1)] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+            -- AGGREGATE  |PARTITIONED|
+              select (array-contains($$C.getField("checkin_times").getField("dates"), "2018-05-25")) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+              -- STREAM_SELECT  |PARTITIONED|
+                project ([$$C]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                -- STREAM_PROJECT  |PARTITIONED|
+                  exchange [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                    data-scan []<-[$$38, $$C] <- TestYelp.YelpCheckin project ({checkin_times:{dates:any}}) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                    -- DATASOURCE_SCAN  |PARTITIONED|
+                      exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 299e32a..ce4c1bd 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -16206,6 +16206,7 @@
         <output-dir compare="Text">filter/001</output-dir>
         <expected-warn>ASX0051: Incomparable input types: string and bigint (in line 30, at column 23)</expected-warn>
         <expected-warn>ASX0051: Incomparable input types: bigint and string (in line 29, at column 38)</expected-warn>
+        <expected-warn>ASX0051: Incomparable input types: array and bigint (in line 28, at column 15)</expected-warn>
       </compilation-unit>
     </test-case>
     <test-case FilePath="column" check-warnings="true">
@@ -16220,6 +16221,26 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="column">
+      <compilation-unit name="filter/004">
+        <output-dir compare="Text">filter/004</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="column">
+      <compilation-unit name="filter/005">
+        <output-dir compare="Text">filter/005</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="column">
+      <compilation-unit name="filter/006">
+        <output-dir compare="Text">filter/006</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="column">
+      <compilation-unit name="filter/007">
+        <output-dir compare="Text">filter/007</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="column">
       <compilation-unit name="big-object">
         <output-dir compare="Text">big-object</output-dir>
       </compilation-unit>
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java
index 2a29a70..1895404 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java
@@ -155,14 +155,17 @@
         AssemblerInfo itemInfo = new AssemblerInfo(itemDeclaredType, arrayAssembler, false);
         itemNode.accept(this, itemInfo);
 
-        // Set repeated assembler as a delegate (responsible for writing null values)
-        delegateAssembler.setAsDelegate();
-        IColumnValuesReader reader = delegateAssembler.getReader();
-        int numberOfDelimiters = reader.getNumberOfDelimiters();
-        // End of group assembler is responsible to finalize array/multiset builders
-        EndOfRepeatedGroupAssembler endOfGroupAssembler =
-                new EndOfRepeatedGroupAssembler(reader, arrayAssembler, numberOfDelimiters - delimiters.size());
-        valueAssemblers.add(endOfGroupAssembler);
+        // if delegateAssembler is null, that means no column will be accessed
+        if (delegateAssembler != null) {
+            // Set repeated assembler as a delegate (responsible for writing null values)
+            delegateAssembler.setAsDelegate();
+            IColumnValuesReader reader = delegateAssembler.getReader();
+            int numberOfDelimiters = reader.getNumberOfDelimiters();
+            // End of group assembler is responsible to finalize array/multiset builders
+            EndOfRepeatedGroupAssembler endOfGroupAssembler =
+                    new EndOfRepeatedGroupAssembler(reader, arrayAssembler, numberOfDelimiters - delimiters.size());
+            valueAssemblers.add(endOfGroupAssembler);
+        }
 
         level--;
         delimiters.removeInt(delimiters.size() - 1);
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/value/MissingValueGetter.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/value/MissingValueGetter.java
index 1ae84ee..2de77f4 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/value/MissingValueGetter.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/value/MissingValueGetter.java
@@ -25,7 +25,7 @@
 
 public class MissingValueGetter implements IValueGetter {
     public static final IValueGetter INSTANCE = new MissingValueGetter();
-    private static final VoidPointable MISSING;
+    public static final VoidPointable MISSING;
 
     static {
         MISSING = new VoidPointable();
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/FalseColumnFilterEvaluator.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/FalseColumnFilterEvaluator.java
similarity index 66%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/FalseColumnFilterEvaluator.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/FalseColumnFilterEvaluator.java
index fccd015..f53208b 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/FalseColumnFilterEvaluator.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/FalseColumnFilterEvaluator.java
@@ -16,23 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.evaluator;
+package org.apache.asterix.column.filter;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
 
-public class FalseColumnFilterEvaluator implements IColumnFilterEvaluator {
-    public static final IColumnFilterEvaluator INSTANCE = new FalseColumnFilterEvaluator();
+public class FalseColumnFilterEvaluator implements IColumnIterableFilterEvaluator {
+    public static final IColumnIterableFilterEvaluator INSTANCE = new FalseColumnFilterEvaluator();
 
     private FalseColumnFilterEvaluator() {
     }
 
     @Override
+    public void reset() {
+
+    }
+
+    @Override
     public boolean evaluate() {
         return false;
     }
 
     @Override
-    public String toString() {
-        return "FALSE";
+    public int getTupleIndex() {
+        return -1;
+    }
+
+    @Override
+    public void setAt(int index) {
+        // NoOp
     }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/FilterAccessorProvider.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/FilterAccessorProvider.java
new file mode 100644
index 0000000..2302aa6
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/FilterAccessorProvider.java
@@ -0,0 +1,178 @@
+/*
+ * 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.column.filter;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.asterix.column.assembler.value.IValueGetter;
+import org.apache.asterix.column.assembler.value.IValueGetterFactory;
+import org.apache.asterix.column.filter.iterable.accessor.ColumnFilterValueAccessorEvaluator;
+import org.apache.asterix.column.filter.iterable.accessor.MissingEvaluator;
+import org.apache.asterix.column.filter.iterable.accessor.UnionColumnFilterValueAccessorEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.accessor.ColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.accessor.NoOpColumnFilterValueAccessor;
+import org.apache.asterix.column.metadata.schema.AbstractSchemaNode;
+import org.apache.asterix.column.metadata.schema.ObjectSchemaNode;
+import org.apache.asterix.column.metadata.schema.primitive.MissingFieldSchemaNode;
+import org.apache.asterix.column.metadata.schema.primitive.PrimitiveSchemaNode;
+import org.apache.asterix.column.metadata.schema.visitor.PathExtractorVisitor;
+import org.apache.asterix.column.metadata.schema.visitor.SchemaClipperVisitor;
+import org.apache.asterix.column.values.IColumnValuesReader;
+import org.apache.asterix.column.values.IColumnValuesReaderFactory;
+import org.apache.asterix.column.values.writer.filters.AbstractColumnFilterWriter;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public class FilterAccessorProvider {
+    public static final String FILTER_ACCESSOR_PROVIDER_KEY = "filter-accessor-provider";
+    private final ObjectSchemaNode root;
+    private final ObjectSchemaNode metaRoot;
+    private final SchemaClipperVisitor clipperVisitor;
+    private final PathExtractorVisitor pathExtractorVisitor;
+    private final Map<ARecordType, PrimitiveSchemaNode> cachedNodes;
+    private final List<IColumnFilterNormalizedValueAccessor> filterAccessors;
+    private final List<IColumnValuesReader> filterColumnReaders;
+    private final IValueGetterFactory valueGetterFactory;
+
+    public FilterAccessorProvider(ObjectSchemaNode root, SchemaClipperVisitor clipperVisitor,
+            IColumnValuesReaderFactory readerFactory, IValueGetterFactory valueGetterFactory) {
+        this(root, null, clipperVisitor, readerFactory, valueGetterFactory);
+    }
+
+    public FilterAccessorProvider(ObjectSchemaNode root, ObjectSchemaNode metaRoot, SchemaClipperVisitor clipperVisitor,
+            IColumnValuesReaderFactory readerFactory, IValueGetterFactory valueGetterFactory) {
+        this.root = root;
+        this.metaRoot = metaRoot;
+        this.clipperVisitor = clipperVisitor;
+        this.valueGetterFactory = valueGetterFactory;
+        pathExtractorVisitor = new PathExtractorVisitor(readerFactory);
+        cachedNodes = new HashMap<>();
+        filterAccessors = new ArrayList<>();
+        filterColumnReaders = new ArrayList<>();
+    }
+
+    public void reset() {
+        cachedNodes.clear();
+    }
+
+    public IColumnFilterNormalizedValueAccessor createColumnFilterNormalizedValueAccessor(ARecordType path, boolean min)
+            throws HyracksDataException {
+        PrimitiveSchemaNode node = cachedNodes.get(path);
+        if (node == null) {
+            AbstractSchemaNode pathNode = getNode(path);
+            node = (PrimitiveSchemaNode) (pathNode.isNested() ? MissingFieldSchemaNode.INSTANCE : pathNode);
+            cachedNodes.put(path, node);
+        }
+
+        ATypeTag typeTag = node.getTypeTag();
+        if (typeTag == ATypeTag.MISSING) {
+            return NoOpColumnFilterValueAccessor.INSTANCE;
+        }
+        IColumnFilterNormalizedValueAccessor accessor =
+                new ColumnFilterNormalizedValueAccessor(node.getColumnIndex(), typeTag, min);
+        filterAccessors.add(accessor);
+        return accessor;
+    }
+
+    public IScalarEvaluator createColumnAccessEvaluator(ARecordType path) throws HyracksDataException {
+        List<IColumnValuesReader> readers = createReaders(path);
+        if (readers.isEmpty()) {
+            return MissingEvaluator.INSTANCE;
+        } else if (readers.size() == 1) {
+            IColumnValuesReader reader = readers.get(0);
+            IValueGetter valueGetter = valueGetterFactory.createValueGetter(reader.getTypeTag());
+            return new ColumnFilterValueAccessorEvaluator(reader, valueGetter);
+        }
+        // Union readers
+        IColumnValuesReader[] unionReaders = new IColumnValuesReader[readers.size()];
+        IValueGetter[] valueGetters = new IValueGetter[readers.size()];
+        for (int i = 0; i < readers.size(); i++) {
+            IColumnValuesReader reader = readers.get(i);
+            unionReaders[i] = reader;
+            valueGetters[i] = valueGetterFactory.createValueGetter(reader.getTypeTag());
+        }
+        return new UnionColumnFilterValueAccessorEvaluator(unionReaders, valueGetters);
+    }
+
+    public List<IColumnFilterNormalizedValueAccessor> getFilterAccessors() {
+        return filterAccessors;
+    }
+
+    public List<IColumnValuesReader> getFilterColumnReaders() {
+        return filterColumnReaders;
+    }
+
+    public static void setFilterValues(List<IColumnFilterNormalizedValueAccessor> filterValueAccessors,
+            ByteBuffer pageZero, int numberOfColumns) {
+        for (int i = 0; i < filterValueAccessors.size(); i++) {
+            ColumnFilterNormalizedValueAccessor accessor =
+                    (ColumnFilterNormalizedValueAccessor) filterValueAccessors.get(i);
+            int columnIndex = accessor.getColumnIndex();
+            long normalizedValue;
+            if (columnIndex < numberOfColumns) {
+                int filterOffset = pageZero.position() + columnIndex * AbstractColumnFilterWriter.FILTER_SIZE;
+                normalizedValue =
+                        accessor.isMin() ? pageZero.getLong(filterOffset) : pageZero.getLong(filterOffset + Long.BYTES);
+            } else {
+                // Column is missing
+                normalizedValue = accessor.isMin() ? Long.MAX_VALUE : Long.MIN_VALUE;
+            }
+            accessor.setNormalizedValue(normalizedValue);
+        }
+    }
+
+    private AbstractSchemaNode getNode(ARecordType path) throws HyracksDataException {
+        ObjectSchemaNode dataPath = (ObjectSchemaNode) path.accept(clipperVisitor, root);
+        AbstractSchemaNode node = dataPath.accept(pathExtractorVisitor, null);
+        if (node.getTypeTag() == ATypeTag.MISSING && metaRoot != null) {
+            //Try meta
+            ObjectSchemaNode metaPath = (ObjectSchemaNode) path.accept(clipperVisitor, metaRoot);
+            node = metaPath.accept(pathExtractorVisitor, null);
+        }
+
+        return node;
+    }
+
+    private List<IColumnValuesReader> createReaders(ARecordType path) throws HyracksDataException {
+        List<IColumnValuesReader> readers = Collections.emptyList();
+        if (!cachedNodes.containsKey(path)) {
+            ObjectSchemaNode dataPath = (ObjectSchemaNode) path.accept(clipperVisitor, root);
+            readers = pathExtractorVisitor.getOrCreateReaders(dataPath, filterColumnReaders);
+            if (readers.isEmpty() && metaRoot != null) {
+                //Try meta
+                ObjectSchemaNode metaPath = (ObjectSchemaNode) path.accept(clipperVisitor, metaRoot);
+                readers = pathExtractorVisitor.getOrCreateReaders(metaPath, filterColumnReaders);
+            }
+
+            if (readers.isEmpty()) {
+                cachedNodes.put(path, (PrimitiveSchemaNode) MissingFieldSchemaNode.INSTANCE);
+            }
+        }
+
+        return readers;
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/IColumnFilterEvaluator.java
similarity index 61%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
copy to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/IColumnFilterEvaluator.java
index 62abb92..023e04f 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/IColumnFilterEvaluator.java
@@ -16,13 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+package org.apache.asterix.column.filter;
 
-import java.io.Serializable;
-
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
-@FunctionalInterface
-public interface IColumnFilterEvaluatorFactory extends Serializable {
-    IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
+/**
+ * An evaluator created by either {@link IColumnNormalizedFilterEvaluatorFactory}
+ * or {@link IColumnIterableFilterEvaluatorFactory}.
+ */
+public interface IColumnFilterEvaluator {
+    /**
+     * @return true or false depend on the evaluated value(s)
+     */
+    boolean evaluate() throws HyracksDataException;
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/IFilterApplier.java
similarity index 61%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
copy to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/IFilterApplier.java
index 62abb92..0285190 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/IFilterApplier.java
@@ -16,13 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+package org.apache.asterix.column.filter;
 
-import java.io.Serializable;
-
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.asterix.om.types.ATypeTag;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IValueReference;
 
+/**
+ * Applies {@link IColumnIterableFilterEvaluator} to filter out tuples that do not satisfy the filter expression
+ */
 @FunctionalInterface
-public interface IColumnFilterEvaluatorFactory extends Serializable {
-    IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
+public interface IFilterApplier {
+    /**
+     * @return the tuple if the filter evaluator returns true or {@link ATypeTag#MISSING} o.w
+     */
+    IValueReference getTuple() throws HyracksDataException;
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/NoOpColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/NoOpColumnFilterEvaluatorFactory.java
new file mode 100644
index 0000000..b14402b
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/NoOpColumnFilterEvaluatorFactory.java
@@ -0,0 +1,53 @@
+/*
+ * 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.column.filter;
+
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+/**
+ * The factory returns {@link TrueColumnFilterEvaluator#INSTANCE} which evaluates always to true
+ */
+public class NoOpColumnFilterEvaluatorFactory
+        implements IColumnNormalizedFilterEvaluatorFactory, IColumnIterableFilterEvaluatorFactory {
+    private static final long serialVersionUID = -7122361396576592000L;
+    public static final NoOpColumnFilterEvaluatorFactory INSTANCE = new NoOpColumnFilterEvaluatorFactory();
+
+    private NoOpColumnFilterEvaluatorFactory() {
+    }
+
+    @Override
+    public IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException {
+        return TrueColumnFilterEvaluator.INSTANCE;
+    }
+
+    @Override
+    public IColumnIterableFilterEvaluator create(FilterAccessorProvider filterAccessorProvider,
+            IEvaluatorContext context) throws HyracksDataException {
+        return TrueColumnFilterEvaluator.INSTANCE;
+    }
+
+    @Override
+    public String toString() {
+        return "TRUE";
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/TrueColumnFilterEvaluator.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/TrueColumnFilterEvaluator.java
similarity index 61%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/TrueColumnFilterEvaluator.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/TrueColumnFilterEvaluator.java
index 37f1c5c..86ccab3 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/TrueColumnFilterEvaluator.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/TrueColumnFilterEvaluator.java
@@ -16,26 +16,37 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.evaluator;
+package org.apache.asterix.column.filter;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
 
 /**
  * This evaluator is also used to indicate a NoOp filter
  */
-public class TrueColumnFilterEvaluator implements IColumnFilterEvaluator {
-    public static final IColumnFilterEvaluator INSTANCE = new TrueColumnFilterEvaluator();
+public class TrueColumnFilterEvaluator implements IColumnIterableFilterEvaluator {
+    public static final IColumnIterableFilterEvaluator INSTANCE = new TrueColumnFilterEvaluator();
 
     private TrueColumnFilterEvaluator() {
     }
 
     @Override
-    public boolean evaluate() {
+    public boolean evaluate() throws HyracksDataException {
         return true;
     }
 
     @Override
-    public String toString() {
-        return "TRUE";
+    public void reset() {
+        // NoOp
+    }
+
+    @Override
+    public int getTupleIndex() {
+        return -1;
+    }
+
+    @Override
+    public void setAt(int index) {
+        // NoOp
     }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/IColumnIterableFilterEvaluator.java
similarity index 74%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/IColumnIterableFilterEvaluator.java
index 62abb92..67eb135 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/IColumnIterableFilterEvaluator.java
@@ -16,13 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+package org.apache.asterix.column.filter.iterable;
 
-import java.io.Serializable;
-
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
-@FunctionalInterface
-public interface IColumnFilterEvaluatorFactory extends Serializable {
-    IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
+public interface IColumnIterableFilterEvaluator extends IColumnFilterEvaluator {
+    void reset();
+
+    int getTupleIndex();
+
+    void setAt(int index) throws HyracksDataException;
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/IColumnIterableFilterEvaluatorFactory.java
similarity index 68%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
copy to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/IColumnIterableFilterEvaluatorFactory.java
index 62abb92..99df077 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/IColumnIterableFilterEvaluatorFactory.java
@@ -16,13 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+package org.apache.asterix.column.filter.iterable;
 
 import java.io.Serializable;
 
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
-@FunctionalInterface
-public interface IColumnFilterEvaluatorFactory extends Serializable {
-    IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
+public interface IColumnIterableFilterEvaluatorFactory extends Serializable {
+    IColumnIterableFilterEvaluator create(FilterAccessorProvider filterAccessorProvider, IEvaluatorContext context)
+            throws HyracksDataException;
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/ColumnFilterValueAccessorEvaluator.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/ColumnFilterValueAccessorEvaluator.java
new file mode 100644
index 0000000..57f4db6
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/ColumnFilterValueAccessorEvaluator.java
@@ -0,0 +1,48 @@
+/*
+ * 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.column.filter.iterable.accessor;
+
+import org.apache.asterix.column.assembler.value.IValueGetter;
+import org.apache.asterix.column.values.IColumnValuesReader;
+import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class ColumnFilterValueAccessorEvaluator implements IScalarEvaluator {
+    private final IColumnValuesReader reader;
+    private final IValueGetter getter;
+
+    public ColumnFilterValueAccessorEvaluator(IColumnValuesReader reader, IValueGetter getter) {
+        this.reader = reader;
+        this.getter = getter;
+    }
+
+    @Override
+    public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+        if (reader.isRepeated() && !reader.isRepeatedValue() || reader.isMissing()) {
+            PointableHelper.setMissing(result);
+        } else if (reader.isNull()) {
+            PointableHelper.setNull(result);
+        } else {
+            result.set(getter.getValue(reader));
+        }
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/ColumnFilterValueAccessorEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/ColumnFilterValueAccessorEvaluatorFactory.java
new file mode 100644
index 0000000..ce26d6b
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/ColumnFilterValueAccessorEvaluatorFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.column.filter.iterable.accessor;
+
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.dataflow.common.utils.TaskUtil;
+
+public class ColumnFilterValueAccessorEvaluatorFactory implements IScalarEvaluatorFactory {
+    private static final long serialVersionUID = -7871899093673316190L;
+    private final ARecordType path;
+
+    public ColumnFilterValueAccessorEvaluatorFactory(ARecordType path) {
+        this.path = path;
+    }
+
+    @Override
+    public IScalarEvaluator createScalarEvaluator(IEvaluatorContext ctx) throws HyracksDataException {
+        IHyracksTaskContext taskContext = ctx.getTaskContext();
+        FilterAccessorProvider provider =
+                TaskUtil.get(FilterAccessorProvider.FILTER_ACCESSOR_PROVIDER_KEY, taskContext);
+        if (provider == null) {
+            throw new IllegalStateException("FILTER_ACCESSOR_PROVIDER_KEY is not set");
+        }
+        return provider.createColumnAccessEvaluator(path);
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/MissingEvaluator.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/MissingEvaluator.java
new file mode 100644
index 0000000..8cb1211
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/MissingEvaluator.java
@@ -0,0 +1,37 @@
+/*
+ * 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.column.filter.iterable.accessor;
+
+import org.apache.asterix.column.assembler.value.MissingValueGetter;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class MissingEvaluator implements IScalarEvaluator {
+    public static final IScalarEvaluator INSTANCE = new MissingEvaluator();
+
+    private MissingEvaluator() {
+    }
+
+    @Override
+    public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+        result.set(MissingValueGetter.MISSING);
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/UnionColumnFilterValueAccessorEvaluator.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/UnionColumnFilterValueAccessorEvaluator.java
new file mode 100644
index 0000000..48d0f69
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/accessor/UnionColumnFilterValueAccessorEvaluator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.column.filter.iterable.accessor;
+
+import org.apache.asterix.column.assembler.value.IValueGetter;
+import org.apache.asterix.column.values.IColumnValuesReader;
+import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class UnionColumnFilterValueAccessorEvaluator implements IScalarEvaluator {
+    private final IColumnValuesReader[] readers;
+    private final IValueGetter[] valueGetters;
+
+    public UnionColumnFilterValueAccessorEvaluator(IColumnValuesReader[] readers, IValueGetter[] valueGetters) {
+        this.readers = readers;
+        this.valueGetters = valueGetters;
+    }
+
+    @Override
+    public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+        for (int i = 0; i < readers.length; i++) {
+            IColumnValuesReader reader = readers[i];
+            IValueGetter getter = valueGetters[i];
+            if (setValue(reader, getter, result)) {
+                return;
+            }
+        }
+        // All values were missing
+        PointableHelper.setMissing(result);
+    }
+
+    private boolean setValue(IColumnValuesReader reader, IValueGetter getter, IPointable result) {
+        if (reader.isRepeated() && !reader.isRepeatedValue() || reader.isMissing()) {
+            return false;
+        }
+
+        if (reader.isNull()) {
+            PointableHelper.setNull(result);
+        } else {
+            result.set(getter.getValue(reader));
+        }
+        return true;
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/AbstractIterableFilterEvaluator.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/AbstractIterableFilterEvaluator.java
new file mode 100644
index 0000000..9ebb7b7
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/AbstractIterableFilterEvaluator.java
@@ -0,0 +1,62 @@
+/*
+ * 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.column.filter.iterable.evaluator;
+
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.asterix.formats.nontagged.BinaryBooleanInspector;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+
+abstract class AbstractIterableFilterEvaluator implements IColumnIterableFilterEvaluator {
+    protected final IScalarEvaluator evaluator;
+    private final VoidPointable booleanResult;
+    protected int index;
+
+    AbstractIterableFilterEvaluator(IScalarEvaluator evaluator) {
+        this.evaluator = evaluator;
+        this.booleanResult = new VoidPointable();
+        reset();
+    }
+
+    @Override
+    public final void reset() {
+        index = -1;
+    }
+
+    @Override
+    public final int getTupleIndex() {
+        return index;
+    }
+
+    @Override
+    public final void setAt(int index) throws HyracksDataException {
+        int count = index - this.index;
+        // count - 1 as we want to evaluate the value at 'index'
+        skip(count - 1);
+    }
+
+    protected abstract void skip(int count) throws HyracksDataException;
+
+    protected final boolean inspect() throws HyracksDataException {
+        evaluator.evaluate(null, booleanResult);
+        return BinaryBooleanInspector.getBooleanValue(booleanResult.getByteArray(), booleanResult.getStartOffset(),
+                booleanResult.getLength());
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnIterableFilterEvaluator.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnIterableFilterEvaluator.java
new file mode 100644
index 0000000..2878429
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnIterableFilterEvaluator.java
@@ -0,0 +1,64 @@
+/*
+ * 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.column.filter.iterable.evaluator;
+
+import java.util.List;
+
+import org.apache.asterix.column.values.IColumnValuesReader;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public class ColumnIterableFilterEvaluator extends AbstractIterableFilterEvaluator {
+    private final List<IColumnValuesReader> readers;
+
+    public ColumnIterableFilterEvaluator(IScalarEvaluator evaluator, List<IColumnValuesReader> readers) {
+        super(evaluator);
+        this.readers = readers;
+    }
+
+    @Override
+    public boolean evaluate() throws HyracksDataException {
+        boolean result = false;
+        while (!result && next()) {
+            result = inspect();
+            index++;
+        }
+        if (!result) {
+            // Last tuple does not satisfy the condition
+            index++;
+        }
+        return result;
+    }
+
+    private boolean next() throws HyracksDataException {
+        for (int i = 0; i < readers.size(); i++) {
+            if (!readers.get(i).next()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void skip(int count) throws HyracksDataException {
+        for (int i = 0; count > 0 && i < readers.size(); i++) {
+            readers.get(i).skip(count);
+        }
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnIterableFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnIterableFilterEvaluatorFactory.java
new file mode 100644
index 0000000..1264c24
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnIterableFilterEvaluatorFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.column.filter.iterable.evaluator;
+
+import java.util.List;
+
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.values.IColumnValuesReader;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public class ColumnIterableFilterEvaluatorFactory implements IColumnIterableFilterEvaluatorFactory {
+    private static final long serialVersionUID = 171140626152211361L;
+    private final IScalarEvaluatorFactory evaluatorFactory;
+
+    public ColumnIterableFilterEvaluatorFactory(IScalarEvaluatorFactory evaluatorFactory) {
+        this.evaluatorFactory = evaluatorFactory;
+    }
+
+    @Override
+    public IColumnIterableFilterEvaluator create(FilterAccessorProvider filterAccessorProvider,
+            IEvaluatorContext context) throws HyracksDataException {
+        IScalarEvaluator evaluator = evaluatorFactory.createScalarEvaluator(context);
+        List<IColumnValuesReader> readers = filterAccessorProvider.getFilterColumnReaders();
+        if (readers.stream().anyMatch(IColumnValuesReader::isRepeated)) {
+            return new ColumnarRepeatedIterableFilterEvaluator(evaluator, readers);
+        }
+        return new ColumnIterableFilterEvaluator(evaluator, readers);
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnarRepeatedIterableFilterEvaluator.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnarRepeatedIterableFilterEvaluator.java
new file mode 100644
index 0000000..7db9f65
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/iterable/evaluator/ColumnarRepeatedIterableFilterEvaluator.java
@@ -0,0 +1,92 @@
+/*
+ * 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.column.filter.iterable.evaluator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.column.values.IColumnValuesReader;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public class ColumnarRepeatedIterableFilterEvaluator extends AbstractIterableFilterEvaluator {
+    private final List<IColumnValuesReader> readers;
+    private final List<IColumnValuesReader> repeatedReaders;
+
+    ColumnarRepeatedIterableFilterEvaluator(IScalarEvaluator evaluator, List<IColumnValuesReader> readers) {
+        super(evaluator);
+        this.readers = readers;
+        repeatedReaders = new ArrayList<>();
+        for (IColumnValuesReader reader : readers) {
+            if (reader.isRepeated()) {
+                repeatedReaders.add(reader);
+            }
+        }
+    }
+
+    @Override
+    public boolean evaluate() throws HyracksDataException {
+        boolean result = false;
+        while (!result && next()) {
+            // TODO handle nested repetition (x = unnest --> y = unnest --> select (x = 1 AND y = 3))
+            // TODO we need a way to 'rewind' y for each x
+            result = evaluateRepeated();
+            index++;
+        }
+        if (!result) {
+            // Last tuple does not satisfy the condition
+            index++;
+        }
+        return result;
+    }
+
+    private boolean evaluateRepeated() throws HyracksDataException {
+        boolean result = false;
+        boolean doNext;
+        do {
+            doNext = false;
+            result |= inspect();
+            for (int i = 0; i < repeatedReaders.size(); i++) {
+                IColumnValuesReader reader = repeatedReaders.get(i);
+                boolean repeatedValue = reader.isRepeatedValue() && !reader.isLastDelimiter();
+                doNext |= repeatedValue;
+                if (repeatedValue) {
+                    reader.next();
+                }
+            }
+        } while (doNext);
+        return result;
+    }
+
+    private boolean next() throws HyracksDataException {
+        for (int i = 0; i < readers.size(); i++) {
+            if (!readers.get(i).next()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    protected void skip(int count) throws HyracksDataException {
+        for (int i = 0; count > 0 && i < readers.size(); i++) {
+            readers.get(i).skip(count);
+        }
+    }
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnFilterNormalizedValueAccessor.java
similarity index 76%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
copy to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnFilterNormalizedValueAccessor.java
index 69abb37..99937cc 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnFilterNormalizedValueAccessor.java
@@ -16,12 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+package org.apache.asterix.column.filter.normalized;
 
 import org.apache.asterix.om.types.ATypeTag;
 
-public interface IColumnFilterValueAccessor {
+/**
+ * Creates a normalized value accessor
+ */
+public interface IColumnFilterNormalizedValueAccessor {
+    /**
+     * @return the normalized value
+     */
     long getNormalizedValue();
 
+    /**
+     * @return the type of the normalized value
+     */
     ATypeTag getTypeTag();
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnFilterNormalizedValueAccessorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnFilterNormalizedValueAccessorFactory.java
new file mode 100644
index 0000000..d27718e
--- /dev/null
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnFilterNormalizedValueAccessorFactory.java
@@ -0,0 +1,40 @@
+/*
+ * 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.column.filter.normalized;
+
+import java.io.Serializable;
+import java.util.PriorityQueue;
+
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.values.IColumnBatchWriter;
+import org.apache.asterix.column.values.IColumnValuesWriter;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+/**
+ * Creates an accessor for a normalized value reside in page0
+ *
+ * @see IColumnValuesWriter#getNormalizedMaxValue()
+ * @see IColumnValuesWriter#getNormalizedMinValue()
+ * @see IColumnBatchWriter#writeColumns(PriorityQueue)
+ */
+@FunctionalInterface
+public interface IColumnFilterNormalizedValueAccessorFactory extends Serializable {
+    IColumnFilterNormalizedValueAccessor create(FilterAccessorProvider filterAccessorProvider)
+            throws HyracksDataException;
+}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnNormalizedFilterEvaluatorFactory.java
similarity index 61%
copy from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
copy to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnNormalizedFilterEvaluatorFactory.java
index 62abb92..4832d64 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/IColumnNormalizedFilterEvaluatorFactory.java
@@ -16,13 +16,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter;
+package org.apache.asterix.column.filter.normalized;
 
 import java.io.Serializable;
+import java.util.PriorityQueue;
 
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.values.IColumnBatchWriter;
+import org.apache.asterix.column.values.IColumnValuesWriter;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
+/**
+ * A factory for creating an evaluator for normalized MIN/MAX values
+ *
+ * @see IColumnValuesWriter#getNormalizedMaxValue()
+ * @see IColumnValuesWriter#getNormalizedMinValue()
+ * @see IColumnBatchWriter#writeColumns(PriorityQueue)
+ */
 @FunctionalInterface
-public interface IColumnFilterEvaluatorFactory extends Serializable {
+public interface IColumnNormalizedFilterEvaluatorFactory extends Serializable {
     IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ColumnFilterValueAccessor.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ColumnFilterNormalizedValueAccessor.java
similarity index 80%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ColumnFilterValueAccessor.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ColumnFilterNormalizedValueAccessor.java
index 0aa2b31..da1d176 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ColumnFilterNormalizedValueAccessor.java
@@ -16,18 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.value;
+package org.apache.asterix.column.filter.normalized.accessor;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
 import org.apache.asterix.om.types.ATypeTag;
 
-public class ColumnFilterValueAccessor implements IColumnFilterValueAccessor {
+public class ColumnFilterNormalizedValueAccessor implements IColumnFilterNormalizedValueAccessor {
     private final int columnIndex;
     private final ATypeTag typeTag;
     private final boolean min;
     private long normalizedValue;
 
-    public ColumnFilterValueAccessor(int columnIndex, ATypeTag typeTag, boolean min) {
+    public ColumnFilterNormalizedValueAccessor(int columnIndex, ATypeTag typeTag, boolean min) {
         this.columnIndex = columnIndex;
         this.typeTag = typeTag;
         this.min = min;
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ColumnFilterValueAccessorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ColumnFilterNormalizedValueAccessorFactory.java
similarity index 70%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ColumnFilterValueAccessorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ColumnFilterNormalizedValueAccessorFactory.java
index fb02321..8e7c858 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ColumnFilterValueAccessorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ColumnFilterNormalizedValueAccessorFactory.java
@@ -16,29 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.value;
+package org.apache.asterix.column.filter.normalized.accessor;
 
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessorFactory;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessorFactory;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.visitor.PathStringBuilderForIATypeVisitor;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
-public class ColumnFilterValueAccessorFactory implements IColumnFilterValueAccessorFactory {
+public class ColumnFilterNormalizedValueAccessorFactory implements IColumnFilterNormalizedValueAccessorFactory {
     private static final long serialVersionUID = -6341611172763952841L;
     private final ARecordType path;
     private final boolean min;
 
-    public ColumnFilterValueAccessorFactory(ARecordType path, boolean min) {
+    public ColumnFilterNormalizedValueAccessorFactory(ARecordType path, boolean min) {
         this.path = path;
         this.min = min;
     }
 
     @Override
-    public IColumnFilterValueAccessor create(FilterAccessorProvider filterAccessorProvider)
+    public IColumnFilterNormalizedValueAccessor create(FilterAccessorProvider filterAccessorProvider)
             throws HyracksDataException {
-        return filterAccessorProvider.createColumnFilterValueAccessor(path, min);
+        return filterAccessorProvider.createColumnFilterNormalizedValueAccessor(path, min);
     }
 
     @Override
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ConstantColumnFilterValueAccessor.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ConstantColumnFilterNormalizedValueAccessor.java
similarity index 77%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ConstantColumnFilterValueAccessor.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ConstantColumnFilterNormalizedValueAccessor.java
index db9ef9c..cca3cab 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ConstantColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ConstantColumnFilterNormalizedValueAccessor.java
@@ -16,18 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.value;
+package org.apache.asterix.column.filter.normalized.accessor;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
 import org.apache.asterix.om.types.ATypeTag;
 
-public final class ConstantColumnFilterValueAccessor implements IColumnFilterValueAccessor {
+public final class ConstantColumnFilterNormalizedValueAccessor implements IColumnFilterNormalizedValueAccessor {
     private final long normalizedValue;
     private final ATypeTag typeTag;
 
     //TODO add UUID
 
-    public ConstantColumnFilterValueAccessor(long normalizedValue, ATypeTag typeTag) {
+    public ConstantColumnFilterNormalizedValueAccessor(long normalizedValue, ATypeTag typeTag) {
         this.normalizedValue = normalizedValue;
         this.typeTag = typeTag;
     }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ConstantColumnFilterValueAccessorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ConstantColumnFilterNormalizedValueAccessorFactory.java
similarity index 73%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ConstantColumnFilterValueAccessorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ConstantColumnFilterNormalizedValueAccessorFactory.java
index eeb903d..667a2c3 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/ConstantColumnFilterValueAccessorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/ConstantColumnFilterNormalizedValueAccessorFactory.java
@@ -16,11 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.value;
+package org.apache.asterix.column.filter.normalized.accessor;
 
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessorFactory;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessorFactory;
 import org.apache.asterix.om.base.ADouble;
 import org.apache.asterix.om.base.AInt64;
 import org.apache.asterix.om.base.AString;
@@ -28,19 +28,20 @@
 import org.apache.asterix.om.types.ATypeTag;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
-public class ConstantColumnFilterValueAccessorFactory implements IColumnFilterValueAccessorFactory {
+public class ConstantColumnFilterNormalizedValueAccessorFactory implements IColumnFilterNormalizedValueAccessorFactory {
     private static final long serialVersionUID = -4835407779342615453L;
     private final long normalizedValue;
     private final ATypeTag typeTag;
     private final String stringValue;
 
-    private ConstantColumnFilterValueAccessorFactory(String stringValue, long normalizedValue, ATypeTag typeTag) {
+    private ConstantColumnFilterNormalizedValueAccessorFactory(String stringValue, long normalizedValue,
+            ATypeTag typeTag) {
         this.stringValue = stringValue;
         this.normalizedValue = normalizedValue;
         this.typeTag = typeTag;
     }
 
-    public static ConstantColumnFilterValueAccessorFactory createFactory(IAObject value) {
+    public static ConstantColumnFilterNormalizedValueAccessorFactory createFactory(IAObject value) {
         String stringValue;
         long normalizedValue;
         ATypeTag typeTag = value.getType().getTypeTag();
@@ -63,13 +64,13 @@
                 return null;
         }
 
-        return new ConstantColumnFilterValueAccessorFactory(stringValue, normalizedValue, typeTag);
+        return new ConstantColumnFilterNormalizedValueAccessorFactory(stringValue, normalizedValue, typeTag);
     }
 
     @Override
-    public IColumnFilterValueAccessor create(FilterAccessorProvider filterAccessorProvider)
+    public IColumnFilterNormalizedValueAccessor create(FilterAccessorProvider filterAccessorProvider)
             throws HyracksDataException {
-        return new ConstantColumnFilterValueAccessor(normalizedValue, typeTag);
+        return new ConstantColumnFilterNormalizedValueAccessor(normalizedValue, typeTag);
     }
 
     @Override
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/NoOpColumnFilterValueAccessor.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/NoOpColumnFilterValueAccessor.java
similarity index 80%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/NoOpColumnFilterValueAccessor.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/NoOpColumnFilterValueAccessor.java
index c52eeda..acd3a44 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/value/NoOpColumnFilterValueAccessor.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/accessor/NoOpColumnFilterValueAccessor.java
@@ -16,13 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.value;
+package org.apache.asterix.column.filter.normalized.accessor;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
 import org.apache.asterix.om.types.ATypeTag;
 
-public class NoOpColumnFilterValueAccessor implements IColumnFilterValueAccessor {
-    public static final IColumnFilterValueAccessor INSTANCE = new NoOpColumnFilterValueAccessor();
+public class NoOpColumnFilterValueAccessor implements IColumnFilterNormalizedValueAccessor {
+    public static final IColumnFilterNormalizedValueAccessor INSTANCE = new NoOpColumnFilterValueAccessor();
 
     private NoOpColumnFilterValueAccessor() {
     }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/AbstractColumnFilterComparatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/AbstractColumnFilterComparatorFactory.java
similarity index 62%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/AbstractColumnFilterComparatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/AbstractColumnFilterComparatorFactory.java
index 8244876..cb63204 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/AbstractColumnFilterComparatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/AbstractColumnFilterComparatorFactory.java
@@ -16,26 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.compartor;
+package org.apache.asterix.column.filter.normalized.compartor;
 
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessorFactory;
-import org.apache.asterix.column.values.reader.filter.evaluator.FalseColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.evaluator.TrueColumnFilterEvaluator;
+import org.apache.asterix.column.filter.FalseColumnFilterEvaluator;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.TrueColumnFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.asterix.om.types.ATypeTag;
 import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
-abstract class AbstractColumnFilterComparatorFactory implements IColumnFilterEvaluatorFactory {
+abstract class AbstractColumnFilterComparatorFactory implements IColumnNormalizedFilterEvaluatorFactory {
     private static final long serialVersionUID = 4229059703449173694L;
-    private final IColumnFilterValueAccessorFactory left;
-    private final IColumnFilterValueAccessorFactory right;
+    private final IColumnFilterNormalizedValueAccessorFactory left;
+    private final IColumnFilterNormalizedValueAccessorFactory right;
 
-    AbstractColumnFilterComparatorFactory(IColumnFilterValueAccessorFactory left,
-            IColumnFilterValueAccessorFactory right) {
+    AbstractColumnFilterComparatorFactory(IColumnFilterNormalizedValueAccessorFactory left,
+            IColumnFilterNormalizedValueAccessorFactory right) {
         this.left = left;
         this.right = right;
     }
@@ -43,8 +43,8 @@
     @Override
     public final IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider)
             throws HyracksDataException {
-        IColumnFilterValueAccessor leftAccessor = left.create(filterAccessorProvider);
-        IColumnFilterValueAccessor rightAccessor = right.create(filterAccessorProvider);
+        IColumnFilterNormalizedValueAccessor leftAccessor = left.create(filterAccessorProvider);
+        IColumnFilterNormalizedValueAccessor rightAccessor = right.create(filterAccessorProvider);
 
         ATypeTag leftTypeTag = leftAccessor.getTypeTag();
         ATypeTag rightTypeTag = rightAccessor.getTypeTag();
@@ -61,8 +61,8 @@
         return rightTypeTag == ATypeTag.MISSING || leftTypeTag != rightTypeTag;
     }
 
-    protected abstract IColumnFilterEvaluator createComparator(IColumnFilterValueAccessor left,
-            IColumnFilterValueAccessor right);
+    protected abstract IColumnFilterEvaluator createComparator(IColumnFilterNormalizedValueAccessor left,
+            IColumnFilterNormalizedValueAccessor right);
 
     protected abstract String getOpt();
 
@@ -72,10 +72,10 @@
     }
 
     static abstract class AbstractComparator implements IColumnFilterEvaluator {
-        protected final IColumnFilterValueAccessor left;
-        protected final IColumnFilterValueAccessor right;
+        protected final IColumnFilterNormalizedValueAccessor left;
+        protected final IColumnFilterNormalizedValueAccessor right;
 
-        AbstractComparator(IColumnFilterValueAccessor left, IColumnFilterValueAccessor right) {
+        AbstractComparator(IColumnFilterNormalizedValueAccessor left, IColumnFilterNormalizedValueAccessor right) {
             this.left = left;
             this.right = right;
         }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/GEColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/GEColumnFilterEvaluatorFactory.java
similarity index 71%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/GEColumnFilterEvaluatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/GEColumnFilterEvaluatorFactory.java
index 81d58db..bd880e6 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/GEColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/GEColumnFilterEvaluatorFactory.java
@@ -16,23 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.compartor;
+package org.apache.asterix.column.filter.normalized.compartor;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessorFactory;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessorFactory;
 
 public class GEColumnFilterEvaluatorFactory extends AbstractColumnFilterComparatorFactory {
     private static final long serialVersionUID = 6879193736347174789L;
 
-    public GEColumnFilterEvaluatorFactory(IColumnFilterValueAccessorFactory left,
-            IColumnFilterValueAccessorFactory right) {
+    public GEColumnFilterEvaluatorFactory(IColumnFilterNormalizedValueAccessorFactory left,
+            IColumnFilterNormalizedValueAccessorFactory right) {
         super(left, right);
     }
 
     @Override
-    protected IColumnFilterEvaluator createComparator(IColumnFilterValueAccessor left,
-            IColumnFilterValueAccessor right) {
+    protected IColumnFilterEvaluator createComparator(IColumnFilterNormalizedValueAccessor left,
+            IColumnFilterNormalizedValueAccessor right) {
         return new AbstractComparator(left, right) {
             @Override
             public boolean evaluate() {
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/GTColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/GTColumnFilterEvaluatorFactory.java
similarity index 71%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/GTColumnFilterEvaluatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/GTColumnFilterEvaluatorFactory.java
index b24e18bf..de8eed0 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/GTColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/GTColumnFilterEvaluatorFactory.java
@@ -16,23 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.compartor;
+package org.apache.asterix.column.filter.normalized.compartor;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessorFactory;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessorFactory;
 
 public class GTColumnFilterEvaluatorFactory extends AbstractColumnFilterComparatorFactory {
     private static final long serialVersionUID = -3104103170926445020L;
 
-    public GTColumnFilterEvaluatorFactory(IColumnFilterValueAccessorFactory left,
-            IColumnFilterValueAccessorFactory right) {
+    public GTColumnFilterEvaluatorFactory(IColumnFilterNormalizedValueAccessorFactory left,
+            IColumnFilterNormalizedValueAccessorFactory right) {
         super(left, right);
     }
 
     @Override
-    protected IColumnFilterEvaluator createComparator(IColumnFilterValueAccessor left,
-            IColumnFilterValueAccessor right) {
+    protected IColumnFilterEvaluator createComparator(IColumnFilterNormalizedValueAccessor left,
+            IColumnFilterNormalizedValueAccessor right) {
         return new AbstractComparator(left, right) {
             @Override
             public boolean evaluate() {
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/LEColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/LEColumnFilterEvaluatorFactory.java
similarity index 71%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/LEColumnFilterEvaluatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/LEColumnFilterEvaluatorFactory.java
index f195d03..dd43c5a 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/LEColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/LEColumnFilterEvaluatorFactory.java
@@ -16,23 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.compartor;
+package org.apache.asterix.column.filter.normalized.compartor;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessorFactory;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessorFactory;
 
 public class LEColumnFilterEvaluatorFactory extends AbstractColumnFilterComparatorFactory {
     private static final long serialVersionUID = 1068661809768620550L;
 
-    public LEColumnFilterEvaluatorFactory(IColumnFilterValueAccessorFactory left,
-            IColumnFilterValueAccessorFactory right) {
+    public LEColumnFilterEvaluatorFactory(IColumnFilterNormalizedValueAccessorFactory left,
+            IColumnFilterNormalizedValueAccessorFactory right) {
         super(left, right);
     }
 
     @Override
-    protected IColumnFilterEvaluator createComparator(IColumnFilterValueAccessor left,
-            IColumnFilterValueAccessor right) {
+    protected IColumnFilterEvaluator createComparator(IColumnFilterNormalizedValueAccessor left,
+            IColumnFilterNormalizedValueAccessor right) {
         return new AbstractComparator(left, right) {
             @Override
             public boolean evaluate() {
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/LTColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/LTColumnFilterEvaluatorFactory.java
similarity index 71%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/LTColumnFilterEvaluatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/LTColumnFilterEvaluatorFactory.java
index 41c8018..7896ccf 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/compartor/LTColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/compartor/LTColumnFilterEvaluatorFactory.java
@@ -16,23 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.compartor;
+package org.apache.asterix.column.filter.normalized.compartor;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessorFactory;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessorFactory;
 
 public class LTColumnFilterEvaluatorFactory extends AbstractColumnFilterComparatorFactory {
     private static final long serialVersionUID = -4066709771630858677L;
 
-    public LTColumnFilterEvaluatorFactory(IColumnFilterValueAccessorFactory left,
-            IColumnFilterValueAccessorFactory right) {
+    public LTColumnFilterEvaluatorFactory(IColumnFilterNormalizedValueAccessorFactory left,
+            IColumnFilterNormalizedValueAccessorFactory right) {
         super(left, right);
     }
 
     @Override
-    protected IColumnFilterEvaluator createComparator(IColumnFilterValueAccessor left,
-            IColumnFilterValueAccessor right) {
+    protected IColumnFilterEvaluator createComparator(IColumnFilterNormalizedValueAccessor left,
+            IColumnFilterNormalizedValueAccessor right) {
         return new AbstractComparator(left, right) {
             @Override
             public boolean evaluate() {
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/ANDColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/ANDColumnFilterEvaluatorFactory.java
similarity index 78%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/ANDColumnFilterEvaluatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/ANDColumnFilterEvaluatorFactory.java
index 03ae64e..924cbd6 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/ANDColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/ANDColumnFilterEvaluatorFactory.java
@@ -16,17 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.evaluator;
+package org.apache.asterix.column.filter.normalized.evaluator;
 
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.FalseColumnFilterEvaluator;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.TrueColumnFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
 public class ANDColumnFilterEvaluatorFactory extends AbstractColumnFilterEvaluatorFactory {
     private static final long serialVersionUID = -7902069740719309586L;
 
-    public ANDColumnFilterEvaluatorFactory(IColumnFilterEvaluatorFactory left, IColumnFilterEvaluatorFactory right) {
+    public ANDColumnFilterEvaluatorFactory(IColumnNormalizedFilterEvaluatorFactory left,
+            IColumnNormalizedFilterEvaluatorFactory right) {
         super(left, right);
     }
 
@@ -53,9 +56,9 @@
     }
 
     private IColumnFilterEvaluator create(IColumnFilterEvaluator left, IColumnFilterEvaluator right) {
-        return new AbstractEvaluator(left, right) {
+        return new AbstractNormalizedEvaluator(left, right) {
             @Override
-            public boolean evaluate() {
+            public boolean evaluate() throws HyracksDataException {
                 return left.evaluate() && right.evaluate();
             }
         };
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/AbstractColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/AbstractColumnFilterEvaluatorFactory.java
similarity index 64%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/AbstractColumnFilterEvaluatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/AbstractColumnFilterEvaluatorFactory.java
index d1a53d1..66597db 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/AbstractColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/AbstractColumnFilterEvaluatorFactory.java
@@ -16,19 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.evaluator;
+package org.apache.asterix.column.filter.normalized.evaluator;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 
-public abstract class AbstractColumnFilterEvaluatorFactory implements IColumnFilterEvaluatorFactory {
+public abstract class AbstractColumnFilterEvaluatorFactory implements IColumnNormalizedFilterEvaluatorFactory {
     private static final long serialVersionUID = 1436531448052787426L;
 
-    protected final IColumnFilterEvaluatorFactory left;
-    protected final IColumnFilterEvaluatorFactory right;
+    protected final IColumnNormalizedFilterEvaluatorFactory left;
+    protected final IColumnNormalizedFilterEvaluatorFactory right;
 
-    public AbstractColumnFilterEvaluatorFactory(IColumnFilterEvaluatorFactory left,
-            IColumnFilterEvaluatorFactory right) {
+    public AbstractColumnFilterEvaluatorFactory(IColumnNormalizedFilterEvaluatorFactory left,
+            IColumnNormalizedFilterEvaluatorFactory right) {
         this.left = left;
         this.right = right;
     }
@@ -40,11 +40,11 @@
         return left.toString() + " " + getOp() + " " + right.toString();
     }
 
-    static abstract class AbstractEvaluator implements IColumnFilterEvaluator {
+    static abstract class AbstractNormalizedEvaluator implements IColumnFilterEvaluator {
         protected final IColumnFilterEvaluator left;
         protected final IColumnFilterEvaluator right;
 
-        AbstractEvaluator(IColumnFilterEvaluator left, IColumnFilterEvaluator right) {
+        AbstractNormalizedEvaluator(IColumnFilterEvaluator left, IColumnFilterEvaluator right) {
             this.left = left;
             this.right = right;
         }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/ORColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/ORColumnFilterEvaluatorFactory.java
similarity index 78%
rename from asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/ORColumnFilterEvaluatorFactory.java
rename to asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/ORColumnFilterEvaluatorFactory.java
index aedc9f4..046f05d 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/ORColumnFilterEvaluatorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/filter/normalized/evaluator/ORColumnFilterEvaluatorFactory.java
@@ -16,17 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.column.values.reader.filter.evaluator;
+package org.apache.asterix.column.filter.normalized.evaluator;
 
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.FalseColumnFilterEvaluator;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.TrueColumnFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
 public class ORColumnFilterEvaluatorFactory extends AbstractColumnFilterEvaluatorFactory {
     private static final long serialVersionUID = 9029706131191375500L;
 
-    public ORColumnFilterEvaluatorFactory(IColumnFilterEvaluatorFactory left, IColumnFilterEvaluatorFactory right) {
+    public ORColumnFilterEvaluatorFactory(IColumnNormalizedFilterEvaluatorFactory left,
+            IColumnNormalizedFilterEvaluatorFactory right) {
         super(left, right);
     }
 
@@ -54,9 +57,9 @@
     }
 
     private IColumnFilterEvaluator create(IColumnFilterEvaluator left, IColumnFilterEvaluator right) {
-        return new AbstractEvaluator(left, right) {
+        return new AbstractNormalizedEvaluator(left, right) {
             @Override
-            public boolean evaluate() {
+            public boolean evaluate() throws HyracksDataException {
                 return left.evaluate() || right.evaluate();
             }
         };
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/metadata/schema/visitor/PathExtractorVisitor.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/metadata/schema/visitor/PathExtractorVisitor.java
index 2bd2954..707f5b7 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/metadata/schema/visitor/PathExtractorVisitor.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/metadata/schema/visitor/PathExtractorVisitor.java
@@ -18,6 +18,11 @@
  */
 package org.apache.asterix.column.metadata.schema.visitor;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
 import org.apache.asterix.column.metadata.schema.AbstractSchemaNode;
 import org.apache.asterix.column.metadata.schema.ISchemaNodeVisitor;
 import org.apache.asterix.column.metadata.schema.ObjectSchemaNode;
@@ -25,11 +30,53 @@
 import org.apache.asterix.column.metadata.schema.collection.AbstractCollectionSchemaNode;
 import org.apache.asterix.column.metadata.schema.primitive.MissingFieldSchemaNode;
 import org.apache.asterix.column.metadata.schema.primitive.PrimitiveSchemaNode;
+import org.apache.asterix.column.values.IColumnValuesReader;
+import org.apache.asterix.column.values.IColumnValuesReaderFactory;
+import org.apache.asterix.om.types.ATypeTag;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
 import it.unimi.dsi.fastutil.ints.IntList;
 
 public class PathExtractorVisitor implements ISchemaNodeVisitor<AbstractSchemaNode, Void> {
+    private final IColumnValuesReaderFactory readerFactory;
+    private final IntList delimiters;
+    private final Int2ObjectMap<IColumnValuesReader> cachedReaders;
+    private int level;
+
+    public PathExtractorVisitor(IColumnValuesReaderFactory readerFactory) {
+        this.readerFactory = readerFactory;
+        cachedReaders = new Int2ObjectOpenHashMap<>();
+        delimiters = new IntArrayList();
+    }
+
+    public List<IColumnValuesReader> getOrCreateReaders(ObjectSchemaNode path, List<IColumnValuesReader> readers)
+            throws HyracksDataException {
+        level = 0;
+        delimiters.clear();
+        AbstractSchemaNode node = path.accept(this, null);
+        ATypeTag typeTag = node.getTypeTag();
+        if (typeTag == ATypeTag.MISSING) {
+            return Collections.emptyList();
+        } else if (typeTag == ATypeTag.UNION) {
+            UnionSchemaNode unionNode = (UnionSchemaNode) node;
+            Collection<AbstractSchemaNode> children = unionNode.getChildren().values();
+            List<IColumnValuesReader> unionReaders = new ArrayList<>();
+            for (AbstractSchemaNode child : children) {
+                if (child.isNested()) {
+                    // ignore nested nodes as we only compare flat types
+                    continue;
+                }
+                IColumnValuesReader reader = getOrCreate(child, readers);
+                unionReaders.add(reader);
+            }
+            return unionReaders;
+        }
+        return Collections.singletonList(getOrCreate(node, readers));
+    }
+
     @Override
     public AbstractSchemaNode visit(ObjectSchemaNode objectNode, Void arg) throws HyracksDataException {
         IntList fieldNameIndexes = objectNode.getChildrenFieldNameIndexes();
@@ -37,6 +84,7 @@
         if (fieldNameIndex < 0) {
             return MissingFieldSchemaNode.INSTANCE;
         }
+        level++;
         return objectNode.getChild(fieldNameIndex).accept(this, null);
     }
 
@@ -46,16 +94,23 @@
         if (itemNode == null) {
             return MissingFieldSchemaNode.INSTANCE;
         }
+        delimiters.add(level - 1);
+        level++;
         return collectionNode.getItemNode().accept(this, null);
     }
 
     @Override
     public AbstractSchemaNode visit(UnionSchemaNode unionNode, Void arg) throws HyracksDataException {
-        for (AbstractSchemaNode node : unionNode.getChildren().values()) {
-            // Using 'for-loop' is the only get the child out of a collection
-            return node.accept(this, null);
+        Collection<AbstractSchemaNode> children = unionNode.getChildren().values();
+        if (children.size() == 1) {
+            // A specific type was requested. Get the requested type from union
+            for (AbstractSchemaNode node : children) {
+                return node.accept(this, null);
+            }
         }
-        return MissingFieldSchemaNode.INSTANCE;
+
+        // Multiple types were requested, return the union
+        return unionNode;
     }
 
     @Override
@@ -63,4 +118,24 @@
         //Missing column index is -1
         return primitiveNode;
     }
+
+    private IColumnValuesReader getOrCreate(AbstractSchemaNode node, List<IColumnValuesReader> readers) {
+        PrimitiveSchemaNode primitiveNode = (PrimitiveSchemaNode) node;
+        int columnIndex = primitiveNode.getColumnIndex();
+        return cachedReaders.computeIfAbsent(columnIndex, k -> createReader(primitiveNode, readers));
+    }
+
+    private IColumnValuesReader createReader(PrimitiveSchemaNode primitiveNode, List<IColumnValuesReader> readers) {
+        IColumnValuesReader reader;
+        if (delimiters.isEmpty()) {
+            reader = readerFactory.createValueReader(primitiveNode.getTypeTag(), primitiveNode.getColumnIndex(), level,
+                    primitiveNode.isPrimaryKey());
+        } else {
+            // array
+            reader = readerFactory.createValueReader(primitiveNode.getTypeTag(), primitiveNode.getColumnIndex(), level,
+                    delimiters.toIntArray());
+        }
+        readers.add(reader);
+        return reader;
+    }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/metadata/schema/visitor/SchemaClipperVisitor.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/metadata/schema/visitor/SchemaClipperVisitor.java
index 351dcdf..5db01f2 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/metadata/schema/visitor/SchemaClipperVisitor.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/metadata/schema/visitor/SchemaClipperVisitor.java
@@ -43,12 +43,18 @@
     private final FieldNamesDictionary fieldNamesDictionary;
     private final IWarningCollector warningCollector;
     private final Map<String, FunctionCallInformation> functionCallInfoMap;
+    private boolean ignoreFlatType;
 
     public SchemaClipperVisitor(FieldNamesDictionary fieldNamesDictionary,
             Map<String, FunctionCallInformation> functionCallInfoMap, IWarningCollector warningCollector) {
         this.fieldNamesDictionary = fieldNamesDictionary;
         this.functionCallInfoMap = functionCallInfoMap;
         this.warningCollector = warningCollector;
+        ignoreFlatType = false;
+    }
+
+    public void setIgnoreFlatType(boolean ignoreFlatType) {
+        this.ignoreFlatType = ignoreFlatType;
     }
 
     @Override
@@ -100,7 +106,7 @@
 
     @Override
     public AbstractSchemaNode visitFlat(IAType flatType, AbstractSchemaNode arg) {
-        if (flatType.getTypeTag() == ATypeTag.ANY) {
+        if (ignoreFlatType || flatType.getTypeTag() == ATypeTag.ANY) {
             return arg;
         } else if (isNotCompatible(flatType, arg)) {
             return getNonCompatibleNumericNodeIfAny(flatType, arg);
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/merge/MergeColumnReadMetadata.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/merge/MergeColumnReadMetadata.java
index 11f3059..a1eff69 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/merge/MergeColumnReadMetadata.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/merge/MergeColumnReadMetadata.java
@@ -89,6 +89,16 @@
     }
 
     @Override
+    public int getFilteredColumnIndex(int ordinal) {
+        return -1;
+    }
+
+    @Override
+    public int getNumberOfFilteredColumns() {
+        return 0;
+    }
+
+    @Override
     public AbstractColumnTupleReader createTupleReader() {
         return new MergeColumnTupleReader(this);
     }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/create/PrimaryScanColumnTupleProjector.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/create/PrimaryScanColumnTupleProjector.java
index b993582..c86318e 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/create/PrimaryScanColumnTupleProjector.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/create/PrimaryScanColumnTupleProjector.java
@@ -22,8 +22,8 @@
 import java.io.IOException;
 import java.util.Collections;
 
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.column.operation.query.QueryColumnTupleProjector;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.common.exceptions.NoOpWarningCollector;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -39,7 +39,8 @@
     public PrimaryScanColumnTupleProjector(ARecordType datasetType, int numberOfPrimaryKeys,
             ARecordType requestedType) {
         projector = new QueryColumnTupleProjector(datasetType, numberOfPrimaryKeys, requestedType,
-                Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE);
+                Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE,
+                NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE, null);
     }
 
     @Override
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/create/PrimaryScanColumnTupleWithMetaProjector.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/create/PrimaryScanColumnTupleWithMetaProjector.java
index 0933049..e7fb31f 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/create/PrimaryScanColumnTupleWithMetaProjector.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/create/PrimaryScanColumnTupleWithMetaProjector.java
@@ -22,8 +22,8 @@
 import java.io.IOException;
 import java.util.Collections;
 
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.column.operation.query.QueryColumnWithMetaTupleProjector;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.common.exceptions.NoOpWarningCollector;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -40,7 +40,7 @@
             int numberOfPrimaryKeys, ARecordType requestedType) {
         projector = new QueryColumnWithMetaTupleProjector(datasetType, metaType, numberOfPrimaryKeys, requestedType,
                 Collections.emptyMap(), metaType, Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE,
-                NoOpWarningCollector.INSTANCE);
+                NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE, null);
     }
 
     @Override
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/upsert/UpsertPreviousColumnTupleProjector.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/upsert/UpsertPreviousColumnTupleProjector.java
index b245785..34b0291 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/upsert/UpsertPreviousColumnTupleProjector.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/upsert/UpsertPreviousColumnTupleProjector.java
@@ -22,8 +22,8 @@
 import java.io.IOException;
 import java.util.Collections;
 
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.column.operation.query.QueryColumnTupleProjector;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.common.exceptions.NoOpWarningCollector;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -41,7 +41,8 @@
             ARecordType requestedType) {
         builder = new ArrayTupleBuilder(numberOfPrimaryKeys + 1);
         projector = new QueryColumnTupleProjector(datasetType, numberOfPrimaryKeys, requestedType,
-                Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE);
+                Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE,
+                NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE, null);
     }
 
     @Override
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/upsert/UpsertPreviousColumnTupleWithMetaProjector.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/upsert/UpsertPreviousColumnTupleWithMetaProjector.java
index d6285dc..2c760bf 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/upsert/UpsertPreviousColumnTupleWithMetaProjector.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/lsm/secondary/upsert/UpsertPreviousColumnTupleWithMetaProjector.java
@@ -22,8 +22,8 @@
 import java.io.IOException;
 import java.util.Collections;
 
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.column.operation.query.QueryColumnWithMetaTupleProjector;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.common.exceptions.NoOpWarningCollector;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -43,7 +43,7 @@
         builder = new ArrayTupleBuilder(numberOfPrimaryKeys + 2);
         projector = new QueryColumnWithMetaTupleProjector(datasetType, metaType, numberOfPrimaryKeys, requestedType,
                 Collections.emptyMap(), metaType, Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE,
-                NoOpWarningCollector.INSTANCE);
+                NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE, null);
     }
 
     @Override
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java
index e86f063..23a7856 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java
@@ -92,10 +92,15 @@
         return assemblers.length;
     }
 
-    public void skip(int count) throws HyracksDataException {
+    public int skip(int count) throws HyracksDataException {
         tupleIndex += count;
         for (int i = 0; i < assemblers.length; i++) {
             assemblers[i].skip(count);
         }
+        return tupleIndex;
+    }
+
+    public void setAt(int index) throws HyracksDataException {
+        skip(index - tupleIndex);
     }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java
index 54ac60c..77bf945 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java
@@ -22,31 +22,39 @@
 import java.io.DataInput;
 import java.io.DataInputStream;
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.asterix.column.assembler.value.IValueGetterFactory;
+import org.apache.asterix.column.filter.FalseColumnFilterEvaluator;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.TrueColumnFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.asterix.column.metadata.AbstractColumnImmutableReadMetadata;
 import org.apache.asterix.column.metadata.FieldNamesDictionary;
 import org.apache.asterix.column.metadata.schema.AbstractSchemaNode;
 import org.apache.asterix.column.metadata.schema.ObjectSchemaNode;
 import org.apache.asterix.column.metadata.schema.visitor.SchemaClipperVisitor;
 import org.apache.asterix.column.util.SchemaStringBuilderVisitor;
+import org.apache.asterix.column.values.IColumnValuesReader;
 import org.apache.asterix.column.values.IColumnValuesReaderFactory;
 import org.apache.asterix.column.values.reader.PrimitiveColumnValuesReader;
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.evaluator.FalseColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.evaluator.TrueColumnFilterEvaluator;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.runtime.projection.DataProjectionFiltrationInfo;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.evaluators.EvaluatorContext;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 import org.apache.hyracks.data.std.api.IValueReference;
 import org.apache.hyracks.data.std.primitive.IntegerPointable;
+import org.apache.hyracks.dataflow.common.utils.TaskUtil;
 import org.apache.hyracks.storage.am.lsm.btree.column.api.AbstractColumnTupleReader;
 import org.apache.hyracks.util.LogRedactionUtil;
 import org.apache.logging.log4j.LogManager;
@@ -59,22 +67,28 @@
     private static final Logger LOGGER = LogManager.getLogger();
     private final FieldNamesDictionary fieldNamesDictionary;
     private final PrimitiveColumnValuesReader[] primaryKeyReaders;
-    private final IColumnFilterEvaluator filterEvaluator;
-    private final List<IColumnFilterValueAccessor> filterValueAccessors;
+    private final IColumnFilterEvaluator normalizedFilterEvaluator;
+    private final List<IColumnFilterNormalizedValueAccessor> filterValueAccessors;
+    private final IColumnIterableFilterEvaluator columnFilterEvaluator;
+    private final List<IColumnValuesReader> filterColumnReaders;
 
     protected final ColumnAssembler assembler;
 
     protected QueryColumnMetadata(ARecordType datasetType, ARecordType metaType,
             PrimitiveColumnValuesReader[] primaryKeyReaders, IValueReference serializedMetadata,
             FieldNamesDictionary fieldNamesDictionary, ObjectSchemaNode root, IColumnValuesReaderFactory readerFactory,
-            IValueGetterFactory valueGetterFactory, IColumnFilterEvaluator filterEvaluator,
-            List<IColumnFilterValueAccessor> filterValueAccessors) throws HyracksDataException {
+            IValueGetterFactory valueGetterFactory, IColumnFilterEvaluator normalizedFilterEvaluator,
+            List<IColumnFilterNormalizedValueAccessor> filterValueAccessors,
+            IColumnIterableFilterEvaluator columnFilterEvaluator, List<IColumnValuesReader> filterColumnReaders)
+            throws HyracksDataException {
         super(datasetType, metaType, primaryKeyReaders.length, serializedMetadata, -1);
         this.fieldNamesDictionary = fieldNamesDictionary;
         this.assembler = new ColumnAssembler(root, datasetType, this, readerFactory, valueGetterFactory);
         this.primaryKeyReaders = primaryKeyReaders;
-        this.filterEvaluator = filterEvaluator;
+        this.normalizedFilterEvaluator = normalizedFilterEvaluator;
         this.filterValueAccessors = filterValueAccessors;
+        this.columnFilterEvaluator = columnFilterEvaluator;
+        this.filterColumnReaders = filterColumnReaders;
     }
 
     public final ColumnAssembler getAssembler() {
@@ -89,14 +103,22 @@
         return primaryKeyReaders;
     }
 
-    public IColumnFilterEvaluator getFilterEvaluator() {
-        return filterEvaluator;
+    public final IColumnFilterEvaluator getNormalizedFilterEvaluator() {
+        return normalizedFilterEvaluator;
     }
 
-    public List<IColumnFilterValueAccessor> getFilterValueAccessors() {
+    public final List<IColumnFilterNormalizedValueAccessor> getFilterValueAccessors() {
         return filterValueAccessors;
     }
 
+    public final IColumnIterableFilterEvaluator getColumnFilterEvaluator() {
+        return columnFilterEvaluator;
+    }
+
+    public final List<IColumnValuesReader> getFilterColumnReaders() {
+        return filterColumnReaders;
+    }
+
     /* *****************************************************
      * Non-final methods
      * *****************************************************
@@ -112,11 +134,21 @@
     }
 
     @Override
+    public int getFilteredColumnIndex(int ordinal) {
+        return filterColumnReaders.get(ordinal).getColumnIndex();
+    }
+
+    @Override
     public int getNumberOfProjectedColumns() {
         return assembler.getNumberOfColumns();
     }
 
     @Override
+    public int getNumberOfFilteredColumns() {
+        return filterColumnReaders.size();
+    }
+
+    @Override
     public int getNumberOfColumns() {
         return assembler.getNumberOfColumns();
     }
@@ -141,8 +173,9 @@
             IValueReference serializedMetadata, IColumnValuesReaderFactory readerFactory,
             IValueGetterFactory valueGetterFactory, ARecordType requestedType,
             Map<String, FunctionCallInformation> functionCallInfoMap,
-            IColumnFilterEvaluatorFactory filterEvaluatorFactory, IWarningCollector warningCollector)
-            throws IOException {
+            IColumnNormalizedFilterEvaluatorFactory normalizedEvaluatorFactory,
+            IColumnIterableFilterEvaluatorFactory columnFilterEvaluatorFactory, IWarningCollector warningCollector,
+            IHyracksTaskContext context) throws IOException {
         byte[] bytes = serializedMetadata.getByteArray();
         int offset = serializedMetadata.getStartOffset();
         int length = serializedMetadata.getLength();
@@ -166,16 +199,34 @@
                 new SchemaClipperVisitor(fieldNamesDictionary, functionCallInfoMap, warningCollector);
         ObjectSchemaNode clippedRoot = clip(requestedType, root, clipperVisitor);
 
-        FilterAccessorProvider filterAccessorProvider = new FilterAccessorProvider(root, clipperVisitor);
-        IColumnFilterEvaluator filterEvaluator = filterEvaluatorFactory.create(filterAccessorProvider);
-        List<IColumnFilterValueAccessor> filterValueAccessors = filterAccessorProvider.getFilterAccessors();
+        IColumnFilterEvaluator normalizedFilterEvaluator = TrueColumnFilterEvaluator.INSTANCE;
+        IColumnIterableFilterEvaluator columnFilterEvaluator = TrueColumnFilterEvaluator.INSTANCE;
+        List<IColumnValuesReader> filterColumnReaders = Collections.emptyList();
+        List<IColumnFilterNormalizedValueAccessor> filterValueAccessors = Collections.emptyList();
+        if (context != null) {
+            FilterAccessorProvider filterAccessorProvider =
+                    new FilterAccessorProvider(root, clipperVisitor, readerFactory, valueGetterFactory);
+            TaskUtil.put(FilterAccessorProvider.FILTER_ACCESSOR_PROVIDER_KEY, filterAccessorProvider, context);
+            // Min/Max filters in page0
+            normalizedFilterEvaluator = normalizedEvaluatorFactory.create(filterAccessorProvider);
+            filterValueAccessors = filterAccessorProvider.getFilterAccessors();
 
+            // Filter columns (columns appeared in WHERE clause)
+            IEvaluatorContext evaluatorContext = new EvaluatorContext(context);
+            // ignore atomic (or flat) types information
+            clipperVisitor.setIgnoreFlatType(true);
+            filterAccessorProvider.reset();
+            columnFilterEvaluator = columnFilterEvaluatorFactory.create(filterAccessorProvider, evaluatorContext);
+            filterColumnReaders = filterAccessorProvider.getFilterColumnReaders();
+        }
+
+        // Primary key readers
         PrimitiveColumnValuesReader[] primaryKeyReaders =
                 createPrimaryKeyReaders(input, readerFactory, numberOfPrimaryKeys);
 
-        if (LOGGER.isInfoEnabled() && filterEvaluator != TrueColumnFilterEvaluator.INSTANCE) {
-            String filterString = filterEvaluator == FalseColumnFilterEvaluator.INSTANCE ? "SKIP_ALL"
-                    : LogRedactionUtil.userData(filterEvaluatorFactory.toString());
+        if (LOGGER.isInfoEnabled() && normalizedFilterEvaluator != TrueColumnFilterEvaluator.INSTANCE) {
+            String filterString = normalizedFilterEvaluator == FalseColumnFilterEvaluator.INSTANCE ? "SKIP_ALL"
+                    : LogRedactionUtil.userData(normalizedEvaluatorFactory.toString());
             LOGGER.info("Filter: {}", filterString);
         }
 
@@ -183,7 +234,8 @@
         logSchema(clippedRoot, SchemaStringBuilderVisitor.RECORD_SCHEMA, fieldNamesDictionary);
 
         return new QueryColumnMetadata(datasetType, null, primaryKeyReaders, serializedMetadata, fieldNamesDictionary,
-                clippedRoot, readerFactory, valueGetterFactory, filterEvaluator, filterValueAccessors);
+                clippedRoot, readerFactory, valueGetterFactory, normalizedFilterEvaluator, filterValueAccessors,
+                columnFilterEvaluator, filterColumnReaders);
     }
 
     protected static ObjectSchemaNode clip(ARecordType requestedType, ObjectSchemaNode root,
@@ -211,10 +263,10 @@
 
     protected static void logSchema(ObjectSchemaNode root, String schemaSource,
             FieldNamesDictionary fieldNamesDictionary) throws HyracksDataException {
-        if (LOGGER.isDebugEnabled()) {
+        if (LOGGER.isInfoEnabled()) {
             SchemaStringBuilderVisitor schemaBuilder = new SchemaStringBuilderVisitor(fieldNamesDictionary);
             String schema = LogRedactionUtil.userData(schemaBuilder.build(root));
-            LOGGER.debug("Queried {} schema: \n {}", schemaSource, schema);
+            LOGGER.info("Queried {} schema: \n {}", schemaSource, schema);
         }
     }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnTupleProjector.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnTupleProjector.java
index 08efc2b..e2a69d6 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnTupleProjector.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnTupleProjector.java
@@ -22,13 +22,16 @@
 import java.io.IOException;
 import java.util.Map;
 
+import org.apache.asterix.column.assembler.value.MissingValueGetter;
 import org.apache.asterix.column.assembler.value.ValueGetterFactory;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.asterix.column.tuple.AssembledTupleReference;
 import org.apache.asterix.column.tuple.QueryColumnTupleReference;
 import org.apache.asterix.column.values.reader.ColumnValueReaderFactory;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 import org.apache.hyracks.data.std.api.IValueReference;
@@ -43,18 +46,24 @@
     protected final int numberOfPrimaryKeys;
     protected final Map<String, FunctionCallInformation> functionCallInfoMap;
     protected final IWarningCollector warningCollector;
-    protected final IColumnFilterEvaluatorFactory filterEvaluator;
+    protected final IHyracksTaskContext context;
+    protected final IColumnNormalizedFilterEvaluatorFactory normalizedFilterEvaluatorFactory;
+    protected final IColumnIterableFilterEvaluatorFactory columnFilterEvaluatorFactory;
     private final AssembledTupleReference assembledTupleReference;
 
     public QueryColumnTupleProjector(ARecordType datasetType, int numberOfPrimaryKeys, ARecordType requestedType,
-            Map<String, FunctionCallInformation> functionCallInfoMap, IColumnFilterEvaluatorFactory filterEvaluator,
-            IWarningCollector warningCollector) {
+            Map<String, FunctionCallInformation> functionCallInfoMap,
+            IColumnNormalizedFilterEvaluatorFactory normalizedFilterEvaluatorFactory,
+            IColumnIterableFilterEvaluatorFactory columnFilterEvaluatorFactory, IWarningCollector warningCollector,
+            IHyracksTaskContext context) {
         this.datasetType = datasetType;
         this.numberOfPrimaryKeys = numberOfPrimaryKeys;
         this.requestedType = requestedType;
         this.functionCallInfoMap = functionCallInfoMap;
-        this.filterEvaluator = filterEvaluator;
+        this.normalizedFilterEvaluatorFactory = normalizedFilterEvaluatorFactory;
+        this.columnFilterEvaluatorFactory = columnFilterEvaluatorFactory;
         this.warningCollector = warningCollector;
+        this.context = context;
         assembledTupleReference = new AssembledTupleReference(getNumberOfTupleFields());
     }
 
@@ -63,7 +72,7 @@
         try {
             return QueryColumnMetadata.create(datasetType, numberOfPrimaryKeys, serializedMetadata,
                     new ColumnValueReaderFactory(), ValueGetterFactory.INSTANCE, requestedType, functionCallInfoMap,
-                    filterEvaluator, warningCollector);
+                    normalizedFilterEvaluatorFactory, columnFilterEvaluatorFactory, warningCollector, context);
         } catch (IOException e) {
             throw HyracksDataException.create(e);
         }
@@ -78,6 +87,9 @@
         }
         if (isColumnar(tuple)) {
             IValueReference assembledRecord = getAssembledValue(tuple);
+            if (assembledRecord == MissingValueGetter.MISSING) {
+                return null;
+            }
             dos.write(assembledRecord.getByteArray(), assembledRecord.getStartOffset(), assembledRecord.getLength());
         } else {
             dos.write(tuple.getFieldData(numberOfPrimaryKeys), tuple.getFieldStart(numberOfPrimaryKeys),
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnTupleProjectorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnTupleProjectorFactory.java
index 0acad67..f63df95 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnTupleProjectorFactory.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnTupleProjectorFactory.java
@@ -20,7 +20,8 @@
 
 import java.util.Map;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
 import org.apache.hyracks.api.context.IHyracksTaskContext;
@@ -38,12 +39,14 @@
     private final ARecordType requestedMetaType;
     private final Map<String, FunctionCallInformation> functionCallInfo;
     private final Map<String, FunctionCallInformation> metaFunctionCallInfo;
-    private final IColumnFilterEvaluatorFactory filterEvaluator;
+    private final IColumnNormalizedFilterEvaluatorFactory normalizedFilterEvaluatorFactory;
+    private final IColumnIterableFilterEvaluatorFactory columnFilterEvaluatorFactory;
 
     public QueryColumnTupleProjectorFactory(ARecordType datasetType, ARecordType metaType, int numberOfPrimaryKeys,
             ARecordType requestedType, Map<String, FunctionCallInformation> functionCallInfo,
             ARecordType requestedMetaType, Map<String, FunctionCallInformation> metaFunctionCallInfo,
-            IColumnFilterEvaluatorFactory filterEvaluator) {
+            IColumnNormalizedFilterEvaluatorFactory normalizedFilterEvaluatorFactory,
+            IColumnIterableFilterEvaluatorFactory columnFilterEvaluatorFactory) {
         this.datasetType = datasetType;
         this.metaType = metaType;
         this.numberOfPrimaryKeys = numberOfPrimaryKeys;
@@ -51,7 +54,8 @@
         this.functionCallInfo = functionCallInfo;
         this.requestedMetaType = requestedMetaType;
         this.metaFunctionCallInfo = metaFunctionCallInfo;
-        this.filterEvaluator = filterEvaluator;
+        this.normalizedFilterEvaluatorFactory = normalizedFilterEvaluatorFactory;
+        this.columnFilterEvaluatorFactory = columnFilterEvaluatorFactory;
     }
 
     @Override
@@ -60,10 +64,11 @@
         if (requestedMetaType == null) {
             // The dataset does not contain a meta part
             return new QueryColumnTupleProjector(datasetType, numberOfPrimaryKeys, requestedType, functionCallInfo,
-                    filterEvaluator, warningCollector);
+                    normalizedFilterEvaluatorFactory, columnFilterEvaluatorFactory, warningCollector, context);
         }
         // The dataset has a meta part
         return new QueryColumnWithMetaTupleProjector(datasetType, metaType, numberOfPrimaryKeys, requestedType,
-                functionCallInfo, requestedMetaType, metaFunctionCallInfo, filterEvaluator, warningCollector);
+                functionCallInfo, requestedMetaType, metaFunctionCallInfo, normalizedFilterEvaluatorFactory,
+                columnFilterEvaluatorFactory, warningCollector, context);
     }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnWithMetaMetadata.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnWithMetaMetadata.java
index 2896231..e63358b 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnWithMetaMetadata.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnWithMetaMetadata.java
@@ -22,27 +22,36 @@
 import java.io.DataInput;
 import java.io.DataInputStream;
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.asterix.column.assembler.value.IValueGetterFactory;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.TrueColumnFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.asterix.column.metadata.FieldNamesDictionary;
 import org.apache.asterix.column.metadata.schema.AbstractSchemaNode;
 import org.apache.asterix.column.metadata.schema.ObjectSchemaNode;
 import org.apache.asterix.column.metadata.schema.visitor.SchemaClipperVisitor;
 import org.apache.asterix.column.util.SchemaStringBuilderVisitor;
+import org.apache.asterix.column.values.IColumnValuesReader;
 import org.apache.asterix.column.values.IColumnValuesReaderFactory;
 import org.apache.asterix.column.values.reader.PrimitiveColumnValuesReader;
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.evaluators.EvaluatorContext;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 import org.apache.hyracks.data.std.api.IValueReference;
 import org.apache.hyracks.data.std.primitive.IntegerPointable;
+import org.apache.hyracks.dataflow.common.utils.TaskUtil;
 import org.apache.hyracks.storage.am.lsm.btree.column.api.AbstractColumnTupleReader;
 
 /**
@@ -55,10 +64,11 @@
             PrimitiveColumnValuesReader[] primaryKeyReaders, IValueReference serializedMetadata,
             FieldNamesDictionary fieldNamesDictionary, ObjectSchemaNode root, ObjectSchemaNode metaRoot,
             IColumnValuesReaderFactory readerFactory, IValueGetterFactory valueGetterFactory,
-            IColumnFilterEvaluator filterEvaluator, List<IColumnFilterValueAccessor> filterValueAccessors)
+            IColumnFilterEvaluator filterEvaluator, List<IColumnFilterNormalizedValueAccessor> filterValueAccessors,
+            IColumnIterableFilterEvaluator columnFilterEvaluator, List<IColumnValuesReader> filterColumnReaders)
             throws HyracksDataException {
         super(datasetType, metaType, primaryKeyReaders, serializedMetadata, fieldNamesDictionary, root, readerFactory,
-                valueGetterFactory, filterEvaluator, filterValueAccessors);
+                valueGetterFactory, filterEvaluator, filterValueAccessors, columnFilterEvaluator, filterColumnReaders);
         metaAssembler = new ColumnAssembler(metaRoot, metaType, this, readerFactory, valueGetterFactory);
     }
 
@@ -112,8 +122,9 @@
             IValueGetterFactory valueGetterFactory, ARecordType requestedType,
             Map<String, FunctionCallInformation> functionCallInfo, ARecordType metaRequestedType,
             Map<String, FunctionCallInformation> metaFunctionCallInfo,
-            IColumnFilterEvaluatorFactory filterEvaluatorFactory, IWarningCollector warningCollector)
-            throws IOException {
+            IColumnNormalizedFilterEvaluatorFactory normalizedEvaluatorFactory,
+            IColumnIterableFilterEvaluatorFactory columnFilterEvaluatorFactory, IWarningCollector warningCollector,
+            IHyracksTaskContext context) throws IOException {
         byte[] bytes = serializedMetadata.getByteArray();
         int offset = serializedMetadata.getStartOffset();
         int length = serializedMetadata.getLength();
@@ -138,10 +149,28 @@
                 new SchemaClipperVisitor(fieldNamesDictionary, metaFunctionCallInfo, warningCollector);
         ObjectSchemaNode metaClippedRoot = clip(metaRequestedType, metaRoot, metaClipperVisitor);
 
-        FilterAccessorProvider filterAccessorProvider = new FilterAccessorProvider(root, metaRoot, clipperVisitor);
-        IColumnFilterEvaluator filterEvaluator = filterEvaluatorFactory.create(filterAccessorProvider);
-        List<IColumnFilterValueAccessor> filterValueAccessors = filterAccessorProvider.getFilterAccessors();
+        IColumnFilterEvaluator normalizedFilterEvaluator = TrueColumnFilterEvaluator.INSTANCE;
+        IColumnIterableFilterEvaluator columnFilterEvaluator = TrueColumnFilterEvaluator.INSTANCE;
+        List<IColumnValuesReader> filterColumnReaders = Collections.emptyList();
+        List<IColumnFilterNormalizedValueAccessor> filterValueAccessors = Collections.emptyList();
+        if (context != null) {
+            FilterAccessorProvider filterAccessorProvider =
+                    new FilterAccessorProvider(root, clipperVisitor, readerFactory, valueGetterFactory);
+            TaskUtil.put(FilterAccessorProvider.FILTER_ACCESSOR_PROVIDER_KEY, filterAccessorProvider, context);
+            // Min/Max filters in page0
+            normalizedFilterEvaluator = normalizedEvaluatorFactory.create(filterAccessorProvider);
+            filterValueAccessors = filterAccessorProvider.getFilterAccessors();
 
+            // Filter columns (columns appeared in WHERE clause)
+            IEvaluatorContext evaluatorContext = new EvaluatorContext(context);
+            // ignore atomic (or flat) types information
+            clipperVisitor.setIgnoreFlatType(true);
+            filterAccessorProvider.reset();
+            columnFilterEvaluator = columnFilterEvaluatorFactory.create(filterAccessorProvider, evaluatorContext);
+            filterColumnReaders = filterAccessorProvider.getFilterColumnReaders();
+        }
+
+        // Primary key readers
         PrimitiveColumnValuesReader[] primaryKeyReaders =
                 createPrimaryKeyReaders(input, readerFactory, numberOfPrimaryKeys);
 
@@ -151,7 +180,7 @@
         logSchema(metaClippedRoot, SchemaStringBuilderVisitor.META_RECORD_SCHEMA, fieldNamesDictionary);
 
         return new QueryColumnWithMetaMetadata(datasetType, metaType, primaryKeyReaders, serializedMetadata,
-                fieldNamesDictionary, clippedRoot, metaClippedRoot, readerFactory, valueGetterFactory, filterEvaluator,
-                filterValueAccessors);
+                fieldNamesDictionary, clippedRoot, metaClippedRoot, readerFactory, valueGetterFactory,
+                normalizedFilterEvaluator, filterValueAccessors, columnFilterEvaluator, filterColumnReaders);
     }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnWithMetaTupleProjector.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnWithMetaTupleProjector.java
index b3deb46..838973f 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnWithMetaTupleProjector.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnWithMetaTupleProjector.java
@@ -23,11 +23,13 @@
 import java.util.Map;
 
 import org.apache.asterix.column.assembler.value.ValueGetterFactory;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.asterix.column.tuple.QueryColumnWithMetaTupleReference;
 import org.apache.asterix.column.values.reader.ColumnValueReaderFactory;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.runtime.projection.FunctionCallInformation;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 import org.apache.hyracks.data.std.api.IValueReference;
@@ -43,8 +45,11 @@
     public QueryColumnWithMetaTupleProjector(ARecordType datasetType, ARecordType metaType, int numberOfPrimaryKeys,
             ARecordType requestedType, Map<String, FunctionCallInformation> functionCallInfoMap,
             ARecordType requestedMetaType, Map<String, FunctionCallInformation> metaFunctionCallInfoMap,
-            IColumnFilterEvaluatorFactory filterEvaluator, IWarningCollector warningCollector) {
-        super(datasetType, numberOfPrimaryKeys, requestedType, functionCallInfoMap, filterEvaluator, warningCollector);
+            IColumnNormalizedFilterEvaluatorFactory filterEvaluator,
+            IColumnIterableFilterEvaluatorFactory columnFilterEvaluatorFactory, IWarningCollector warningCollector,
+            IHyracksTaskContext context) {
+        super(datasetType, numberOfPrimaryKeys, requestedType, functionCallInfoMap, filterEvaluator,
+                columnFilterEvaluatorFactory, warningCollector, context);
         this.metaType = metaType;
         this.requestedMetaType = requestedMetaType;
         this.metaFunctionCallInfoMap = metaFunctionCallInfoMap;
@@ -55,7 +60,8 @@
         try {
             return QueryColumnWithMetaMetadata.create(datasetType, metaType, numberOfPrimaryKeys, serializedMetadata,
                     new ColumnValueReaderFactory(), ValueGetterFactory.INSTANCE, requestedType, functionCallInfoMap,
-                    requestedMetaType, metaFunctionCallInfoMap, filterEvaluator, warningCollector);
+                    requestedMetaType, metaFunctionCallInfoMap, normalizedFilterEvaluatorFactory,
+                    columnFilterEvaluatorFactory, warningCollector, context);
         } catch (IOException e) {
             throw HyracksDataException.create(e);
         }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/MergeColumnTupleReference.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/MergeColumnTupleReference.java
index 56b0a57..61030e1 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/MergeColumnTupleReference.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/MergeColumnTupleReference.java
@@ -79,6 +79,17 @@
     }
 
     @Override
+    protected void startColumnFilter(IColumnBufferProvider buffersProvider, int ordinal, int numberOfTuples)
+            throws HyracksDataException {
+        // NoOp
+    }
+
+    @Override
+    protected boolean evaluateFilter() throws HyracksDataException {
+        return true;
+    }
+
+    @Override
     public void skip(int count) throws HyracksDataException {
         skipCount += count;
     }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/QueryColumnTupleReference.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/QueryColumnTupleReference.java
index b70bddc..32d25e3 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/QueryColumnTupleReference.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/QueryColumnTupleReference.java
@@ -21,13 +21,20 @@
 import java.nio.ByteBuffer;
 import java.util.List;
 
+import org.apache.asterix.column.assembler.value.MissingValueGetter;
 import org.apache.asterix.column.bytes.stream.in.AbstractBytesInputStream;
+import org.apache.asterix.column.bytes.stream.in.ByteBufferInputStream;
+import org.apache.asterix.column.bytes.stream.in.MultiByteBufferInputStream;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.IFilterApplier;
+import org.apache.asterix.column.filter.TrueColumnFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
 import org.apache.asterix.column.operation.query.ColumnAssembler;
 import org.apache.asterix.column.operation.query.QueryColumnMetadata;
+import org.apache.asterix.column.values.IColumnValuesReader;
 import org.apache.asterix.column.values.reader.PrimitiveColumnValuesReader;
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
 import org.apache.asterix.column.values.writer.filters.AbstractColumnFilterWriter;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.api.IValueReference;
@@ -38,15 +45,34 @@
 
 public final class QueryColumnTupleReference extends AbstractAsterixColumnTupleReference {
     private final ColumnAssembler assembler;
-    private final IColumnFilterEvaluator filterEvaluator;
-    private final List<IColumnFilterValueAccessor> filterValueAccessors;
+    private final IColumnFilterEvaluator normalizedFilterEvaluator;
+    private final List<IColumnFilterNormalizedValueAccessor> filterValueAccessors;
+    private final IColumnIterableFilterEvaluator columnFilterEvaluator;
+    private final IFilterApplier filterApplier;
+    private final List<IColumnValuesReader> filterColumnReaders;
+    private final AbstractBytesInputStream[] filteredColumnStreams;
 
     public QueryColumnTupleReference(int componentIndex, ColumnBTreeReadLeafFrame frame,
             QueryColumnMetadata columnMetadata, IColumnReadMultiPageOp multiPageOp) {
         super(componentIndex, frame, columnMetadata, multiPageOp);
         assembler = columnMetadata.getAssembler();
-        filterEvaluator = columnMetadata.getFilterEvaluator();
+
+        normalizedFilterEvaluator = columnMetadata.getNormalizedFilterEvaluator();
         filterValueAccessors = columnMetadata.getFilterValueAccessors();
+
+        columnFilterEvaluator = columnMetadata.getColumnFilterEvaluator();
+        filterColumnReaders = columnMetadata.getFilterColumnReaders();
+        filterApplier = createFilterApplier();
+
+        int numberOfPrimaryKeys = columnMetadata.getNumberOfPrimaryKeys();
+        filteredColumnStreams = new AbstractBytesInputStream[columnMetadata.getNumberOfFilteredColumns()];
+        for (int i = 0; i < filteredColumnStreams.length; i++) {
+            if (filterColumnReaders.get(i).getColumnIndex() >= numberOfPrimaryKeys) {
+                filteredColumnStreams[i] = new MultiByteBufferInputStream();
+            } else {
+                filteredColumnStreams[i] = new ByteBufferInputStream();
+            }
+        }
     }
 
     @Override
@@ -55,7 +81,8 @@
     }
 
     @Override
-    protected boolean startNewPage(ByteBuffer pageZero, int numberOfColumns, int numberOfTuples) {
+    protected boolean startNewPage(ByteBuffer pageZero, int numberOfColumns, int numberOfTuples)
+            throws HyracksDataException {
         //Skip to filters
         pageZero.position(pageZero.position() + numberOfColumns * Integer.BYTES);
         //Set filters' values
@@ -63,12 +90,26 @@
         //Skip filters
         pageZero.position(pageZero.position() + numberOfColumns * AbstractColumnFilterWriter.FILTER_SIZE);
         //Check if we should read all column pages
-        boolean readColumns = filterEvaluator.evaluate();
+        boolean readColumns = normalizedFilterEvaluator.evaluate();
         assembler.reset(readColumns ? numberOfTuples : 0);
+        columnFilterEvaluator.reset();
         return readColumns;
     }
 
     @Override
+    protected void startColumnFilter(IColumnBufferProvider buffersProvider, int ordinal, int numberOfTuples)
+            throws HyracksDataException {
+        AbstractBytesInputStream columnStream = filteredColumnStreams[ordinal];
+        columnStream.reset(buffersProvider);
+        filterColumnReaders.get(ordinal).reset(columnStream, numberOfTuples);
+    }
+
+    @Override
+    protected boolean evaluateFilter() throws HyracksDataException {
+        return columnFilterEvaluator.evaluate();
+    }
+
+    @Override
     protected void startColumn(IColumnBufferProvider buffersProvider, int ordinal, int numberOfTuples)
             throws HyracksDataException {
         AbstractBytesInputStream columnStream = columnStreams[ordinal];
@@ -78,10 +119,31 @@
 
     @Override
     public void skip(int count) throws HyracksDataException {
-        assembler.skip(count);
+        columnFilterEvaluator.setAt(assembler.skip(count));
     }
 
     public IValueReference getAssembledValue() throws HyracksDataException {
-        return assembler.nextValue();
+        return filterApplier.getTuple();
+    }
+
+    private IFilterApplier createFilterApplier() {
+        if (columnFilterEvaluator == TrueColumnFilterEvaluator.INSTANCE) {
+            return assembler::nextValue;
+        } else {
+            return this::getFilteredAssembledValue;
+        }
+    }
+
+    private IValueReference getFilteredAssembledValue() throws HyracksDataException {
+        int index = columnFilterEvaluator.getTupleIndex();
+        // index == -1 if the normalized filter indicated that a mega leaf node
+        // is filtered
+        if (index == tupleIndex) {
+            assembler.setAt(index);
+            // set the next tuple index that satisfies the filter
+            columnFilterEvaluator.evaluate();
+            return assembler.nextValue();
+        }
+        return MissingValueGetter.MISSING;
     }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/QueryColumnWithMetaTupleReference.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/QueryColumnWithMetaTupleReference.java
index 5b7794e..e2858ae 100644
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/QueryColumnWithMetaTupleReference.java
+++ b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/tuple/QueryColumnWithMetaTupleReference.java
@@ -21,14 +21,21 @@
 import java.nio.ByteBuffer;
 import java.util.List;
 
+import org.apache.asterix.column.assembler.value.MissingValueGetter;
 import org.apache.asterix.column.bytes.stream.in.AbstractBytesInputStream;
+import org.apache.asterix.column.bytes.stream.in.ByteBufferInputStream;
+import org.apache.asterix.column.bytes.stream.in.MultiByteBufferInputStream;
+import org.apache.asterix.column.filter.FilterAccessorProvider;
+import org.apache.asterix.column.filter.IColumnFilterEvaluator;
+import org.apache.asterix.column.filter.IFilterApplier;
+import org.apache.asterix.column.filter.TrueColumnFilterEvaluator;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluator;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessor;
 import org.apache.asterix.column.operation.query.ColumnAssembler;
 import org.apache.asterix.column.operation.query.QueryColumnMetadata;
 import org.apache.asterix.column.operation.query.QueryColumnWithMetaMetadata;
+import org.apache.asterix.column.values.IColumnValuesReader;
 import org.apache.asterix.column.values.reader.PrimitiveColumnValuesReader;
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessor;
 import org.apache.asterix.column.values.writer.filters.AbstractColumnFilterWriter;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.api.IValueReference;
@@ -40,16 +47,35 @@
 public final class QueryColumnWithMetaTupleReference extends AbstractAsterixColumnTupleReference {
     private final ColumnAssembler assembler;
     private final ColumnAssembler metaAssembler;
-    private final IColumnFilterEvaluator filterEvaluator;
-    private final List<IColumnFilterValueAccessor> filterValueAccessors;
+    private final IColumnFilterEvaluator normalizedFilterEvaluator;
+    private final List<IColumnFilterNormalizedValueAccessor> filterValueAccessors;
+    private final IColumnIterableFilterEvaluator columnFilterEvaluator;
+    private final IFilterApplier filterApplier;
+    private final List<IColumnValuesReader> filterColumnReaders;
+    private final AbstractBytesInputStream[] filteredColumnStreams;
 
     public QueryColumnWithMetaTupleReference(int componentIndex, ColumnBTreeReadLeafFrame frame,
             QueryColumnMetadata columnMetadata, IColumnReadMultiPageOp multiPageOp) {
         super(componentIndex, frame, columnMetadata, multiPageOp);
         assembler = columnMetadata.getAssembler();
         metaAssembler = ((QueryColumnWithMetaMetadata) columnMetadata).getMetaAssembler();
-        filterEvaluator = columnMetadata.getFilterEvaluator();
+
+        normalizedFilterEvaluator = columnMetadata.getNormalizedFilterEvaluator();
         filterValueAccessors = columnMetadata.getFilterValueAccessors();
+
+        columnFilterEvaluator = columnMetadata.getColumnFilterEvaluator();
+        filterColumnReaders = columnMetadata.getFilterColumnReaders();
+        filterApplier = createFilterApplier();
+
+        int numberOfPrimaryKeys = columnMetadata.getNumberOfPrimaryKeys();
+        filteredColumnStreams = new AbstractBytesInputStream[columnMetadata.getNumberOfFilteredColumns()];
+        for (int i = 0; i < filteredColumnStreams.length; i++) {
+            if (filterColumnReaders.get(i).getColumnIndex() >= numberOfPrimaryKeys) {
+                filteredColumnStreams[i] = new MultiByteBufferInputStream();
+            } else {
+                filteredColumnStreams[i] = new ByteBufferInputStream();
+            }
+        }
     }
 
     @Override
@@ -58,7 +84,8 @@
     }
 
     @Override
-    protected boolean startNewPage(ByteBuffer pageZero, int numberOfColumns, int numberOfTuples) {
+    protected boolean startNewPage(ByteBuffer pageZero, int numberOfColumns, int numberOfTuples)
+            throws HyracksDataException {
         //Skip to filters
         pageZero.position(pageZero.position() + numberOfColumns * Integer.BYTES);
         //Set filters' values
@@ -66,13 +93,27 @@
         //Skip filters
         pageZero.position(pageZero.position() + numberOfColumns * AbstractColumnFilterWriter.FILTER_SIZE);
         //Check if we should read all column pages
-        boolean readColumns = filterEvaluator.evaluate();
+        boolean readColumns = normalizedFilterEvaluator.evaluate();
         assembler.reset(readColumns ? numberOfTuples : 0);
         metaAssembler.reset(readColumns ? numberOfTuples : 0);
+        columnFilterEvaluator.reset();
         return readColumns;
     }
 
     @Override
+    protected void startColumnFilter(IColumnBufferProvider buffersProvider, int ordinal, int numberOfTuples)
+            throws HyracksDataException {
+        AbstractBytesInputStream columnStream = filteredColumnStreams[ordinal];
+        columnStream.reset(buffersProvider);
+        filterColumnReaders.get(ordinal).reset(columnStream, numberOfTuples);
+    }
+
+    @Override
+    protected boolean evaluateFilter() throws HyracksDataException {
+        return columnFilterEvaluator.evaluate();
+    }
+
+    @Override
     protected void startColumn(IColumnBufferProvider buffersProvider, int ordinal, int numberOfTuples)
             throws HyracksDataException {
         AbstractBytesInputStream columnStream = columnStreams[ordinal];
@@ -88,14 +129,36 @@
     @Override
     public void skip(int count) throws HyracksDataException {
         metaAssembler.skip(count);
-        assembler.skip(count);
+        columnFilterEvaluator.setAt(assembler.skip(count));
     }
 
     public IValueReference getAssembledValue() throws HyracksDataException {
-        return assembler.nextValue();
+        return filterApplier.getTuple();
     }
 
     public IValueReference getMetaAssembledValue() throws HyracksDataException {
         return metaAssembler.nextValue();
     }
+
+    private IFilterApplier createFilterApplier() {
+        if (columnFilterEvaluator == TrueColumnFilterEvaluator.INSTANCE) {
+            return assembler::nextValue;
+        } else {
+            return this::getFilteredAssembledValue;
+        }
+    }
+
+    private IValueReference getFilteredAssembledValue() throws HyracksDataException {
+        int index = columnFilterEvaluator.getTupleIndex();
+        // index == -1 if the normalized filter indicated that a mega leaf node
+        // is filtered
+        if (index == tupleIndex) {
+            assembler.setAt(index);
+            metaAssembler.setAt(index);
+            // set the next tuple index that satisfies the filter
+            columnFilterEvaluator.evaluate();
+            return assembler.nextValue();
+        }
+        return MissingValueGetter.MISSING;
+    }
 }
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/FilterAccessorProvider.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/FilterAccessorProvider.java
deleted file mode 100644
index 2c8cf19..0000000
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/FilterAccessorProvider.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.column.values.reader.filter;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.asterix.column.metadata.schema.ObjectSchemaNode;
-import org.apache.asterix.column.metadata.schema.primitive.PrimitiveSchemaNode;
-import org.apache.asterix.column.metadata.schema.visitor.PathExtractorVisitor;
-import org.apache.asterix.column.metadata.schema.visitor.SchemaClipperVisitor;
-import org.apache.asterix.column.values.reader.filter.value.ColumnFilterValueAccessor;
-import org.apache.asterix.column.values.reader.filter.value.NoOpColumnFilterValueAccessor;
-import org.apache.asterix.column.values.writer.filters.AbstractColumnFilterWriter;
-import org.apache.asterix.om.types.ARecordType;
-import org.apache.asterix.om.types.ATypeTag;
-import org.apache.hyracks.api.exceptions.HyracksDataException;
-
-public class FilterAccessorProvider {
-    private final ObjectSchemaNode root;
-    private final ObjectSchemaNode metaRoot;
-    private final SchemaClipperVisitor clipperVisitor;
-    private final PathExtractorVisitor pathExtractorVisitor;
-    private final Map<ARecordType, PrimitiveSchemaNode> cachedNodes;
-    private final List<IColumnFilterValueAccessor> filterAccessors;
-
-    public FilterAccessorProvider(ObjectSchemaNode root, SchemaClipperVisitor clipperVisitor) {
-        this(root, null, clipperVisitor);
-    }
-
-    public FilterAccessorProvider(ObjectSchemaNode root, ObjectSchemaNode metaRoot,
-            SchemaClipperVisitor clipperVisitor) {
-        this.root = root;
-        this.metaRoot = metaRoot;
-        this.clipperVisitor = clipperVisitor;
-        this.pathExtractorVisitor = new PathExtractorVisitor();
-        cachedNodes = new HashMap<>();
-        filterAccessors = new ArrayList<>();
-    }
-
-    public IColumnFilterValueAccessor createColumnFilterValueAccessor(ARecordType path, boolean min)
-            throws HyracksDataException {
-        PrimitiveSchemaNode node = getNode(path);
-        ATypeTag typeTag = node.getTypeTag();
-        if (typeTag == ATypeTag.MISSING) {
-            return NoOpColumnFilterValueAccessor.INSTANCE;
-        }
-        IColumnFilterValueAccessor accessor = new ColumnFilterValueAccessor(node.getColumnIndex(), typeTag, min);
-        filterAccessors.add(accessor);
-        return accessor;
-    }
-
-    public List<IColumnFilterValueAccessor> getFilterAccessors() {
-        return filterAccessors;
-    }
-
-    public static void setFilterValues(List<IColumnFilterValueAccessor> filterValueAccessors, ByteBuffer pageZero,
-            int numberOfColumns) {
-        for (int i = 0; i < filterValueAccessors.size(); i++) {
-            ColumnFilterValueAccessor accessor = (ColumnFilterValueAccessor) filterValueAccessors.get(i);
-            int columnIndex = accessor.getColumnIndex();
-            long normalizedValue;
-            if (columnIndex < numberOfColumns) {
-                int filterOffset = pageZero.position() + columnIndex * AbstractColumnFilterWriter.FILTER_SIZE;
-                normalizedValue =
-                        accessor.isMin() ? pageZero.getLong(filterOffset) : pageZero.getLong(filterOffset + Long.BYTES);
-            } else {
-                // Column is missing
-                normalizedValue = accessor.isMin() ? Long.MAX_VALUE : Long.MIN_VALUE;
-            }
-            accessor.setNormalizedValue(normalizedValue);
-        }
-    }
-
-    private PrimitiveSchemaNode getNode(ARecordType path) throws HyracksDataException {
-        PrimitiveSchemaNode node = cachedNodes.get(path);
-        if (node == null) {
-            ObjectSchemaNode dataPath = (ObjectSchemaNode) path.accept(clipperVisitor, root);
-            node = (PrimitiveSchemaNode) dataPath.accept(pathExtractorVisitor, null);
-            if (node.getTypeTag() == ATypeTag.MISSING && metaRoot != null) {
-                //Try meta
-                ObjectSchemaNode metaPath = (ObjectSchemaNode) path.accept(clipperVisitor, metaRoot);
-                node = (PrimitiveSchemaNode) metaPath.accept(pathExtractorVisitor, null);
-            }
-            cachedNodes.put(path, node);
-        }
-        return node;
-    }
-}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessorFactory.java
deleted file mode 100644
index 9621c02..0000000
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/IColumnFilterValueAccessorFactory.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.column.values.reader.filter;
-
-import java.io.Serializable;
-
-import org.apache.hyracks.api.exceptions.HyracksDataException;
-
-@FunctionalInterface
-public interface IColumnFilterValueAccessorFactory extends Serializable {
-    IColumnFilterValueAccessor create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException;
-}
diff --git a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/NoOpColumnFilterEvaluatorFactory.java b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/NoOpColumnFilterEvaluatorFactory.java
deleted file mode 100644
index 765f3c6..0000000
--- a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/filter/evaluator/NoOpColumnFilterEvaluatorFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.column.values.reader.filter.evaluator;
-
-import org.apache.asterix.column.values.reader.filter.FilterAccessorProvider;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluator;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
-import org.apache.hyracks.api.exceptions.HyracksDataException;
-
-public class NoOpColumnFilterEvaluatorFactory implements IColumnFilterEvaluatorFactory {
-    private static final long serialVersionUID = -7122361396576592000L;
-    public static final IColumnFilterEvaluatorFactory INSTANCE = new NoOpColumnFilterEvaluatorFactory();
-
-    private NoOpColumnFilterEvaluatorFactory() {
-    }
-
-    @Override
-    public IColumnFilterEvaluator create(FilterAccessorProvider filterAccessorProvider) throws HyracksDataException {
-        // True is also NoOp
-        return TrueColumnFilterEvaluator.INSTANCE;
-    }
-}
diff --git a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/bytes/FlushLargeTest.java b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/bytes/FlushLargeTest.java
index 398c909..24fbf92 100644
--- a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/bytes/FlushLargeTest.java
+++ b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/bytes/FlushLargeTest.java
@@ -26,10 +26,10 @@
 import org.apache.asterix.column.assembler.value.ValueGetterFactory;
 import org.apache.asterix.column.common.buffer.DummyPage;
 import org.apache.asterix.column.common.test.TestCase;
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.column.operation.lsm.flush.FlushColumnMetadata;
 import org.apache.asterix.column.operation.query.QueryColumnMetadata;
 import org.apache.asterix.column.values.reader.ColumnValueReaderFactory;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.common.exceptions.NoOpWarningCollector;
 import org.apache.asterix.runtime.projection.DataProjectionFiltrationInfo;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -63,11 +63,12 @@
         FlushColumnMetadata columnMetadata = prepareNewFile(fileId);
         List<IValueReference> record = getParsedRecords();
         List<DummyPage> pageZeros = transform(fileId, columnMetadata, record, numberOfTuplesToWrite);
-        QueryColumnMetadata readMetadata = QueryColumnMetadata.create(columnMetadata.getDatasetType(),
-                columnMetadata.getNumberOfPrimaryKeys(), columnMetadata.serializeColumnsMetadata(),
-                new ColumnValueReaderFactory(), ValueGetterFactory.INSTANCE,
-                DataProjectionFiltrationInfo.ALL_FIELDS_TYPE, Collections.emptyMap(),
-                NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE);
+        QueryColumnMetadata readMetadata =
+                QueryColumnMetadata.create(columnMetadata.getDatasetType(), columnMetadata.getNumberOfPrimaryKeys(),
+                        columnMetadata.serializeColumnsMetadata(), new ColumnValueReaderFactory(),
+                        ValueGetterFactory.INSTANCE, DataProjectionFiltrationInfo.ALL_FIELDS_TYPE,
+                        Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE,
+                        NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE, null);
         writeResult(fileId, readMetadata, pageZeros);
         testCase.compareRepeated(numberOfTuplesToWrite);
     }
diff --git a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/bytes/FlushSmallTest.java b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/bytes/FlushSmallTest.java
index 6993478..9164a78 100644
--- a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/bytes/FlushSmallTest.java
+++ b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/bytes/FlushSmallTest.java
@@ -26,10 +26,10 @@
 import org.apache.asterix.column.assembler.value.ValueGetterFactory;
 import org.apache.asterix.column.common.buffer.DummyPage;
 import org.apache.asterix.column.common.test.TestCase;
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.column.operation.lsm.flush.FlushColumnMetadata;
 import org.apache.asterix.column.operation.query.QueryColumnMetadata;
 import org.apache.asterix.column.values.reader.ColumnValueReaderFactory;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.common.exceptions.NoOpWarningCollector;
 import org.apache.asterix.runtime.projection.DataProjectionFiltrationInfo;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -62,11 +62,12 @@
         FlushColumnMetadata columnMetadata = prepareNewFile(fileId);
         List<IValueReference> record = getParsedRecords();
         List<DummyPage> pageZeros = transform(fileId, columnMetadata, record, record.size());
-        QueryColumnMetadata readMetadata = QueryColumnMetadata.create(columnMetadata.getDatasetType(),
-                columnMetadata.getNumberOfPrimaryKeys(), columnMetadata.serializeColumnsMetadata(),
-                new ColumnValueReaderFactory(), ValueGetterFactory.INSTANCE,
-                DataProjectionFiltrationInfo.ALL_FIELDS_TYPE, Collections.emptyMap(),
-                NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE);
+        QueryColumnMetadata readMetadata =
+                QueryColumnMetadata.create(columnMetadata.getDatasetType(), columnMetadata.getNumberOfPrimaryKeys(),
+                        columnMetadata.serializeColumnsMetadata(), new ColumnValueReaderFactory(),
+                        ValueGetterFactory.INSTANCE, DataProjectionFiltrationInfo.ALL_FIELDS_TYPE,
+                        Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE,
+                        NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE, null);
         writeResult(fileId, readMetadata, pageZeros);
         testCase.compare();
     }
diff --git a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/dummy/AssemblerTest.java b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/dummy/AssemblerTest.java
index ff088d6..fcb228f 100644
--- a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/dummy/AssemblerTest.java
+++ b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/test/dummy/AssemblerTest.java
@@ -33,11 +33,11 @@
 import org.apache.asterix.column.bytes.stream.in.AbstractBytesInputStream;
 import org.apache.asterix.column.common.buffer.DummyBytesInputStream;
 import org.apache.asterix.column.common.test.TestCase;
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.column.operation.query.ColumnAssembler;
 import org.apache.asterix.column.operation.query.QueryColumnMetadata;
 import org.apache.asterix.column.util.RunLengthIntArray;
 import org.apache.asterix.column.values.reader.DummyColumnValuesReaderFactory;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.column.values.writer.DummyColumnValuesWriter;
 import org.apache.asterix.common.exceptions.NoOpWarningCollector;
 import org.apache.asterix.om.pointables.ARecordVisitablePointable;
@@ -98,7 +98,8 @@
         QueryColumnMetadata queryMetadata = QueryColumnMetadata.create(columnMetadata.getDatasetType(),
                 columnMetadata.getNumberOfPrimaryKeys(), columnMetadata.serializeColumnsMetadata(), readerFactory,
                 DummyValueGetterFactory.INSTANCE, DataProjectionFiltrationInfo.ALL_FIELDS_TYPE, Collections.emptyMap(),
-                NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpWarningCollector.INSTANCE);
+                NoOpColumnFilterEvaluatorFactory.INSTANCE, NoOpColumnFilterEvaluatorFactory.INSTANCE,
+                NoOpWarningCollector.INSTANCE, null);
         AbstractBytesInputStream[] streams = new AbstractBytesInputStream[columnMetadata.getNumberOfColumns()];
         Arrays.fill(streams, DummyBytesInputStream.INSTANCE);
 
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
index 89e99fd..9f5437b 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/DatasetDataSource.java
@@ -158,7 +158,7 @@
                 }
                 int numberOfPrimaryKeys = dataset.getPrimaryKeys().size();
                 ITupleProjectorFactory tupleProjectorFactory =
-                        IndexUtil.createTupleProjectorFactory(dataset.getDatasetFormatInfo(), projectionInfo,
+                        IndexUtil.createTupleProjectorFactory(context, dataset.getDatasetFormatInfo(), projectionInfo,
                                 metaProjectionInfo, datasetType, metaItemType, numberOfPrimaryKeys);
 
                 int[] minFilterFieldIndexes = createFilterIndexes(minFilterVars, opSchema);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/IndexUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/IndexUtil.java
index 808b8a4..df9fcec 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/IndexUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/IndexUtil.java
@@ -26,11 +26,12 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
 import org.apache.asterix.column.operation.lsm.secondary.create.PrimaryScanColumnTupleProjectorFactory;
 import org.apache.asterix.column.operation.lsm.secondary.upsert.UpsertPreviousColumnTupleProjectorFactory;
 import org.apache.asterix.column.operation.query.QueryColumnTupleProjectorFactory;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
 import org.apache.asterix.common.config.DatasetConfig;
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.exceptions.ErrorCode;
@@ -41,6 +42,8 @@
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Index;
 import org.apache.asterix.metadata.entities.InternalDatasetDetails;
+import org.apache.asterix.metadata.utils.filter.ColumnFilterBuilder;
+import org.apache.asterix.metadata.utils.filter.NormalizedColumnFilterBuilder;
 import org.apache.asterix.om.base.AString;
 import org.apache.asterix.om.base.IAObject;
 import org.apache.asterix.om.types.ARecordType;
@@ -53,6 +56,7 @@
 import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import org.apache.hyracks.algebricks.core.algebra.metadata.IProjectionFiltrationInfo;
+import org.apache.hyracks.algebricks.core.jobgen.impl.JobGenContext;
 import org.apache.hyracks.api.dataflow.value.ITypeTraits;
 import org.apache.hyracks.api.exceptions.SourceLocation;
 import org.apache.hyracks.api.job.IJobletEventListenerFactory;
@@ -264,9 +268,10 @@
                 MetadataConstants.SAMPLE_INDEX_2_PREFIX + datasetName);
     }
 
-    public static ITupleProjectorFactory createTupleProjectorFactory(DatasetFormatInfo datasetFormatInfo,
-            IProjectionFiltrationInfo<?> projectionInfo, IProjectionFiltrationInfo<?> metaProjectionInfo,
-            ARecordType datasetType, ARecordType metaItemType, int numberOfPrimaryKeys) {
+    public static ITupleProjectorFactory createTupleProjectorFactory(JobGenContext context,
+            DatasetFormatInfo datasetFormatInfo, IProjectionFiltrationInfo<?> projectionInfo,
+            IProjectionFiltrationInfo<?> metaProjectionInfo, ARecordType datasetType, ARecordType metaItemType,
+            int numberOfPrimaryKeys) throws AlgebricksException {
         if (datasetFormatInfo.getFormat() == DatasetConfig.DatasetFormat.ROW) {
             return DefaultTupleProjectorFactory.INSTANCE;
         }
@@ -276,7 +281,8 @@
             ARecordType metaType = metaItemType == null ? null : DataProjectionFiltrationInfo.ALL_FIELDS_TYPE;
             return new QueryColumnTupleProjectorFactory(datasetType, metaItemType, numberOfPrimaryKeys,
                     DataProjectionFiltrationInfo.ALL_FIELDS_TYPE, Collections.emptyMap(), metaType,
-                    Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE);
+                    Collections.emptyMap(), NoOpColumnFilterEvaluatorFactory.INSTANCE,
+                    NoOpColumnFilterEvaluatorFactory.INSTANCE);
         }
 
         DataProjectionFiltrationInfo metaDataProjectionInfo = (DataProjectionFiltrationInfo) metaProjectionInfo;
@@ -289,12 +295,17 @@
         Map<String, FunctionCallInformation> metaFunctionCallInfo =
                 metaProjectionInfo == null ? null : metaDataProjectionInfo.getFunctionCallInfoMap();
 
-        ColumnFilterBuilder columnFilterBuilder = new ColumnFilterBuilder(dataProjectionInfo);
-        IColumnFilterEvaluatorFactory filterEvaluator = columnFilterBuilder.build();
+        NormalizedColumnFilterBuilder normalizedColumnFilterBuilder =
+                new NormalizedColumnFilterBuilder(dataProjectionInfo);
+        IColumnNormalizedFilterEvaluatorFactory normalizedFilterEvaluatorFactory =
+                normalizedColumnFilterBuilder.build();
+
+        ColumnFilterBuilder columnFilterBuilder = new ColumnFilterBuilder(dataProjectionInfo, context);
+        IColumnIterableFilterEvaluatorFactory columnFilterEvaluatorFactory = columnFilterBuilder.build();
 
         return new QueryColumnTupleProjectorFactory(datasetType, metaItemType, numberOfPrimaryKeys,
                 datasetRequestedType, datasetFunctionCallInfo, metaRequestedType, metaFunctionCallInfo,
-                filterEvaluator);
+                normalizedFilterEvaluatorFactory, columnFilterEvaluatorFactory);
     }
 
     public static ITupleProjectorFactory createUpsertTupleProjectorFactory(DatasetFormatInfo datasetFormatInfo,
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ArrayPathCheckerVisitor.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ArrayPathCheckerVisitor.java
new file mode 100644
index 0000000..ef1915b
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ArrayPathCheckerVisitor.java
@@ -0,0 +1,94 @@
+/*
+ * 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.metadata.utils.filter;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.asterix.column.filter.iterable.evaluator.ColumnarRepeatedIterableFilterEvaluator;
+import org.apache.asterix.om.typecomputer.impl.RecordMergeTypeComputer;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.AbstractCollectionType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.IATypeVisitor;
+import org.apache.asterix.runtime.projection.DataProjectionFiltrationInfo;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+
+/**
+ * TODO this should be removed once we support rewindable readers
+ *
+ * @see ColumnarRepeatedIterableFilterEvaluator#evaluate()
+ */
+public class ArrayPathCheckerVisitor implements IATypeVisitor<Boolean, AbstractCollectionType> {
+    private final Set<Object> seenCollections;
+    private boolean firstPath;
+
+    ArrayPathCheckerVisitor() {
+        seenCollections = new HashSet<>();
+    }
+
+    public boolean containsMultipleArrayPaths(Collection<ARecordType> paths) throws AlgebricksException {
+        ARecordType mergedPaths = DataProjectionFiltrationInfo.EMPTY_TYPE;
+        for (ARecordType path : paths) {
+            mergedPaths = (ARecordType) RecordMergeTypeComputer.merge(mergedPaths, path);
+        }
+        firstPath = true;
+        return !mergedPaths.accept(this, null);
+    }
+
+    @Override
+    public Boolean visit(ARecordType recordType, AbstractCollectionType arg) {
+        for (IAType child : recordType.getFieldTypes()) {
+            if (!child.accept(this, null)) {
+                return Boolean.FALSE;
+            }
+        }
+        return Boolean.TRUE;
+    }
+
+    @Override
+    public Boolean visit(AbstractCollectionType collectionType, AbstractCollectionType arg) {
+        if (firstPath) {
+            seenCollections.add(collectionType);
+        } else if (!seenCollections.contains(collectionType)) {
+            return Boolean.FALSE;
+        }
+        return collectionType.getItemType().accept(this, collectionType);
+    }
+
+    @Override
+    public Boolean visit(AUnionType unionType, AbstractCollectionType arg) {
+        for (IAType child : unionType.getUnionList()) {
+            if (!child.accept(this, arg)) {
+                return Boolean.FALSE;
+            }
+        }
+        return Boolean.TRUE;
+    }
+
+    @Override
+    public Boolean visitFlat(IAType flatType, AbstractCollectionType arg) {
+        if (arg != null) {
+            firstPath = false;
+        }
+        return Boolean.TRUE;
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ColumnFilterBuilder.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ColumnFilterBuilder.java
new file mode 100644
index 0000000..5c770fd
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/ColumnFilterBuilder.java
@@ -0,0 +1,162 @@
+/*
+ * 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.metadata.utils.filter;
+
+import static org.apache.asterix.metadata.utils.filter.NormalizedColumnFilterBuilder.NORMALIZED_PUSHABLE_FUNCTIONS;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.iterable.IColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.iterable.accessor.ColumnFilterValueAccessorEvaluatorFactory;
+import org.apache.asterix.column.filter.iterable.evaluator.ColumnIterableFilterEvaluatorFactory;
+import org.apache.asterix.common.api.IApplicationContext;
+import org.apache.asterix.common.config.CompilerProperties;
+import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptor;
+import org.apache.asterix.om.functions.IFunctionManager;
+import org.apache.asterix.om.functions.IFunctionTypeInferer;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.runtime.projection.DataProjectionFiltrationInfo;
+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.LogicalExpressionTag;
+import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.core.jobgen.impl.JobGenContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+
+public class ColumnFilterBuilder {
+    private final FilterVariableTypeEnvironment typeEnv;
+    private final Map<ILogicalExpression, ARecordType> filterPaths;
+    private final ILogicalExpression filterExpression;
+    private final JobGenContext context;
+    private final ArrayPathCheckerVisitor checkerVisitor;
+
+    public ColumnFilterBuilder(DataProjectionFiltrationInfo projectionFiltrationInfo, JobGenContext context) {
+        typeEnv = new FilterVariableTypeEnvironment();
+        this.filterPaths = projectionFiltrationInfo.getActualPaths();
+        this.filterExpression = projectionFiltrationInfo.getFilterExpression();
+        this.context = context;
+        checkerVisitor = new ArrayPathCheckerVisitor();
+    }
+
+    public IColumnIterableFilterEvaluatorFactory build() throws AlgebricksException {
+        if (filterExpression == null || filterPaths.isEmpty()
+                || checkerVisitor.containsMultipleArrayPaths(filterPaths.values())) {
+            return NoOpColumnFilterEvaluatorFactory.INSTANCE;
+        }
+        IScalarEvaluatorFactory evalFactory = createEvaluator(filterExpression);
+        if (evalFactory == null) {
+            return NoOpColumnFilterEvaluatorFactory.INSTANCE;
+        }
+        return new ColumnIterableFilterEvaluatorFactory(evalFactory);
+    }
+
+    private IScalarEvaluatorFactory createEvaluator(ILogicalExpression expression) throws AlgebricksException {
+        if (filterPaths.containsKey(expression)) {
+            return createValueAccessor(expression);
+        } else if (expression.getExpressionTag() == LogicalExpressionTag.CONSTANT) {
+            return createConstantAccessor(expression);
+        } else if (expression.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+            return handleFunction(expression);
+        }
+        return null;
+    }
+
+    private IScalarEvaluatorFactory createValueAccessor(ILogicalExpression expression) {
+        ARecordType path = filterPaths.get(expression);
+        return new ColumnFilterValueAccessorEvaluatorFactory(path);
+    }
+
+    private IScalarEvaluatorFactory createConstantAccessor(ILogicalExpression expression) throws AlgebricksException {
+        MetadataProvider metadataProvider = (MetadataProvider) context.getMetadataProvider();
+        ConstantExpression constExpr = (ConstantExpression) expression;
+        return metadataProvider.getDataFormat().getConstantEvalFactory(constExpr.getValue());
+    }
+
+    private IScalarEvaluatorFactory handleFunction(ILogicalExpression expr) throws AlgebricksException {
+        AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;
+        IScalarEvaluatorFactory[] args = handleArgs(funcExpr);
+        if (args == null) {
+            return null;
+        }
+
+        IFunctionDescriptor fd = resolveFunction(funcExpr);
+        return fd.createEvaluatorFactory(args);
+    }
+
+    private IScalarEvaluatorFactory[] handleArgs(AbstractFunctionCallExpression funcExpr) throws AlgebricksException {
+        List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
+        IScalarEvaluatorFactory[] argsEvalFactories = new IScalarEvaluatorFactory[args.size()];
+        for (int i = 0; i < args.size(); i++) {
+            ILogicalExpression expr = args.get(i).getValue();
+            IScalarEvaluatorFactory evalFactory = createEvaluator(expr);
+            if (evalFactory == null) {
+                return null;
+            }
+            argsEvalFactories[i] = evalFactory;
+        }
+        return argsEvalFactories;
+    }
+
+    private IFunctionDescriptor resolveFunction(AbstractFunctionCallExpression funcExpr) throws AlgebricksException {
+        MetadataProvider metadataProvider = (MetadataProvider) context.getMetadataProvider();
+        IFunctionManager functionManager = metadataProvider.getFunctionManager();
+        FunctionIdentifier fnId = funcExpr.getFunctionIdentifier();
+        SourceLocation sourceLocation = funcExpr.getSourceLocation();
+        IFunctionDescriptor fd = functionManager.lookupFunction(fnId, sourceLocation);
+        fd.setSourceLocation(sourceLocation);
+        IFunctionTypeInferer fnTypeInfer = functionManager.lookupFunctionTypeInferer(fnId);
+        if (fnTypeInfer != null) {
+            CompilerProperties compilerProps = ((IApplicationContext) context.getAppContext()).getCompilerProperties();
+            fnTypeInfer.infer(funcExpr, fd, typeEnv, compilerProps);
+        }
+        return fd;
+    }
+
+    public static boolean isPushable(FunctionIdentifier fid) {
+        return NORMALIZED_PUSHABLE_FUNCTIONS.contains(fid) || !isNestedFunction(fid) && !isTypeFunction(fid);
+    }
+
+    private static boolean isTypeFunction(FunctionIdentifier fid) {
+        return fid.getName().startsWith("is");
+    }
+
+    private static boolean isNestedFunction(FunctionIdentifier fid) {
+        return isObjectFunction(fid) || isArrayFunction(fid) || BuiltinFunctions.DEEP_EQUAL.equals(fid);
+    }
+
+    private static boolean isObjectFunction(FunctionIdentifier fid) {
+        String functionName = fid.getName();
+        return functionName.contains("object") || BuiltinFunctions.PAIRS.equals(fid);
+    }
+
+    private static boolean isArrayFunction(FunctionIdentifier fid) {
+        String functionName = fid.getName();
+        return functionName.startsWith("array") || functionName.startsWith("strict")
+                || BuiltinFunctions.GET_ITEM.equals(fid);
+    }
+
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/FilterVariableTypeEnvironment.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/FilterVariableTypeEnvironment.java
new file mode 100644
index 0000000..0743b1c
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/FilterVariableTypeEnvironment.java
@@ -0,0 +1,56 @@
+/*
+ * 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.metadata.utils.filter;
+
+import java.util.List;
+
+import org.apache.asterix.om.types.BuiltinType;
+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.IVariableTypeEnvironment;
+
+public class FilterVariableTypeEnvironment implements IVariableTypeEnvironment {
+    @Override
+    public Object getVarType(LogicalVariable var) throws AlgebricksException {
+        throw new IllegalAccessError("Should not be invoked");
+    }
+
+    @Override
+    public Object getVarType(LogicalVariable var, List<LogicalVariable> nonMissableVariables,
+            List<List<LogicalVariable>> correlatedMissableVariableLists, List<LogicalVariable> nonNullableVariables,
+            List<List<LogicalVariable>> correlatedNullableVariableLists) throws AlgebricksException {
+        throw new IllegalAccessError("Should not be invoked");
+    }
+
+    @Override
+    public void setVarType(LogicalVariable var, Object type) {
+        throw new IllegalAccessError("Should not be invoked");
+    }
+
+    @Override
+    public Object getType(ILogicalExpression expr) throws AlgebricksException {
+        return BuiltinType.ANY;
+    }
+
+    @Override
+    public boolean substituteProducedVariable(LogicalVariable v1, LogicalVariable v2) throws AlgebricksException {
+        throw new IllegalAccessError("Should not be invoked");
+    }
+}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/ColumnFilterBuilder.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/NormalizedColumnFilterBuilder.java
similarity index 62%
rename from asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/ColumnFilterBuilder.java
rename to asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/NormalizedColumnFilterBuilder.java
index e8c2b7f..d667e68 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/ColumnFilterBuilder.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/filter/NormalizedColumnFilterBuilder.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.asterix.metadata.utils;
+package org.apache.asterix.metadata.utils.filter;
 
 import static org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions.ComparisonKind;
 
@@ -25,17 +25,17 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.asterix.column.values.reader.filter.IColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.IColumnFilterValueAccessorFactory;
-import org.apache.asterix.column.values.reader.filter.compartor.GEColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.compartor.GTColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.compartor.LEColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.compartor.LTColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.evaluator.ANDColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.evaluator.NoOpColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.evaluator.ORColumnFilterEvaluatorFactory;
-import org.apache.asterix.column.values.reader.filter.value.ColumnFilterValueAccessorFactory;
-import org.apache.asterix.column.values.reader.filter.value.ConstantColumnFilterValueAccessorFactory;
+import org.apache.asterix.column.filter.NoOpColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnFilterNormalizedValueAccessorFactory;
+import org.apache.asterix.column.filter.normalized.IColumnNormalizedFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.accessor.ColumnFilterNormalizedValueAccessorFactory;
+import org.apache.asterix.column.filter.normalized.accessor.ConstantColumnFilterNormalizedValueAccessorFactory;
+import org.apache.asterix.column.filter.normalized.compartor.GEColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.compartor.GTColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.compartor.LEColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.compartor.LTColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.evaluator.ANDColumnFilterEvaluatorFactory;
+import org.apache.asterix.column.filter.normalized.evaluator.ORColumnFilterEvaluatorFactory;
 import org.apache.asterix.om.base.IAObject;
 import org.apache.asterix.om.constants.AsterixConstantValue;
 import org.apache.asterix.om.functions.BuiltinFunctions;
@@ -49,26 +49,26 @@
 import org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 
-public class ColumnFilterBuilder {
+public class NormalizedColumnFilterBuilder {
     public static final Set<FunctionIdentifier> COMPARE_FUNCTIONS = getCompareFunctions();
-    public static final Set<FunctionIdentifier> PUSHABLE_FUNCTIONS = getPushableFunctions();
+    public static final Set<FunctionIdentifier> NORMALIZED_PUSHABLE_FUNCTIONS = getNormalizedPushableFunctions();
 
     private final Map<ILogicalExpression, ARecordType> filterPaths;
     private final ILogicalExpression filterExpression;
 
-    public ColumnFilterBuilder(DataProjectionFiltrationInfo projectionFiltrationInfo) {
-        this.filterPaths = projectionFiltrationInfo.getExpressionToPath();
+    public NormalizedColumnFilterBuilder(DataProjectionFiltrationInfo projectionFiltrationInfo) {
+        this.filterPaths = projectionFiltrationInfo.getNormalizedPaths();
         this.filterExpression = projectionFiltrationInfo.getFilterExpression();
     }
 
-    public IColumnFilterEvaluatorFactory build() {
+    public IColumnNormalizedFilterEvaluatorFactory build() {
         if (filterExpression == null || filterPaths.isEmpty()) {
             return NoOpColumnFilterEvaluatorFactory.INSTANCE;
         }
         return createEvaluator(filterPaths, filterExpression);
     }
 
-    private IColumnFilterEvaluatorFactory createEvaluator(Map<ILogicalExpression, ARecordType> filterPaths,
+    private IColumnNormalizedFilterEvaluatorFactory createEvaluator(Map<ILogicalExpression, ARecordType> filterPaths,
             ILogicalExpression filterExpression) {
         AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) filterExpression;
         FunctionIdentifier fid = funcExpr.getFunctionIdentifier();
@@ -79,7 +79,7 @@
         return createEvaluatorsForArgs(funcExpr, filterPaths);
     }
 
-    private IColumnFilterEvaluatorFactory createComparator(FunctionIdentifier fid,
+    private IColumnNormalizedFilterEvaluatorFactory createComparator(FunctionIdentifier fid,
             List<Mutable<ILogicalExpression>> arguments, Map<ILogicalExpression, ARecordType> filterPaths) {
         ILogicalExpression arg0 = arguments.get(0).getValue();
         ILogicalExpression arg1 = arguments.get(1).getValue();
@@ -95,30 +95,35 @@
         }
     }
 
-    private IColumnFilterEvaluatorFactory createEvaluatorsForArgs(AbstractFunctionCallExpression funcExpr,
+    private IColumnNormalizedFilterEvaluatorFactory createEvaluatorsForArgs(AbstractFunctionCallExpression funcExpr,
             Map<ILogicalExpression, ARecordType> filterPaths) {
         List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
         FunctionIdentifier fid = funcExpr.getFunctionIdentifier();
 
         //AND/OR have at least two arguments
-        IColumnFilterEvaluatorFactory arg0 = createEvaluator(filterPaths, args.get(0).getValue());
-        IColumnFilterEvaluatorFactory arg1 = createEvaluator(filterPaths, args.get(1).getValue());
+        IColumnNormalizedFilterEvaluatorFactory arg0 = createEvaluator(filterPaths, args.get(0).getValue());
+        IColumnNormalizedFilterEvaluatorFactory arg1 = createEvaluator(filterPaths, args.get(1).getValue());
 
-        IColumnFilterEvaluatorFactory left = createEvaluator(fid, arg0, arg1);
+        IColumnNormalizedFilterEvaluatorFactory left = createEvaluator(fid, arg0, arg1);
         for (int i = 2; i < args.size() && left != null; i++) {
-            IColumnFilterEvaluatorFactory right = createEvaluator(filterPaths, args.get(i).getValue());
+            IColumnNormalizedFilterEvaluatorFactory right = createEvaluator(filterPaths, args.get(i).getValue());
             left = createEvaluator(fid, left, right);
         }
         return left;
     }
 
-    private IColumnFilterEvaluatorFactory createComparator(FunctionIdentifier fid, ARecordType path, IAObject constant,
-            boolean leftToRight) {
+    private IColumnNormalizedFilterEvaluatorFactory createComparator(FunctionIdentifier fid, ARecordType path,
+            IAObject constant, boolean leftToRight) {
         ComparisonKind comparisonKind = AlgebricksBuiltinFunctions.getComparisonType(fid);
+        if (path == null) {
+            // skipped path
+            return NoOpColumnFilterEvaluatorFactory.INSTANCE;
+        }
 
-        IColumnFilterValueAccessorFactory constValue = ConstantColumnFilterValueAccessorFactory.createFactory(constant);
-        IColumnFilterValueAccessorFactory min = new ColumnFilterValueAccessorFactory(path, true);
-        IColumnFilterValueAccessorFactory max = new ColumnFilterValueAccessorFactory(path, false);
+        IColumnFilterNormalizedValueAccessorFactory constValue =
+                ConstantColumnFilterNormalizedValueAccessorFactory.createFactory(constant);
+        IColumnFilterNormalizedValueAccessorFactory min = new ColumnFilterNormalizedValueAccessorFactory(path, true);
+        IColumnFilterNormalizedValueAccessorFactory max = new ColumnFilterNormalizedValueAccessorFactory(path, false);
 
         if (leftToRight) {
             return createEvaluator(comparisonKind, min, constValue, max);
@@ -126,8 +131,8 @@
         return createEvaluator(invert(comparisonKind), min, constValue, max);
     }
 
-    private static IColumnFilterEvaluatorFactory createEvaluator(FunctionIdentifier fid,
-            IColumnFilterEvaluatorFactory left, IColumnFilterEvaluatorFactory right) {
+    private static IColumnNormalizedFilterEvaluatorFactory createEvaluator(FunctionIdentifier fid,
+            IColumnNormalizedFilterEvaluatorFactory left, IColumnNormalizedFilterEvaluatorFactory right) {
         if (right == null) {
             return null;
         }
@@ -149,16 +154,16 @@
         return ComparisonKind.LT;
     }
 
-    private static IColumnFilterEvaluatorFactory createEvaluator(ComparisonKind comparisonKind,
-            IColumnFilterValueAccessorFactory min, IColumnFilterValueAccessorFactory constVal,
-            IColumnFilterValueAccessorFactory max) {
+    private static IColumnNormalizedFilterEvaluatorFactory createEvaluator(ComparisonKind comparisonKind,
+            IColumnFilterNormalizedValueAccessorFactory min, IColumnFilterNormalizedValueAccessorFactory constVal,
+            IColumnFilterNormalizedValueAccessorFactory max) {
         if (comparisonKind == ComparisonKind.LT) {
             return new GTColumnFilterEvaluatorFactory(constVal, min);
         } else if (comparisonKind == ComparisonKind.LE) {
             return new GEColumnFilterEvaluatorFactory(constVal, min);
         } else if (comparisonKind == ComparisonKind.EQ) {
-            IColumnFilterEvaluatorFactory minComp = new GEColumnFilterEvaluatorFactory(constVal, min);
-            IColumnFilterEvaluatorFactory maxComp = new LEColumnFilterEvaluatorFactory(constVal, max);
+            IColumnNormalizedFilterEvaluatorFactory minComp = new GEColumnFilterEvaluatorFactory(constVal, min);
+            IColumnNormalizedFilterEvaluatorFactory maxComp = new LEColumnFilterEvaluatorFactory(constVal, max);
             return new ANDColumnFilterEvaluatorFactory(minComp, maxComp);
         } else if (comparisonKind == ComparisonKind.GT) {
             return new LTColumnFilterEvaluatorFactory(constVal, max);
@@ -176,7 +181,7 @@
                 AlgebricksBuiltinFunctions.GT, AlgebricksBuiltinFunctions.EQ);
     }
 
-    private static Set<FunctionIdentifier> getPushableFunctions() {
+    private static Set<FunctionIdentifier> getNormalizedPushableFunctions() {
         Set<FunctionIdentifier> pushableFunctions = new HashSet<>(COMPARE_FUNCTIONS);
         pushableFunctions.add(AlgebricksBuiltinFunctions.AND);
         pushableFunctions.add(AlgebricksBuiltinFunctions.OR);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/DataProjectionFiltrationInfo.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/DataProjectionFiltrationInfo.java
index e625163..de9b852 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/DataProjectionFiltrationInfo.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/projection/DataProjectionFiltrationInfo.java
@@ -37,17 +37,21 @@
     public static final ARecordType ALL_FIELDS_TYPE = createType("");
     //Default open record type when requesting none of the fields
     public static final ARecordType EMPTY_TYPE = createType("{}");
+    public static final String FILTER_VALUE_ACCESSOR = "filter-value-accessor";
 
     private final ARecordType root;
     private final Map<String, FunctionCallInformation> functionCallInfoMap;
-    private final Map<ILogicalExpression, ARecordType> expressionToPath;
+    private final Map<ILogicalExpression, ARecordType> normalizedPaths;
+    private final Map<ILogicalExpression, ARecordType> actualPaths;
     private final ILogicalExpression filterExpression;
 
     public DataProjectionFiltrationInfo(ARecordType root, Map<String, FunctionCallInformation> sourceInformationMap,
-            Map<ILogicalExpression, ARecordType> expressionToPath, ILogicalExpression filterExpression) {
+            Map<ILogicalExpression, ARecordType> normalizedPaths, Map<ILogicalExpression, ARecordType> actualPaths,
+            ILogicalExpression filterExpression) {
         this.root = root;
         this.functionCallInfoMap = sourceInformationMap;
-        this.expressionToPath = expressionToPath;
+        this.normalizedPaths = normalizedPaths;
+        this.actualPaths = actualPaths;
         this.filterExpression = filterExpression;
     }
 
@@ -60,7 +64,8 @@
             root = other.root.deepCopy(other.root);
         }
         functionCallInfoMap = new HashMap<>(other.functionCallInfoMap);
-        expressionToPath = new HashMap<>(other.expressionToPath);
+        normalizedPaths = new HashMap<>(other.normalizedPaths);
+        actualPaths = new HashMap<>(other.actualPaths);
         filterExpression = other.filterExpression;
     }
 
@@ -83,8 +88,12 @@
         return functionCallInfoMap;
     }
 
-    public Map<ILogicalExpression, ARecordType> getExpressionToPath() {
-        return expressionToPath;
+    public Map<ILogicalExpression, ARecordType> getNormalizedPaths() {
+        return normalizedPaths;
+    }
+
+    public Map<ILogicalExpression, ARecordType> getActualPaths() {
+        return actualPaths;
     }
 
     @Override
@@ -98,7 +107,7 @@
         DataProjectionFiltrationInfo otherInfo = (DataProjectionFiltrationInfo) o;
         return root.deepEqual(otherInfo.root) && Objects.equals(functionCallInfoMap, otherInfo.functionCallInfoMap)
                 && Objects.equals(filterExpression, otherInfo.filterExpression)
-                && Objects.equals(expressionToPath, otherInfo.expressionToPath);
+                && Objects.equals(normalizedPaths, otherInfo.normalizedPaths);
     }
 
     @Override
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-common/src/main/java/org/apache/hyracks/storage/am/common/dataflow/IndexSearchOperatorNodePushable.java b/hyracks-fullstack/hyracks/hyracks-storage-am-common/src/main/java/org/apache/hyracks/storage/am/common/dataflow/IndexSearchOperatorNodePushable.java
index c3719c7..406dbc6 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-common/src/main/java/org/apache/hyracks/storage/am/common/dataflow/IndexSearchOperatorNodePushable.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-common/src/main/java/org/apache/hyracks/storage/am/common/dataflow/IndexSearchOperatorNodePushable.java
@@ -269,6 +269,9 @@
             // tuple must be written first before the filter is applied to
             // assemble columnar tuples
             tuple = writeTupleToOutput(tuple);
+            if (tuple == null) {
+                continue;
+            }
             if (tupleFilter != null) {
                 referenceFilterTuple.reset(tuple);
                 if (!tupleFilter.accept(referenceFilterTuple)) {
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree-column/src/main/java/org/apache/hyracks/storage/am/lsm/btree/column/api/projection/IColumnProjectionInfo.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree-column/src/main/java/org/apache/hyracks/storage/am/lsm/btree/column/api/projection/IColumnProjectionInfo.java
index 1506433..641f704 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree-column/src/main/java/org/apache/hyracks/storage/am/lsm/btree/column/api/projection/IColumnProjectionInfo.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree-column/src/main/java/org/apache/hyracks/storage/am/lsm/btree/column/api/projection/IColumnProjectionInfo.java
@@ -37,4 +37,15 @@
      * @return number of primary keys
      */
     int getNumberOfPrimaryKeys();
+
+    /**
+     * @param ordinal position of the filtered column
+     * @return column index given the ordinal number of the filtered column
+     */
+    int getFilteredColumnIndex(int ordinal);
+
+    /**
+     * @return number of filtered columns
+     */
+    int getNumberOfFilteredColumns();
 }
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree-column/src/main/java/org/apache/hyracks/storage/am/lsm/btree/column/impls/lsm/tuples/AbstractColumnTupleReference.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree-column/src/main/java/org/apache/hyracks/storage/am/lsm/btree/column/impls/lsm/tuples/AbstractColumnTupleReference.java
index 6f95dbf..310b0b6 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree-column/src/main/java/org/apache/hyracks/storage/am/lsm/btree/column/impls/lsm/tuples/AbstractColumnTupleReference.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree-column/src/main/java/org/apache/hyracks/storage/am/lsm/btree/column/impls/lsm/tuples/AbstractColumnTupleReference.java
@@ -38,6 +38,7 @@
     private final int componentIndex;
     private final ColumnBTreeReadLeafFrame frame;
     private final IColumnBufferProvider[] primaryKeyBufferProviders;
+    private final IColumnBufferProvider[] filterBufferProviders;
     private final IColumnBufferProvider[] buffersProviders;
     private final int numberOfPrimaryKeys;
     private int totalNumberOfMegaLeafNodes;
@@ -59,11 +60,21 @@
         numberOfPrimaryKeys = info.getNumberOfPrimaryKeys();
 
         primaryKeyBufferProviders = new IColumnBufferProvider[numberOfPrimaryKeys];
-
         for (int i = 0; i < numberOfPrimaryKeys; i++) {
             primaryKeyBufferProviders[i] = new ColumnSingleBufferProvider(i);
         }
 
+        int numberOfFilteredColumns = info.getNumberOfFilteredColumns();
+        filterBufferProviders = new IColumnBufferProvider[numberOfFilteredColumns];
+        for (int i = 0; i < numberOfFilteredColumns; i++) {
+            int columnIndex = info.getFilteredColumnIndex(i);
+            if (columnIndex >= numberOfPrimaryKeys) {
+                filterBufferProviders[i] = new ColumnMultiBufferProvider(columnIndex, multiPageOp);
+            } else {
+                filterBufferProviders[i] = new ColumnSingleBufferProvider(columnIndex);
+            }
+        }
+
         int numberOfRequestedColumns = info.getNumberOfProjectedColumns();
         buffersProviders = new IColumnBufferProvider[numberOfRequestedColumns];
         for (int i = 0; i < numberOfRequestedColumns; i++) {
@@ -105,6 +116,16 @@
         boolean readColumnPages = startNewPage(pageZero, frame.getNumberOfColumns(), numberOfTuples);
         setPrimaryKeysAt(startIndex, startIndex);
         if (readColumnPages) {
+            for (int i = 0; i < filterBufferProviders.length; i++) {
+                IColumnBufferProvider provider = filterBufferProviders[i];
+                //Release previous pinned pages if any
+                provider.releaseAll();
+                provider.reset(frame);
+                startColumnFilter(provider, i, numberOfTuples);
+            }
+        }
+
+        if (readColumnPages && evaluateFilter()) {
             for (int i = 0; i < buffersProviders.length; i++) {
                 IColumnBufferProvider provider = buffersProviders[i];
                 //Release previous pinned pages if any
@@ -131,7 +152,8 @@
 
     protected abstract void setPrimaryKeysAt(int index, int skipCount) throws HyracksDataException;
 
-    protected abstract boolean startNewPage(ByteBuffer pageZero, int numberOfColumns, int numberOfTuples);
+    protected abstract boolean startNewPage(ByteBuffer pageZero, int numberOfColumns, int numberOfTuples)
+            throws HyracksDataException;
 
     protected abstract void startPrimaryKey(IColumnBufferProvider bufferProvider, int ordinal, int numberOfTuples)
             throws HyracksDataException;
@@ -139,6 +161,11 @@
     protected abstract void startColumn(IColumnBufferProvider buffersProvider, int ordinal, int numberOfTuples)
             throws HyracksDataException;
 
+    protected abstract void startColumnFilter(IColumnBufferProvider buffersProvider, int ordinal, int numberOfTuples)
+            throws HyracksDataException;
+
+    protected abstract boolean evaluateFilter() throws HyracksDataException;
+
     protected abstract void onNext() throws HyracksDataException;
 
     protected final int getTupleCount() {