Merge branch 'gerrit/stabilization-6a10f3f81d' into 'gerrit/trinity'

Ext-ref: MB-61840
Change-Id: I5ac772b21a4cbaa2e6c1a14969149b0715508f97
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/subplan/InlineAllNtsInSubplanVisitor.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/subplan/InlineAllNtsInSubplanVisitor.java
index 55165ed..497d21c 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/subplan/InlineAllNtsInSubplanVisitor.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/subplan/InlineAllNtsInSubplanVisitor.java
@@ -592,7 +592,27 @@
 
     @Override
     public ILogicalOperator visitUnionOperator(UnionAllOperator op, Void arg) throws AlgebricksException {
-        visitMultiInputOperator(op);
+        orderingExprs.clear();
+        correlatedKeyVars.clear();
+        ILogicalOperator newChild = op.getInputs().get(0).getValue().accept(this, null);
+        op.getInputs().get(0).setValue(newChild);
+        List<LogicalVariable> leftKeyVars = new ArrayList<>(correlatedKeyVars);
+        correlatedKeyVars.clear();
+
+        newChild = op.getInputs().get(1).getValue().accept(this, null);
+        op.getInputs().get(1).setValue(newChild);
+        int i = 0;
+        for (LogicalVariable leftVar : leftKeyVars) {
+            op.addTriple(new Triple<>(leftKeyVars.get(i),
+                    subplanInputVarToCurrentVarMap.get(currentVarToSubplanInputVarMap.get(leftVar)), context.newVar()));
+            context.computeAndSetTypeEnvironmentForOperator(op);
+            i += 1;
+        }
+        if (correlatedKeyVars.isEmpty()) {
+            correlatedKeyVars.addAll(leftKeyVars);
+        }
+        subtituteVariables(op);
+
         // Update the variable mappings
         List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> varTriples = op.getVariableMappings();
         for (Triple<LogicalVariable, LogicalVariable, LogicalVariable> triple : varTriples) {
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java
index 2602917..35b4866 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java
@@ -54,11 +54,11 @@
     private final Stats stats;
     private final ARecordType recordType;
 
-    private boolean indentJSON;
-    private boolean quoteRecord;
+    private final boolean indentJSON;
+    private final boolean quoteRecord;
 
     // Whether we are wrapping the output sequence in an array
-    private boolean wrapArray = false;
+    private final boolean wrapArray;
     // Whether this is the first instance being output
     private boolean notFirst = false;
 
@@ -72,6 +72,7 @@
         this.recordType = recordType;
         this.indentJSON = conf.is(SessionConfig.FORMAT_INDENT_JSON);
         this.quoteRecord = conf.is(SessionConfig.FORMAT_QUOTE_RECORD);
+        this.wrapArray = conf.is(SessionConfig.FORMAT_WRAPPER_ARRAY);
         this.resultDisplayFrameMgr = new FrameManager(appCtx.getCompilerProperties().getFrameSize());
         if (indentJSON) {
             this.om = new ObjectMapper();
@@ -106,7 +107,6 @@
                 notfirst = true;
                 app.append('"').append(name.replace("\"", "\"\"")).append('"');
             }
-            app.append("\r\n");
         } catch (IOException e) {
             throw HyracksDataException.create(e);
         }
@@ -126,9 +126,8 @@
             throw HyracksDataException.create(e);
         }
 
-        if (conf.is(SessionConfig.FORMAT_WRAPPER_ARRAY)) {
+        if (wrapArray) {
             output.out().print("[ ");
-            wrapArray = true;
         }
 
         if (conf.fmt() == SessionConfig.OutputFormat.CSV && conf.is(SessionConfig.FORMAT_CSV_HEADER)) {
@@ -139,11 +138,13 @@
                 StringWriter sw = new StringWriter();
                 appendCSVHeader(sw, recordType);
                 output.out().print(JSONUtil.quoteAndEscape(sw.toString()));
-                output.out().print("\n");
-                notFirst = true;
             } else {
                 appendCSVHeader(output.out(), recordType);
             }
+            if (!wrapArray) {
+                output.out().println();
+            }
+            notFirst = true;
         }
     }
 
@@ -173,10 +174,6 @@
                 record = result;
             }
         }
-        if (conf.fmt() == SessionConfig.OutputFormat.CSV) {
-            // TODO(tillw): this is inefficient as well
-            record = record + "\r\n";
-        }
         if (quoteRecord) {
             // TODO(tillw): this is inefficient as well
             record = JSONUtil.quoteAndEscape(record);
@@ -210,16 +207,15 @@
                 for (int tIndex = 0; tIndex < last; tIndex++) {
                     final int start = fta.getTupleStartOffset(tIndex);
                     int length = fta.getTupleEndOffset(tIndex) - start;
-                    if (conf.fmt() == SessionConfig.OutputFormat.CSV
-                            && ((length > 0) && (frameBytes[start + length - 1] == '\n'))) {
-                        length--;
-                    }
                     String result = new String(frameBytes, start, length, UTF_8);
                     if (wrapArray && notFirst) {
-                        output.out().print(", ");
+                        output.out().print(',');
                     }
                     notFirst = true;
                     displayRecord(result);
+                    if (!wrapArray) {
+                        output.out().println();
+                    }
                 }
                 frameBuffer.clear();
             }
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java
index 05b8bbf..ac85052 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/ResultExtractor.java
@@ -219,6 +219,7 @@
         }
 
         final boolean isJsonFormat = isJsonFormat(fmt);
