Allow Project Runtime to Pass Through an Empty Frame

Before this change, project runtime expects at least a single record.
Now it can also process an empty frame.

Change-Id: I87dc6eb83a748f7f91610e7d11ebaec9be914e29
Reviewed-on: https://asterix-gerrit.ics.uci.edu/634
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: abdullah alamoudi <bamousaa@gmail.com>
diff --git a/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/operators/std/StreamProjectRuntimeFactory.java b/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/operators/std/StreamProjectRuntimeFactory.java
index 001a5982..43c63b5 100644
--- a/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/operators/std/StreamProjectRuntimeFactory.java
+++ b/algebricks/algebricks-runtime/src/main/java/org/apache/hyracks/algebricks/runtime/operators/std/StreamProjectRuntimeFactory.java
@@ -65,23 +65,26 @@
 
             @Override
             public void nextFrame(ByteBuffer buffer) throws HyracksDataException {
+                // what if numOfTuples is 0?
                 tAccess.reset(buffer);
                 int nTuple = tAccess.getTupleCount();
-
-                int t = 0;
-                if (nTuple > 1) {
-                    for (; t < nTuple - 1; t++) {
+                if (nTuple == 0) {
+                    appender.flush(writer);
+                } else {
+                    int t = 0;
+                    if (nTuple > 1) {
+                        for (; t < nTuple - 1; t++) {
+                            appendProjectionToFrame(t, projectionList);
+                        }
+                    }
+                    if (flushFramesRapidly) {
+                        // Whenever all the tuples in the incoming frame have been consumed, the project operator
+                        // will push its frame to the next operator; i.e., it won't wait until the frame gets full.
+                        appendProjectionToFrame(t, projectionList, true);
+                    } else {
                         appendProjectionToFrame(t, projectionList);
                     }
                 }
-                if (flushFramesRapidly) {
-                    // Whenever all the tuples in the incoming frame have been consumed, the project operator
-                    // will push its frame to the next operator; i.e., it won't wait until the frame gets full.
-                    appendProjectionToFrame(t, projectionList, true);
-                } else {
-                    appendProjectionToFrame(t, projectionList);
-                }
-
             }
 
             @Override