[ASTERIXDB-3626][COMP] Restrict filter pushdown for array functions

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

Details:
Since array comparison is not supported for
filter-pushdown, hence restricting the functions
returning list as ResultTypeComputer.

Ext-ref: MB-67479
Change-Id: Ib3a4aa0715cf3b2fc0a1882d8b5114e88d0004f3
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/20014
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
Tested-by: Ritik Raj <ritik.raj@couchbase.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/AbstractFilterPushdownProcessor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/AbstractFilterPushdownProcessor.java
index 92436c7..18caaa9 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/AbstractFilterPushdownProcessor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/AbstractFilterPushdownProcessor.java
@@ -19,6 +19,7 @@
 package org.apache.asterix.optimizer.rules.pushdown.processor;
 
 import static org.apache.asterix.metadata.utils.PushdownUtil.getConstant;
+import static org.apache.asterix.metadata.utils.PushdownUtil.getTypeEnv;
 import static org.apache.asterix.metadata.utils.PushdownUtil.isAnd;
 import static org.apache.asterix.metadata.utils.PushdownUtil.isCompare;
 import static org.apache.asterix.metadata.utils.PushdownUtil.isConstant;
@@ -36,6 +37,9 @@
 import java.util.Set;
 
 import org.apache.asterix.om.base.IAObject;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.optimizer.rules.pushdown.PushdownContext;
 import org.apache.asterix.optimizer.rules.pushdown.descriptor.DefineDescriptor;
 import org.apache.asterix.optimizer.rules.pushdown.descriptor.ScanDefineDescriptor;
@@ -122,11 +126,12 @@
     /**
      * Handle a compare function
      *
-     * @param expression compare expression
+     * @param expression        compare expression
+     * @param currentDescriptor
      * @return true if the pushdown should continue, false otherwise
      */
-    protected abstract boolean handleCompare(AbstractFunctionCallExpression expression, int depth)
-            throws AlgebricksException;
+    protected abstract FilterBranch handleCompare(AbstractFunctionCallExpression expression, int depth,
+            UseDescriptor currentDescriptor) throws AlgebricksException;
 
     /**
      * Handle a value access path expression
@@ -134,10 +139,10 @@
      * @param expression path expression
      * @return true if the pushdown should continue, false otherwise
      */