+        boolean firstResult = true;
 
         // if we have errors field in the results, we will always return it
         checkForErrors(result);
@@ -235,6 +236,10 @@
             final JsonNode fieldValue = result.get(fieldName);
             switch (fieldKind) {
                 case RESULTS:
+                    if (!firstResult) {
+                        resultBuilder.append('\n');
+                    }
+                    firstResult = false;
                     if (fieldValue.size() <= 1) {
                         if (fieldValue.size() == 0) {
                             resultBuilder.append("");
@@ -257,7 +262,7 @@
                         } else {
                             for (JsonNode f : fields) {
                                 if (f.isValueNode()) {
-                                    resultBuilder.append(f.asText());
+                                    resultBuilder.append(f.asText()).append('\n');
                                 } else {
                                     resultBuilder.append(prettyPrint(f)).append('\n');
                                 }
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index 04da930..abfc9cc 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -357,6 +357,9 @@
             } else if (actualFile.toString().endsWith(".plan")) {
                 runScriptAndCompareWithResultPlan(scriptFile, readerExpected, readerActual);
                 return;
+            } else if (actualFile.toString().endsWith(".jsonl")) {
+                runScriptAndCompareWithResultJsonl(scriptFile, readerExpected, readerActual, statement);
+                return;
             }
 
             String lineExpected, lineActual;
@@ -634,6 +637,49 @@
         }
     }
 
+    private static void runScriptAndCompareWithResultJsonl(File scriptFile, BufferedReader readerExpected,
+            BufferedReader readerActual, String statement) throws ComparisonException, IOException {
+        List<String> expectedLines = readerExpected.lines().collect(Collectors.toList());
+        List<String> actualLines = readerActual.lines().collect(Collectors.toList());
+        boolean compareUnorderedArray = statement != null && getCompareUnorderedArray(statement);
+        boolean ignoreExtraFields = statement != null && getIgnoreExtraFields(statement);
+
+        JsonNode expectedJson, actualJson;
+        int i = 0;
+        for (String expectedLine : expectedLines) {
+            if (actualLines.size() <= i) {
+                throw new ComparisonException("Result for " + canonicalize(scriptFile) + " expected json line at " + i
+                        + " not found: " + truncateIfLong(expectedLine));
+            }
+            String actualLine = actualLines.get(i);
+            i += 1;
+            try {
+                expectedJson = SINGLE_JSON_NODE_READER.readTree(expectedLine);
+            } catch (JsonProcessingException e) {
+                throw new ComparisonException("Invalid expected JSON for: " + scriptFile, e);
+            }
+            try {
+                actualJson = SINGLE_JSON_NODE_READER.readTree(actualLine);
+            } catch (JsonProcessingException e) {
+                throw new ComparisonException("Invalid actual JSON for: " + scriptFile, e);
+            }
+            if (expectedJson == null) {
+                throw new ComparisonException("No expected result for: " + scriptFile);
+            } else if (actualJson == null) {
+                throw new ComparisonException("No actual result for: " + scriptFile);
+            }
+            if (!TestHelper.equalJson(expectedJson, actualJson, compareUnorderedArray, ignoreExtraFields, false,
+                    null)) {
+                throw new ComparisonException("Result for " + scriptFile + " didn't match the expected JSON"
+                        + "\nexpected result:\n" + expectedJson + "\nactual result:\n" + actualJson);
+            }
+        }
+        if (actualLines.size() > i) {
+            throw new ComparisonException("Result for " + canonicalize(scriptFile) + " extra json line at " + i
+                    + " found: " + truncateIfLong(actualLines.get(i)));
+        }
+    }
+
     public void runScriptAndCompareWithResultUnorderedLinesText(File scriptFile, BufferedReader readerExpected,
             BufferedReader readerActual) throws Exception {
         // Using Lists to allow duplicate lines in the result
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.1.ddl.sqlpp
new file mode 100644
index 0000000..774e8a8
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.1.ddl.sqlpp
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description: This test case is to verify the fix for ASTERIXDB-3415
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+
+use test;
+
+create type dt1 as {id:int};
+create dataset collection1(dt1) primary key id;
+create dataset collection2(dt1) primary key id;
+create dataset collection3(dt1) primary key id;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.2.update.sqlpp
new file mode 100644
index 0000000..581408f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.2.update.sqlpp
@@ -0,0 +1,67 @@
+/*
+ * 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 collection1
+([
+    {
+      "id": 1,
+      "f1": "f1"
+    },
+    {
+        "id": 2,
+        "f1": "f1"
+    },
+    {
+      "id": 3,
+      "f1": "f1"
+    }
+]);
+insert into collection2
+([
+    {
+      "id": 1,
+      "f2": "f2"
+    },
+    {
+        "id": 2,
+        "f2": "f2"
+    },
+    {
+      "id": 3,
+      "f2": "f2"
+    }
+]);
+insert into collection3
+([
+    {
+      "id": 1,
+      "f1": "f1",
+      "items": [2, 4]
+
+    },
+    {
+        "id": 2,
+        "f1": "f1",
+        "items": [1]
+    }
+]);
+
+
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.3.query.sqlpp
new file mode 100644
index 0000000..517000d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.3.query.sqlpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description: This test case is to verify the fix for ASTERIXDB-3415
+ */
+-- compareunorderedarray=true
+use test;
+
+SELECT (
+  SELECT c1.f1
+  FROM collection1 AS c1
+  WHERE c1.id IN c3.items
+  UNION ALL
+  SELECT c2.f2
+  FROM collection2 c2 )
+FROM collection3 AS c3
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.4.query.sqlpp
new file mode 100644
index 0000000..9c1fa2f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.4.query.sqlpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description: This test case is to verify the fix for ASTERIXDB-3415
+ */
+-- compareunorderedarray=true
+use test;
+
+SELECT (
+  SELECT c1.f1
+  FROM collection1 AS c1
+  WHERE c1.id = c3.x
+  UNION ALL
+  SELECT c2.f2
+  FROM collection2 c2 )
+FROM collection3 AS c3
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.1.query.sqlpp
new file mode 100644
index 0000000..3c4bc57
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.1.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.
+ */
+
+/*
+ * Description: This test case is to verify the fix for ASTERIXDB-3481
+ */
+
+select array_count(n) from [{"n":[null]},{"n":[null,null]}] as l;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.2.query.sqlpp
new file mode 100644
index 0000000..8bdfcfb
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.2.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.
+ */
+
+/*
+ * Description: This test case is to verify the fix for ASTERIXDB-3481
+ */
+
+select array_count(n) from [{"n":[null, 1]},{"n":[null,null, 2]}] as l;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.3.query.sqlpp
new file mode 100644
index 0000000..c6718c6
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.3.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.
+ */
+
+/*
+ * Description: This test case is to verify the fix for ASTERIXDB-3481
+ */
+
+select array_count(n) from [{"n":[]},{"n":[]}] as l;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.4.query.sqlpp
new file mode 100644
index 0000000..5ed68f8
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.4.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.
+ */
+
+/*
+ * Description: This test case is to verify the fix for ASTERIXDB-3481
+ */
+
+select array_count(n) from [{"n":[null,null,null,null,null,null,null,null,null,null]},{"n":[null,null,null,null,null,null,null,null,null,null]}] as l;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cache-residency/cache-residency.001.regexjson b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cache-residency/cache-residency.001.regexjson
index 173a9a5..628e8b0 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cache-residency/cache-residency.001.regexjson
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cache-residency/cache-residency.001.regexjson
@@ -4,7 +4,7 @@
 		"*": "*"
 	},
 	"type": "application/x-adm",
-	"results": [ "{ \"v\": 1 }\n", "{ \"v\": 2 }\n" ],
+	"results": [ "{ \"v\": 1 }", "{ \"v\": 2 }" ],
 	"plans": "R{.*}",
 	"status": "success",
 	"metrics": {
@@ -13,7 +13,7 @@
 		"compileTime": "R{.*}",
 		"queueWaitTime": "R{.*}",
 		"resultCount": 2,
-		"resultSize": 32,
+		"resultSize": "R{.*}",
 		"processedObjects": 0
 	}
 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cache-residency/cache-residency.002.regexjson b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cache-residency/cache-residency.002.regexjson
index 8f5cf76..a041778 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cache-residency/cache-residency.002.regexjson
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cache-residency/cache-residency.002.regexjson
@@ -4,7 +4,7 @@
 		"*": "*"
 	},
 	"type": "application/x-adm",
-	"results": [ "{ \"$1\": 17 }\n" ],
+	"results": [ "{ \"$1\": 17 }" ],
 	"plans": "R{.*}",
 	"status": "success",
 	"metrics": {
@@ -13,7 +13,7 @@
 		"compileTime": "R{.*}",
 		"queueWaitTime": "R{.*}",
 		"resultCount": 1,
-		"resultSize": 18,
+		"resultSize": "R{.*}",
 		"processedObjects": 17,
 		"bufferCacheHitRatio": "100.00%"
 	}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/format-param-in-accept-01/format-param-in-accept-01.1.regexjson b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/format-param-in-accept-01/format-param-in-accept-01.1.regexjson
index ad8ba0a..0134449 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/format-param-in-accept-01/format-param-in-accept-01.1.regexjson
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/format-param-in-accept-01/format-param-in-accept-01.1.regexjson
@@ -2,7 +2,7 @@
 	"requestID": "R{[a-zA-Z0-9-]+}",
 	"signature": {"*": "*"},
 	"type": "application/x-adm",
-	"results": [ "{{ \"foo\", \"bar\" }}\n" ],
+	"results": [ "{{ \"foo\", \"bar\" }}" ],
 	"plans":{},
 	"status": "success",
     "metrics": "R{.*}"
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/multiple-param-values/multiple-param-values.1.regexjson b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/multiple-param-values/multiple-param-values.1.regexjson
index 0701ef3..aab9677 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/multiple-param-values/multiple-param-values.1.regexjson
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/multiple-param-values/multiple-param-values.1.regexjson
@@ -4,7 +4,7 @@
 		"*": "*"
 	},
 	"type": "application/x-adm",