-    protected final boolean handlePath(AbstractFunctionCallExpression expression) throws AlgebricksException {
+    protected final FilterBranch handlePath(AbstractFunctionCallExpression expression) throws AlgebricksException {
         IExpectedSchemaNode node = getPathNode(expression);
         if (node == null) {
-            return false;
+            return FilterBranch.NA;
         }
         return handlePath(expression, node);
     }
@@ -149,7 +154,7 @@
      * @param node       expected schema node (never null)
      * @return true if the pushdown should continue, false otherwise
      */
-    protected abstract boolean handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
+    protected abstract FilterBranch handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
             throws AlgebricksException;
 
     protected abstract IExpectedSchemaNode getPathNode(AbstractFunctionCallExpression expression)
@@ -285,7 +290,7 @@
 
         // Prepare for pushdown
         preparePushdown(useDescriptor, scanDefineDescriptor);
-        if (pushdownFilterExpression(inlinedExpr, 0)) {
+        if (pushdownFilterExpression(inlinedExpr, useDescriptor, 0) != FilterBranch.NA) {
             putFilterInformation(scanDefineDescriptor, inlinedExpr);
             changed = true;
         }
@@ -293,57 +298,88 @@
         return changed;
     }
 
-    protected final boolean pushdownFilterExpression(ILogicalExpression expression, int depth)
-            throws AlgebricksException {
-        boolean pushdown = false;
+    public enum FilterBranch {
+        CONSTANT,
+        AND,
+        COMPARE,
+        FILTER_PATH,
+        FUNCTION,
+        NA;
+
+        public static FilterBranch andOutput(FilterBranch leftBranch, FilterBranch rightBranch,
+                FilterBranch parentBranch) {
+            if (leftBranch == FilterBranch.NA || rightBranch == FilterBranch.NA) {
+                return FilterBranch.NA;
+            }
+            return parentBranch;
+        }
+    };
+
+    protected final FilterBranch pushdownFilterExpression(ILogicalExpression expression, UseDescriptor useDescriptor,
+            int depth) throws AlgebricksException {
         if (isConstant(expression)) {
             IAObject constantValue = getConstant(expression);
             // Only non-derived types are allowed
-            pushdown = !constantValue.getType().getTypeTag().isDerivedType();
+            if (!constantValue.getType().getTypeTag().isDerivedType()) {
+                return FilterBranch.CONSTANT;
+            }
+            return FilterBranch.NA;
         } else if (isAnd(expression)) {
-            pushdown = handleAnd((AbstractFunctionCallExpression) expression, depth);
+            return handleAnd((AbstractFunctionCallExpression) expression, depth, useDescriptor);
         } else if (isCompare(expression)) {
-            pushdown = handleCompare((AbstractFunctionCallExpression) expression, depth);
+            return handleCompare((AbstractFunctionCallExpression) expression, depth, useDescriptor);
         } else if (isFilterPath(expression)) {
-            pushdown = handlePath((AbstractFunctionCallExpression) expression);
+            return handlePath((AbstractFunctionCallExpression) expression);
         } else if (expression.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
             // All functions including OR
-            pushdown = handleFunction((AbstractFunctionCallExpression) expression, depth);
+            return handleFunction((AbstractFunctionCallExpression) expression, depth, useDescriptor);
         }
         // PK variable should have (pushdown = false) as we should not involve the PK (at least currently)
-        return pushdown;
+        return FilterBranch.NA;
     }
 
-    private boolean handleAnd(AbstractFunctionCallExpression expression, int depth) throws AlgebricksException {
+    private FilterBranch handleAnd(AbstractFunctionCallExpression expression, int depth, UseDescriptor useDescriptor)
+            throws AlgebricksException {
         List<Mutable<ILogicalExpression>> args = expression.getArguments();
         Iterator<Mutable<ILogicalExpression>> argIter = args.iterator();
         while (argIter.hasNext()) {
             ILogicalExpression arg = argIter.next().getValue();
             // Allow for partial pushdown of AND operands
-            if (!pushdownFilterExpression(arg, depth + 1)) {
+            if (pushdownFilterExpression(arg, useDescriptor, depth + 1) == FilterBranch.NA) {
                 if (depth == 0) {
                     // Remove the expression that cannot be pushed down
                     argIter.remove();
                 } else {
-                    return false;
+                    return FilterBranch.NA;
                 }
             }
         }
-        return !args.isEmpty();
+        return !args.isEmpty() ? FilterBranch.AND : FilterBranch.NA;
     }
 
-    private boolean handleFunction(AbstractFunctionCallExpression expression, int depth) throws AlgebricksException {
+    protected boolean expressionReturnsArray(ILogicalExpression expression, ILogicalOperator operator)
+            throws AlgebricksException {
+        IAType expressionType = (IAType) context.getExpressionTypeComputer().getType(expression,
+                context.getMetadataProvider(), getTypeEnv(operator, context));
+        if (ATypeTag.UNION == expressionType.getTypeTag()) {
+            expressionType = ((AUnionType) expressionType).getActualType();
+        }
+        return ATypeTag.ARRAY == expressionType.getTypeTag() || ATypeTag.ANY == expressionType.getTypeTag();
+    }
+
+    private FilterBranch handleFunction(AbstractFunctionCallExpression expression, int depth,
+            UseDescriptor useDescriptor) throws AlgebricksException {
         if (!expression.getFunctionInfo().isFunctional() || isNotPushable(expression)) {
-            return false;
+            return FilterBranch.NA;
         }
 
         for (Mutable<ILogicalExpression> argRef : expression.getArguments()) {
             ILogicalExpression arg = argRef.getValue();
             // Either all arguments are pushable or none
-            if (!pushdownFilterExpression(arg, depth + 1)) {
-                return false;
+            if (pushdownFilterExpression(arg, useDescriptor, depth + 1) == FilterBranch.NA) {
+                return FilterBranch.NA;
             }
         }
-        return true;
+        return FilterBranch.FUNCTION;
     }
 }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ColumnFilterPushdownProcessor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ColumnFilterPushdownProcessor.java
index 497e751..445da7e 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ColumnFilterPushdownProcessor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ColumnFilterPushdownProcessor.java
@@ -104,7 +104,8 @@
     }
 
     @Override
-    protected boolean handleCompare(AbstractFunctionCallExpression expression, int depth) throws AlgebricksException {
+    protected FilterBranch handleCompare(AbstractFunctionCallExpression expression, int depth,
+            UseDescriptor currentDescriptor) throws AlgebricksException {
         List<Mutable<ILogicalExpression>> args = expression.getArguments();
 
         Mutable<ILogicalExpression> leftRef = args.get(0);
@@ -113,17 +114,38 @@
         ILogicalExpression left = leftRef.getValue();
         ILogicalExpression right = rightRef.getValue();
 
-        return pushdownFilterExpression(left, depth + 1) && pushdownFilterExpression(right, depth + 1);
+        //If the left or right is handlePath (like getField), then the right or left shouldn't be an array
+        FilterBranch leftBranch = pushdownFilterExpression(left, currentDescriptor, depth + 1);
+        FilterBranch rightBranch = pushdownFilterExpression(right, currentDescriptor, depth + 1);
+
+        FilterBranch result = FilterBranch.andOutput(leftBranch, rightBranch, FilterBranch.COMPARE);
+        if (result == FilterBranch.NA) {
+            //If the result is NA, then we cannot push down the filter
+            return FilterBranch.NA;
+        }
+
+        boolean pushdown = true;
+        //If the value is a filterPath, means it is coming from the expression tree.
+        if (leftBranch == FilterBranch.FILTER_PATH && rightBranch == FilterBranch.FILTER_PATH) {
+            return FilterBranch.COMPARE;
+        } else if (leftBranch == FilterBranch.FILTER_PATH) {
+            // if the expression return type is an array or any, we cannot push it down
+            pushdown = !expressionReturnsArray(right, currentDescriptor.getOperator());
+        } else if (rightBranch == FilterBranch.FILTER_PATH) {
+            pushdown = !expressionReturnsArray(left, currentDescriptor.getOperator());
+        }
+
+        return pushdown ? result : FilterBranch.NA;
     }
 
     @Override
-    protected boolean handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
+    protected FilterBranch handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
             throws AlgebricksException {
         if (node.getType() != ExpectedSchemaNodeType.ANY) {
-            return false;
+            return FilterBranch.NA;
         }
         paths.put(expression, pathBuilderVisitor.buildPath((AnyExpectedSchemaNode) node));
-        return true;
+        return FilterBranch.FILTER_PATH;
     }
 
     @Override
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ColumnRangeFilterPushdownProcessor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ColumnRangeFilterPushdownProcessor.java
index 030fb6e..04a9f6d 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ColumnRangeFilterPushdownProcessor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ColumnRangeFilterPushdownProcessor.java
@@ -83,7 +83,8 @@
     }
 
     @Override
-    protected boolean handleCompare(AbstractFunctionCallExpression expression, int depth) throws AlgebricksException {
+    protected FilterBranch handleCompare(AbstractFunctionCallExpression expression, int depth,
+            UseDescriptor currentDescriptor) throws AlgebricksException {
         List<Mutable<ILogicalExpression>> args = expression.getArguments();
 
         Mutable<ILogicalExpression> leftRef = args.get(0);
@@ -98,15 +99,15 @@
             return pushdownRangeFilter(left, right, expression, false);
         }
         // Either it is a compare that doesn't involve a constant there's a function that wraps the value access path
-        return false;
+        return FilterBranch.NA;
     }
 
     @Override
-    protected boolean handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
+    protected FilterBranch handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
             throws AlgebricksException {
         // This means we got something like WHERE $r.getField("isVerified") -- where isVerified is a boolean field.
         if (node.getType() != ExpectedSchemaNodeType.ANY) {
-            return false;
+            return FilterBranch.NA;
         }
         IAObject constantValue = ABoolean.TRUE;
         String functionName = expression.getFunctionIdentifier().getName();
@@ -116,7 +117,7 @@
         ARecordType path = pathBuilderVisitor.buildPath((AnyExpectedSchemaNode) node, constantValue.getType(),
                 sourceInformationMap, functionCallInfo);
         paths.put(expression, path);
-        return true;
+        return FilterBranch.FILTER_PATH;
     }
 
     @Override
@@ -132,12 +133,12 @@
         scanDefineDescriptor.getPathLocations().putAll(sourceInformationMap);
     }
 
-    private boolean pushdownRangeFilter(ILogicalExpression pathExpr, ILogicalExpression constExpr,
+    private FilterBranch pushdownRangeFilter(ILogicalExpression pathExpr, ILogicalExpression constExpr,
             AbstractFunctionCallExpression funcExpr, boolean leftConstant) throws AlgebricksException {
         AnyExpectedSchemaNode node = getNode(pathExpr);
         IAObject constantValue = ((AsterixConstantValue) ((ConstantExpression) constExpr).getValue()).getObject();
         if (node == null || !SUPPORTED_CONSTANT_TYPES.contains(constantValue.getType().getTypeTag())) {
-            return false;
+            return FilterBranch.NA;
         }
         String functionName = funcExpr.getFunctionIdentifier().getName();
         SourceLocation sourceLocation = funcExpr.getSourceLocation();
@@ -146,7 +147,7 @@
         ARecordType path =
                 pathBuilderVisitor.buildPath(node, constantValue.getType(), sourceInformationMap, functionCallInfo);
         paths.put(pathExpr, path);
-        return true;
+        return FilterBranch.COMPARE;
     }
 
     private AnyExpectedSchemaNode getNode(ILogicalExpression expression) throws AlgebricksException {
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/DeltaTableFilterPushdownProcessor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/DeltaTableFilterPushdownProcessor.java
index 38dfde8..a5382c0 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/DeltaTableFilterPushdownProcessor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/DeltaTableFilterPushdownProcessor.java
@@ -50,15 +50,15 @@
     }
 
     @Override
-    protected boolean handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
+    protected FilterBranch handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
             throws AlgebricksException {
         if (node.getType() != ExpectedSchemaNodeType.ANY) {
-            return false;
+            return FilterBranch.NA;
         }
 
         // The inferred path from the provided expression
         ARecordType expressionPath = pathBuilderVisitor.buildPath((AnyExpectedSchemaNode) node);
         paths.put(expression, expressionPath);
-        return true;
+        return FilterBranch.FILTER_PATH;
     }
 }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ExternalDatasetFilterPushdownProcessor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ExternalDatasetFilterPushdownProcessor.java
index 37a0128..50180c4 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ExternalDatasetFilterPushdownProcessor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ExternalDatasetFilterPushdownProcessor.java
@@ -73,10 +73,10 @@
     }
 
     @Override
-    protected boolean handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
+    protected FilterBranch handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
             throws AlgebricksException {
         if (node.getType() != ExpectedSchemaNodeType.ANY) {
-            return false;
+            return FilterBranch.NA;
         }
 
         // The inferred path from the provided expression
@@ -84,8 +84,8 @@
         if (prefix.getPaths().contains(expressionPath)) {
             // The expression refer to a declared computed field. Add it to the filter paths
             paths.put(expression, expressionPath);
-            return true;
+            return FilterBranch.FILTER_PATH;
         }
-        return false;
+        return FilterBranch.NA;
     }
 }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ParquetFilterPushdownProcessor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ParquetFilterPushdownProcessor.java
index 6545964..f6c94c6 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ParquetFilterPushdownProcessor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/pushdown/processor/ParquetFilterPushdownProcessor.java
@@ -50,16 +50,16 @@
     }
 
     @Override