-	"results": [ "{ \"$1\": 1 }\n" ]
+	"results": [ "{ \"$1\": 1 }" ]
 	,
 	"plans":{},
 	"status": "success",
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.3.jsonl b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.3.jsonl
new file mode 100644
index 0000000..211c0b0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.3.jsonl
@@ -0,0 +1,2 @@
+{ "$1": [ { "f2": "f2" }, { "f2": "f2" }, { "f2": "f2" }, { "f1": "f1" } ] }
+{ "$1": [ { "f2": "f2" }, { "f2": "f2" }, { "f2": "f2" }, { "f1": "f1" } ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.4.jsonl b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.4.jsonl
new file mode 100644
index 0000000..b28825f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3415/query-ASTERIXDB-3415.4.jsonl
@@ -0,0 +1,2 @@
+{ "$1": [ { "f2": "f2" }, { "f2": "f2" }, { "f2": "f2" } ] }
+{ "$1": [ { "f2": "f2" }, { "f2": "f2" }, { "f2": "f2" } ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.1.adm
new file mode 100644
index 0000000..ea969a1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.1.adm
@@ -0,0 +1,2 @@
+{ "$1": 0 }
+{ "$1": 0 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.2.adm
new file mode 100644
index 0000000..fbe6803
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.2.adm
@@ -0,0 +1,2 @@
+{ "$1": 1 }
+{ "$1": 1 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.3.adm
new file mode 100644
index 0000000..ea969a1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.3.adm
@@ -0,0 +1,2 @@
+{ "$1": 0 }
+{ "$1": 0 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.4.adm
new file mode 100644
index 0000000..ea969a1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-3481/query-ASTERIXDB-3481.4.adm
@@ -0,0 +1,2 @@
+{ "$1": 0 }
+{ "$1": 0 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.03.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.03.regexadm
index bd85d0e..5c091b4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.03.regexadm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.03.regexadm
@@ -3,21 +3,7 @@
 \s*\Q"signature": {\E
 \s*\Q"*": "*"\E
 \s*\Q},\E
-\s*\Q"results": [ { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q]\E
+\s*\Q"results": [ {"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null} ]\E
 \s*\Q,\E
 \s*\Q"plans":{},\E
 \s*\Q"warnings": [{\E\s*
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.04.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.04.regexadm
index dce84fe..a0d6601 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.04.regexadm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.04.regexadm
@@ -3,21 +3,7 @@
 \s*\Q"signature": {\E
 \s*\Q"*": "*"\E
 \s*\Q},\E
-\s*\Q"results": [ { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q]\E
+\s*\Q"results": [ {"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null} ]\E
 \s*\Q,\E
 \s*\Q"plans":{},\E
 \s*\Q"status": "success",\E
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.05.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.05.regexadm
index 6b1931a..ac945a7 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.05.regexadm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.05.regexadm
@@ -3,21 +3,7 @@
 \s*\Q"signature": {\E
 \s*\Q"*": "*"\E
 \s*\Q},\E
-\s*\Q"results": [ { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q]\E
+\s*\Q"results": [ {"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null} ]\E
 \s*\Q,\E
 \s*\Q"plans":{},\E
 \s*\Q"status": "success",\E
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.07.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.07.regexadm
index 6b1931a..ac945a7 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.07.regexadm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.07.regexadm
@@ -3,21 +3,7 @@
 \s*\Q"signature": {\E
 \s*\Q"*": "*"\E
 \s*\Q},\E
-\s*\Q"results": [ { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q]\E
+\s*\Q"results": [ {"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null} ]\E
 \s*\Q,\E
 \s*\Q"plans":{},\E
 \s*\Q"status": "success",\E
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.08.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.08.regexadm
index bd85d0e..5c091b4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.08.regexadm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/warnings/warnings-limit/warnings-limit.08.regexadm
@@ -3,21 +3,7 @@
 \s*\Q"signature": {\E
 \s*\Q"*": "*"\E
 \s*\Q},\E
-\s*\Q"results": [ { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": false }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q, { "F1": { "a": 1 }, "F2": null }\E
-\s*\Q]\E
+\s*\Q"results": [ {"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":false},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null},{"F1":{"a":1},"F2":null} ]\E
 \s*\Q,\E
 \s*\Q"plans":{},\E
 \s*\Q"warnings": [{\E\s*
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 515e765..845fca3 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -7335,6 +7335,16 @@
         <output-dir compare="Text">query-ASTERIXDB-3403</output-dir>
       </compilation-unit>
     </test-case>
+    <test-case FilePath="misc">
+      <compilation-unit name="query-ASTERIXDB-3415">
+        <output-dir compare="Text">query-ASTERIXDB-3415</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="misc">
+      <compilation-unit name="query-ASTERIXDB-3481">
+          <output-dir compare="Text">query-ASTERIXDB-3481</output-dir>
+      </compilation-unit>
+    </test-case>
   </test-group>
   <test-group name="multipart-dataverse">
     <test-case FilePath="multipart-dataverse">
@@ -14181,7 +14191,7 @@
     <test-case FilePath="meta">
       <compilation-unit name="meta_after_gby">
         <output-dir compare="Text">meta_after_gby</output-dir>
-        <expected-error>Compilation error: Inappropriate use of function 'meta'. For example, after GROUP BY (in line 29, at column 21)</expected-error>
+        <expected-error>Compilation error: No source collection found for META(): collection not supported or cannot reference collection (in line 29, at column 21)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="meta">
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp_profiled.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp_profiled.xml
index c22d6d0..1972596 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp_profiled.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp_profiled.xml
@@ -13994,7 +13994,7 @@
     <test-case FilePath="meta">
       <compilation-unit name="meta_after_gby">
         <output-dir compare="Text">meta_after_gby</output-dir>
-        <expected-error>Compilation error: Inappropriate use of function 'meta'. For example, after GROUP BY (in line 29, at column 21)</expected-error>
+        <expected-error>Compilation error: No source collection found for META(): collection not supported or cannot reference collection (in line 29, at column 21)</expected-error>
       </compilation-unit>
     </test-case>
     <test-case FilePath="meta">
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AOrderedListSerializerDeserializer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AOrderedListSerializerDeserializer.java
index e443e13..7c49662 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AOrderedListSerializerDeserializer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AOrderedListSerializerDeserializer.java
@@ -90,6 +90,9 @@
                     }
                 }
                 for (int i = 0; i < numberOfitems; i++) {
+                    if (isNullMissingTagWritten(typeTag)) {
+                        in.readByte();
+                    }
                     IAObject v = (IAObject) currentDeserializer.deserialize(in);
                     items.add(v);
                 }
@@ -101,6 +104,12 @@
         }
     }
 
+    private boolean isNullMissingTagWritten(ATypeTag serializedTypeTag) {
+        ATypeTag itemTypeTag = itemType.getTypeTag();
+        boolean toWriteTag = itemTypeTag == ATypeTag.NULL && serializedTypeTag == ATypeTag.NULL;
+        return toWriteTag || (itemTypeTag == ATypeTag.MISSING && serializedTypeTag == ATypeTag.MISSING);
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     public void serialize(AOrderedList instance, DataOutput out) throws HyracksDataException {
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AUnorderedListSerializerDeserializer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AUnorderedListSerializerDeserializer.java
index b5165d2..b8ae18d 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AUnorderedListSerializerDeserializer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/nontagged/serde/AUnorderedListSerializerDeserializer.java
@@ -92,6 +92,9 @@
                     }
                 }
                 for (int i = 0; i < numberOfitems; i++) {
+                    if (isNullMissingTagWritten(typeTag)) {
+                        in.readByte();
+                    }
                     items.add((IAObject) currentDeserializer.deserialize(in));
                 }
             }
@@ -102,6 +105,12 @@
         }
     }
 
+    private boolean isNullMissingTagWritten(ATypeTag serializedTypeTag) {
+        ATypeTag itemTypeTag = itemType.getTypeTag();
+        boolean toWriteTag = itemTypeTag == ATypeTag.NULL && serializedTypeTag == ATypeTag.NULL;
+        return toWriteTag || (itemTypeTag == ATypeTag.MISSING && serializedTypeTag == ATypeTag.MISSING);
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     public void serialize(AUnorderedList instance, DataOutput out) throws HyracksDataException {
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/printer/json/clean/APrintVisitor.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/printer/json/clean/APrintVisitor.java
index 76768aa..f7acb96 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/printer/json/clean/APrintVisitor.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/printer/json/clean/APrintVisitor.java
@@ -38,12 +38,12 @@
 public class APrintVisitor extends AbstractPrintVisitor {
     @Override
     protected AListPrinter createListPrinter(AListVisitablePointable accessor) {
-        return new AListPrinter("[ ", " ]", ", ");
+        return new AListPrinter("[", "]", ",");
     }
 
     @Override
     protected ARecordPrinter createRecordPrinter(ARecordVisitablePointable accessor) {
-        return new ARecordPrinter("{ ", " }", ", ", ": ");
+        return new ARecordPrinter("{", "}", ",", ":");
     }
 
     @Override
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/printer/json/losslessadm/APrintVisitor.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/printer/json/losslessadm/APrintVisitor.java
index 025590b..0decbaa 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/printer/json/losslessadm/APrintVisitor.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/printer/json/losslessadm/APrintVisitor.java
@@ -39,7 +39,7 @@
 
     @Override
     protected AListPrinter createListPrinter(AListVisitablePointable accessor) {
-        return new AListPrinter("[ ", " ]", ", ") {
+        return new AListPrinter("[", "]", ",") {
             @Override
             protected ATypeTag getItemTypeTag(IVisitablePointable item, ATypeTag typeTag) {
                 // avoid MISSING to NULL conversion, because we print MISSING as is in this format
@@ -50,7 +50,7 @@
 
     @Override
     protected ARecordPrinter createRecordPrinter(ARecordVisitablePointable accessor) {
-        return new ARecordPrinter("{ ", " }", ", ", ": ") {
+        return new ARecordPrinter("{", "}", ",", ":") {
             @Override
             protected void printFieldName(PrintStream ps, IPrintVisitor visitor, IVisitablePointable fieldName)
                     throws HyracksDataException {
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionManager.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionManager.java
index 7158558..d58eeeb 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionManager.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionManager.java
@@ -65,9 +65,11 @@
         Pair<FunctionIdentifier, Integer> key = new Pair<>(fid, fid.getArity());
         IFunctionDescriptorFactory factory = functions.get(key);
         if (factory == null) {
-            String msg = "Inappropriate use of function '" + fid.getName() + "'";
+            String msg;
             if (fid.equals(BuiltinFunctions.META)) {
-                msg = msg + ". For example, after GROUP BY";
+                msg = "No source collection found for META(): collection not supported or cannot reference collection";
+            } else {
+                msg = "Could not resolve function '" + fid.getName() + "'";
             }
             throw AsterixException.create(ErrorCode.COMPILATION_ERROR, src, msg);
         }
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnionAllOperator.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnionAllOperator.java
index 45c6e2f..4d227ea 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnionAllOperator.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/UnionAllOperator.java
@@ -41,6 +41,10 @@
         this.varMap = varMap;
     }
 
+    public void addTriple(Triple<LogicalVariable, LogicalVariable, LogicalVariable> triple) {
+        varMap.add(triple);
+    }
+
     public List<Triple<LogicalVariable, LogicalVariable, LogicalVariable>> getVariableMappings() {
         return varMap;
     }
diff --git a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonOperatorsRule.java b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonOperatorsRule.java
index fba095a..14a44ac 100644
--- a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonOperatorsRule.java
+++ b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/ExtractCommonOperatorsRule.java
@@ -36,12 +36,14 @@
 import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.base.PhysicalOperatorTag;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractReplicateOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.ExchangeOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
+import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnionAllOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.IsomorphismUtilities;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
 import org.apache.hyracks.algebricks.core.algebra.operators.physical.AssignPOperator;
@@ -147,6 +149,63 @@
         return changed;
     }
 
+    // Check for a special case (ASTERIXDB-3415) to avoid adding Replicate Operator
+    // that causes hang during execution of the plan.
+    private boolean isUnionAllSink(List<Mutable<ILogicalOperator>> group) {
+        if (group.size() != 2) {
+            return false;
+        }
+        List<Pair<Mutable<ILogicalOperator>, Integer>> operators = new ArrayList<>();
+        if (childrenToParents.containsKey(group.get(0))) {
+            for (Mutable<ILogicalOperator> op : childrenToParents.get(group.get(0))) {
+                operators.add(new Pair<>(op, 0));
+            }
+        } else {
+            return false;
+        }
+        List<Pair<Mutable<ILogicalOperator>, Integer>> unionAllOps = new ArrayList<>();
+        while (operators.size() > 0) {
+            Pair<Mutable<ILogicalOperator>, Integer> entry = operators.remove(0);
+            if (entry.first.getValue() instanceof UnionAllOperator) {
+                unionAllOps.add(entry);
+            } else if (entry.first.getValue() instanceof ExchangeOperator && ((ExchangeOperator) entry.first.getValue())
+                    .getPhysicalOperator().getOperatorTag() == PhysicalOperatorTag.HASH_PARTITION_EXCHANGE) {
+                entry.second += 1;
+            }
+            if (childrenToParents.containsKey(entry.first)) {
+                for (Mutable<ILogicalOperator> op : childrenToParents.get(entry.first)) {
+                    operators.add(new Pair<>(op, entry.second));
+                }
+            }
+        }
+        if (childrenToParents.containsKey(group.get(1))) {
+            for (Mutable<ILogicalOperator> op : childrenToParents.get(group.get(1))) {
+                operators.add(new Pair<>(op, 0));
+            }
+        } else {
+            return false;
+        }
+        while (operators.size() > 0) {
+            Pair<Mutable<ILogicalOperator>, Integer> entry = operators.remove(0);
+            if (entry.first.getValue() instanceof UnionAllOperator) {
+                for (Pair<Mutable<ILogicalOperator>, Integer> unionAllOp : unionAllOps) {
+                    if (unionAllOp.first.equals(entry.first) && unionAllOp.second + entry.second == 1) {
+                        return true;
+                    }
+                }
+            } else if (entry.first.getValue() instanceof ExchangeOperator && ((ExchangeOperator) entry.first.getValue())
+                    .getPhysicalOperator().getOperatorTag() == PhysicalOperatorTag.HASH_PARTITION_EXCHANGE) {
+                entry.second += 1;
+            }
+            if (childrenToParents.containsKey(entry.first)) {
+                for (Mutable<ILogicalOperator> op : childrenToParents.get(entry.first)) {
+                    operators.add(new Pair<>(op, entry.second));
+                }
+            }
+        }
+        return false;
+    }
+
     private boolean rewriteForOneEquivalentClass(List<Mutable<ILogicalOperator>> members, IOptimizationContext context)
             throws AlgebricksException {
         List<Mutable<ILogicalOperator>> group = new ArrayList<>();
@@ -163,7 +222,7 @@
                 }
             }
             boolean[] materializationFlags = computeMaterilizationFlags(group);
-            if (group.isEmpty()) {
+            if (group.isEmpty() || isUnionAllSink(group)) {
                 continue;
             }
             candidate = group.get(0);
diff --git a/hyracks-fullstack/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/writers/PrinterBasedWriterFactory.java b/hyracks-fullstack/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/writers/PrinterBasedWriterFactory.java
index 015ce73..6fcbdce 100644
--- a/hyracks-fullstack/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/writers/PrinterBasedWriterFactory.java
+++ b/hyracks-fullstack/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/writers/PrinterBasedWriterFactory.java
@@ -61,11 +61,10 @@
                             + tAccess.getFieldStartOffset(tIdx, fields[i]);
                     int fldLen = tAccess.getFieldLength(tIdx, fields[i]);
                     if (i > 0) {
-                        printStream.print("; ");
+                        printStream.print(';');
                     }
                     printers[i].print(tAccess.getBuffer().array(), fldStart, fldLen, printStream);
                 }
-                printStream.println();
             }
         };
     }
diff --git a/hyracks-fullstack/algebricks/algebricks-tests/src/test/java/org/apache/hyracks/algebricks/tests/pushruntime/PushRuntimeTest.java b/hyracks-fullstack/algebricks/algebricks-tests/src/test/java/org/apache/hyracks/algebricks/tests/pushruntime/PushRuntimeTest.java
index d23f7f9..9265f52 100644
--- a/hyracks-fullstack/algebricks/algebricks-tests/src/test/java/org/apache/hyracks/algebricks/tests/pushruntime/PushRuntimeTest.java
+++ b/hyracks-fullstack/algebricks/algebricks-tests/src/test/java/org/apache/hyracks/algebricks/tests/pushruntime/PushRuntimeTest.java
@@ -178,7 +178,7 @@
 
         StringBuilder buf = new StringBuilder();
         readFileToString(outFile, buf);
-        Assert.assertEquals("400; 3", buf.toString());
+        Assert.assertEquals("400;3", buf.toString());
         outFile.delete();
     }
 
@@ -570,7 +570,7 @@
 
         StringBuilder buf = new StringBuilder();
         readFileToString(outFile, buf);
-        Assert.assertEquals("400; 3", buf.toString());
+        Assert.assertEquals("400;3", buf.toString());
         outFile.delete();
     }
 
@@ -796,9 +796,9 @@
         RecordDescriptor sortDesc = scannerDesc;
 
         String fileName = "scanMicroSortWrite.out";
-        String filePath = PATH_ACTUAL + SEPARATOR + fileName;
-        String resultFilePath = PATH_EXPECTED + SEPARATOR + fileName;
-        File outFile = new File(filePath);
+        String actualFilePath = PATH_ACTUAL + SEPARATOR + fileName;
+        String expectedFilePath = PATH_EXPECTED + SEPARATOR + fileName;
+        File outFile = new File(actualFilePath);
         SinkWriterRuntimeFactory writer = new SinkWriterRuntimeFactory(new int[] { 0, 1, 2, 3 },
                 new IPrinterFactory[] { IntegerPrinterFactory.INSTANCE, UTF8StringPrinterFactory.INSTANCE,
                         IntegerPrinterFactory.INSTANCE, UTF8StringPrinterFactory.INSTANCE },
@@ -814,7 +814,7 @@
         spec.addRoot(algebricksOp);
         AlgebricksHyracksIntegrationUtil.runJob(spec);
 
-        compareFiles(filePath, resultFilePath);
+        compareFiles(expectedFilePath, actualFilePath);
         outFile.delete();
     }
 
diff --git a/hyracks-fullstack/algebricks/algebricks-tests/src/test/resources/results/scanMicroSortWrite.out b/hyracks-fullstack/algebricks/algebricks-tests/src/test/resources/results/scanMicroSortWrite.out
index 1c0fd6a..978196c 100644
--- a/hyracks-fullstack/algebricks/algebricks-tests/src/test/resources/results/scanMicroSortWrite.out
+++ b/hyracks-fullstack/algebricks/algebricks-tests/src/test/resources/results/scanMicroSortWrite.out
@@ -1,25 +1 @@
-0; "ALGERIA"; 0; " haggle. carefully final deposits detect slyly agai"
-1; "ARGENTINA"; 1; "al foxes promise slyly according to the regular accounts. bold requests alon"
-2; "BRAZIL"; 1; "y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special "
-3; "CANADA"; 1; "eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold"
-18; "CHINA"; 2; "c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos"
-4; "EGYPT"; 4; "y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d"
-5; "ETHIOPIA"; 0; "ven packages wake quickly. regu"
-6; "FRANCE"; 3; "refully final requests. regular, ironi"
-7; "GERMANY"; 3; "l platelets. regular accounts x-ray: unusual, regular acco"
-8; "INDIA"; 2; "ss excuses cajole slyly across the packages. deposits print aroun"
-9; "INDONESIA"; 2; " slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull"
-10; "IRAN"; 4; "efully alongside of the slyly final dependencies. "
-11; "IRAQ"; 4; "nic deposits boost atop the quickly final requests? quickly regula"
-12; "JAPAN"; 2; "ously. final, express gifts cajole a"
-13; "JORDAN"; 4; "ic deposits are blithely about the carefully regular pa"
-14; "KENYA"; 0; " pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t"
-15; "MOROCCO"; 0; "rns. blithely bold courts among the closely regular packages use furiously bold platelets?"
-16; "MOZAMBIQUE"; 0; "s. ironic, unusual asymptotes wake blithely r"
-17; "PERU"; 1; "platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun"
-19; "ROMANIA"; 3; "ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account"
-22; "RUSSIA"; 3; " requests against the platelets use never according to the quickly regular pint"
-20; "SAUDI ARABIA"; 4; "ts. silent requests haggle. closely express packages sleep across the blithely"
-23; "UNITED KINGDOM"; 3; "eans boost carefully special requests. accounts are. carefull"
-24; "UNITED STATES"; 1; "y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be"
-21; "VIETNAM"; 2; "hely enticingly express accounts. even, final "
+0;"ALGERIA";0;" haggle. carefully final deposits detect slyly agai"1;"ARGENTINA";1;"al foxes promise slyly according to the regular accounts. bold requests alon"2;"BRAZIL";1;"y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special "3;"CANADA";1;"eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold"18;"CHINA";2;"c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos"4;"EGYPT";4;"y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d"5;"ETHIOPIA";0;"ven packages wake quickly. regu"6;"FRANCE";3;"refully final requests. regular, ironi"7;"GERMANY";3;"l platelets. regular accounts x-ray: unusual, regular acco"8;"INDIA";2;"ss excuses cajole slyly across the packages. deposits print aroun"9;"INDONESIA";2;" slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull"10;"IRAN";4;"efully alongside of the slyly final dependencies. "11;"IRAQ";4;"nic deposits boost atop the quickly final requests? quickly regula"12;"JAPAN";2;"ously. final, express gifts cajole a"13;"JORDAN";4;"ic deposits are blithely about the carefully regular pa"14;"KENYA";0;" pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t"15;"MOROCCO";0;"rns. blithely bold courts among the closely regular packages use furiously bold platelets?"16;"MOZAMBIQUE";0;"s. ironic, unusual asymptotes wake blithely r"17;"PERU";1;"platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun"19;"ROMANIA";3;"ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account"22;"RUSSIA";3;" requests against the platelets use never according to the quickly regular pint"20;"SAUDI ARABIA";4;"ts. silent requests haggle. closely express packages sleep across the blithely"23;"UNITED KINGDOM";3;"eans boost carefully special requests. accounts are. carefull"24;"UNITED STATES";1;"y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be"21;"VIETNAM";2;"hely enticingly express accounts. even, final "
\ No newline at end of file
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
index d6698fe..a386ab8 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
@@ -34,6 +34,7 @@
 import java.util.TimerTask;
 import java.util.TreeMap;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 import org.apache.hyracks.api.application.IApplication;
 import org.apache.hyracks.api.application.ICCApplication;
@@ -78,6 +79,7 @@
 import org.apache.hyracks.control.common.ipc.CCNCFunctions;
 import org.apache.hyracks.control.common.logs.LogFile;
 import org.apache.hyracks.control.common.shutdown.ShutdownRun;
+import org.apache.hyracks.control.common.utils.HyracksThreadFactory;
 import org.apache.hyracks.control.common.work.WorkQueue;
 import org.apache.hyracks.ipc.api.IIPCI;
 import org.apache.hyracks.ipc.impl.IPCSystem;
@@ -118,7 +120,7 @@
 
     private final WorkQueue workQueue;
 
-    private ExecutorService executor;
+    private ExecutorService executor = Executors.newCachedThreadPool(new HyracksThreadFactory("<bootstrap>"));
 
     private final Timer timer;
 
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
index e173dcb..f3df6a8 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NodeControllerService.java
@@ -35,6 +35,7 @@
 import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
@@ -72,6 +73,7 @@
 import org.apache.hyracks.control.common.ipc.CCNCFunctions;
 import org.apache.hyracks.control.common.ipc.ClusterControllerRemoteProxy;
 import org.apache.hyracks.control.common.job.profiling.om.JobProfile;
+import org.apache.hyracks.control.common.utils.HyracksThreadFactory;
 import org.apache.hyracks.control.common.work.FutureValue;
 import org.apache.hyracks.control.common.work.WorkQueue;
 import org.apache.hyracks.control.nc.application.NCServiceContext;
@@ -145,7 +147,7 @@
 
     private final Map<JobId, JobParameterByteStore> jobParameterByteStoreMap = new HashMap<>();
 
-    private ExecutorService executor;
+    private ExecutorService executor = Executors.newCachedThreadPool(new HyracksThreadFactory("<bootstrap>"));
 
     private Map<CcId, HeartbeatManager> heartbeatManagers = new ConcurrentHashMap<>();
 
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
index 9f01123..a841484 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
@@ -30,6 +30,7 @@
 import java.util.OptionalDouble;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -236,7 +237,8 @@
         try {
             return readFuture.get();
         } catch (InterruptedException ex) { // NOSONAR -- interrupt or rethrow
-            executor.submit(() -> {
+            // we don't use the executor here, since it might be shutting down- this avoids ugly logging at shutdown
+            ForkJoinPool.commonPool().submit(() -> {
                 try {
                     response.close();
                 } catch (IOException e) {