-    protected boolean handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
+    protected FilterBranch handlePath(AbstractFunctionCallExpression expression, IExpectedSchemaNode node)
             throws AlgebricksException {
         if (node.getType() != ExpectedSchemaNodeType.ANY) {
-            return false;
+            return FilterBranch.NA;
         }
 
         // The inferred path from the provided expression
         ARecordType expressionPath = pathBuilderVisitor.buildPath((AnyExpectedSchemaNode) node);
         paths.put(expression, expressionPath);
-        return true;
+        return FilterBranch.FILTER_PATH;
     }
 
     @Override
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.001.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.001.ddl.sqlpp
new file mode 100644
index 0000000..d327ee4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.001.ddl.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+
+USE test;
+
+CREATE COLLECTION ColumnDataset PRIMARY KEY (id: String)
+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/return-array/return-array.002.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.002.update.sqlpp
new file mode 100644
index 0000000..2c83e38
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.002.update.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * 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 test;
+
+INSERT INTO ColumnDataset ({
+     "id": "1",
+     "homo_array_field": [1, 2, 3],
+     "hetero_array_field": [1, "a", true],
+     "nested_field": {
+        "a": 1,
+        "array_field": [1, "a", true]
+     }
+});
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.003.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.003.query.sqlpp
new file mode 100644
index 0000000..5fc3361
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.003.query.sqlpp
@@ -0,0 +1,23 @@
+/*
+ * 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 test;
+
+SELECT * FROM ColumnDataset
+WHERE homo_array_field = [1, 2, 3];
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.004.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.004.query.sqlpp
new file mode 100644
index 0000000..918de5e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.004.query.sqlpp
@@ -0,0 +1,23 @@
+/*
+ * 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 test;
+
+SELECT * FROM ColumnDataset
+WHERE hetero_array_field = [1, "a", true];
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.005.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.005.query.sqlpp
new file mode 100644
index 0000000..33834dc
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.005.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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 test;
+
+SET `import-private-functions` `true`;
+
+SELECT * FROM ColumnDataset
+WHERE hetero_array_field = `ordered-list-constructor`(1, "a", true);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.006.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.006.query.sqlpp
new file mode 100644
index 0000000..6e2c9e2
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.006.query.sqlpp
@@ -0,0 +1,23 @@
+/*
+ * 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 test;
+
+SELECT * FROM ColumnDataset
+WHERE hetero_array_field = to_array([1, "a", true]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.007.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.007.query.sqlpp
new file mode 100644
index 0000000..1a717a2
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.007.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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 test;
+
+EXPLAIN
+SELECT * FROM ColumnDataset c
+WHERE c.n.x + 1 = 13;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.008.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.008.query.sqlpp
new file mode 100644
index 0000000..743069a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.008.query.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * 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 test;
+
+SET `import-private-functions` `true`;
+
+EXPLAIN
+SELECT * FROM ColumnDataset c
+WHERE `field-access-by-name`(`field-access-by-name`(c, "nested_field"), "array_field") = [1, "a", true];
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.009.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.009.query.sqlpp
new file mode 100644
index 0000000..2f2e6ad
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/column/filter/return-array/return-array.009.query.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * 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 test;
+
+SET `import-private-functions` `true`;
+
+EXPLAIN
+SELECT * FROM ColumnDataset c
+WHERE `field-access-by-name`(`field-access-by-name`(c, "nested_field"), "a") = 1;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.003.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.003.adm
new file mode 100644
index 0000000..03721c7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.003.adm
@@ -0,0 +1 @@
+{ "ColumnDataset": { "id": "1", "homo_array_field": [ 1, 2, 3 ], "hetero_array_field": [ 1, "a", true ], "nested_field": { "a": 1, "array_field": [ 1, "a", true ] } } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.004.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.004.adm
new file mode 100644
index 0000000..03721c7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.004.adm
@@ -0,0 +1 @@
+{ "ColumnDataset": { "id": "1", "homo_array_field": [ 1, 2, 3 ], "hetero_array_field": [ 1, "a", true ], "nested_field": { "a": 1, "array_field": [ 1, "a", true ] } } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.005.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.005.adm
new file mode 100644
index 0000000..03721c7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.005.adm
@@ -0,0 +1 @@
+{ "ColumnDataset": { "id": "1", "homo_array_field": [ 1, 2, 3 ], "hetero_array_field": [ 1, "a", true ], "nested_field": { "a": 1, "array_field": [ 1, "a", true ] } } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.006.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.006.adm
new file mode 100644
index 0000000..03721c7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.006.adm
@@ -0,0 +1 @@
+{ "ColumnDataset": { "id": "1", "homo_array_field": [ 1, 2, 3 ], "hetero_array_field": [ 1, "a", true ], "nested_field": { "a": 1, "array_field": [ 1, "a", true ] } } }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.007.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.007.adm
new file mode 100644
index 0000000..65a8abc
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.007.adm
@@ -0,0 +1,18 @@
+distribute result [$$18] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    assign [$$18] <- [{"c": $$c}] project: [$$18] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+    -- ASSIGN  |PARTITIONED|
+      select (eq(numeric-add($$c.getField("n").getField("x"), 1), 13)) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+      -- STREAM_SELECT  |PARTITIONED|
+        project ([$$c]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+        -- STREAM_PROJECT  |PARTITIONED|
+          exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            data-scan []<-[$$19, $$c] <- test.ColumnDataset filter on: eq(numeric-add($$c.getField("n").getField("x"), 1), 13) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.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/return-array/return-array.008.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.008.adm
new file mode 100644
index 0000000..2f65f60
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.008.adm
@@ -0,0 +1,18 @@
+distribute result [$$18] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    assign [$$18] <- [{"c": $$c}] project: [$$18] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+    -- ASSIGN  |PARTITIONED|
+      select (eq($$c.getField("nested_field").getField("array_field"), ordered-list-constructor(1, "a", true))) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+      -- STREAM_SELECT  |PARTITIONED|
+        project ([$$c]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+        -- STREAM_PROJECT  |PARTITIONED|
+          exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            data-scan []<-[$$19, $$c] <- test.ColumnDataset [cardinality: 0.0, op-cost: 0.0, total-cost: 0.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/return-array/return-array.009.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.009.adm
new file mode 100644
index 0000000..1235754
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/filter/return-array/return-array.009.adm
@@ -0,0 +1,18 @@
+distribute result [$$17] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    assign [$$17] <- [{"c": $$c}] project: [$$17] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+    -- ASSIGN  |PARTITIONED|
+      select (eq($$c.getField("nested_field").getField("a"), 1)) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+      -- STREAM_SELECT  |PARTITIONED|
+        project ([$$c]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+        -- STREAM_PROJECT  |PARTITIONED|
+          exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            data-scan []<-[$$18, $$c] <- test.ColumnDataset filter on: eq($$c.getField("nested_field").getField("a"), 1) range-filter on: eq($$c.getField("nested_field").getField("a"), 1) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.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_cbo/column/filter/return-array/return-array.007.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/return-array/return-array.007.adm
new file mode 100644
index 0000000..4c09511
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/return-array/return-array.007.adm
@@ -0,0 +1,18 @@
+distribute result [$$18] [cardinality: 0.0, op-cost: 0.0, total-cost: 1.0]
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 1.0]
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    assign [$$18] <- [{"c": $$c}] project: [$$18] [cardinality: 0.0, op-cost: 0.0, total-cost: 1.0]
+    -- ASSIGN  |PARTITIONED|
+      select (eq(numeric-add($$c.getField("n").getField("x"), 1), 13)) [cardinality: 0.0, op-cost: 0.0, total-cost: 1.0]
+      -- STREAM_SELECT  |PARTITIONED|
+        project ([$$c]) [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+        -- STREAM_PROJECT  |PARTITIONED|
+          exchange [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            data-scan []<-[$$19, $$c] <- test.ColumnDataset filter on: eq(numeric-add($$c.getField("n").getField("x"), 1), 13) [cardinality: 1.0, op-cost: 1.0, total-cost: 1.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_cbo/column/filter/return-array/return-array.008.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/return-array/return-array.008.adm
new file mode 100644
index 0000000..4f825c4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/return-array/return-array.008.adm
@@ -0,0 +1,18 @@
+distribute result [$$18] [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  exchange [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    assign [$$18] <- [{"c": $$c}] project: [$$18] [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+    -- ASSIGN  |PARTITIONED|
+      select (eq($$c.getField("nested_field").getField("array_field"), ordered-list-constructor(1, "a", true))) [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+      -- STREAM_SELECT  |PARTITIONED|
+        project ([$$c]) [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+        -- STREAM_PROJECT  |PARTITIONED|
+          exchange [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            data-scan []<-[$$19, $$c] <- test.ColumnDataset [cardinality: 1.0, op-cost: 1.0, total-cost: 1.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_cbo/column/filter/return-array/return-array.009.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/return-array/return-array.009.adm
new file mode 100644
index 0000000..7b0fd44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/filter/return-array/return-array.009.adm
@@ -0,0 +1,18 @@
+distribute result [$$17] [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  exchange [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    assign [$$17] <- [{"c": $$c}] project: [$$17] [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+    -- ASSIGN  |PARTITIONED|
+      select (eq($$c.getField("nested_field").getField("a"), 1)) [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+      -- STREAM_SELECT  |PARTITIONED|
+        project ([$$c]) [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+        -- STREAM_PROJECT  |PARTITIONED|
+          exchange [cardinality: 1.0, op-cost: 0.0, total-cost: 1.0]
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            data-scan []<-[$$18, $$c] <- test.ColumnDataset filter on: eq($$c.getField("nested_field").getField("a"), 1) range-filter on: eq($$c.getField("nested_field").getField("a"), 1) [cardinality: 1.0, op-cost: 1.0, total-cost: 1.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/sqlpp_queries.xml b/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
index 3debd6f..355019a 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
@@ -16629,6 +16629,11 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="column">
+      <compilation-unit name="filter/return-array">
+        <output-dir compare="Text">filter/return-array</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="column">
       <compilation-unit name="delete/001">
         <output-dir compare="Text">delete/001</output-dir>
       </compilation-unit>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_single_partition_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_single_partition_sqlpp.xml
index 5da5cea..4a54ce9 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_single_partition_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_single_partition_sqlpp.xml
@@ -105,6 +105,11 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="column">
+      <compilation-unit name="filter/return-array">
+        <output-dir compare="Text">filter/return-array</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="column">
       <compilation-unit name="io/flush/ASTERIXDB-3597">
         <output-dir compare="Text">io/flush/ASTERIXDB-3597</output-dir>
       </compilation-unit>