[ASTERIXDB-2798][COMP] Copy limit through subplans

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

Details:
- CopyLimitDownRule should push limit through subplans

Change-Id: Ia5fa4b7a25cafadb6dd2c050749e851e7e2adec5
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/8846
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/at00/at00.6.async.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/at00/at00.6.async.sqlpp
index 7ba0e96..10b8c85 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/at00/at00.6.async.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/flwor/at00/at00.6.async.sqlpp
@@ -34,4 +34,4 @@
     ) as gen0,
     gen0.i as j at p
 where p < 4
-order by partkey, shipdate;
+order by partkey, p, shipdate;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.1.ddl.sqlpp
index 36af900..dd756b0 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.1.ddl.sqlpp
@@ -29,7 +29,7 @@
 use test;
 
 
-create type test.DBLPType as
+create type DBLPType as
 {
   id : bigint,
   dblpid : string,
@@ -58,6 +58,21 @@
   string4 : string
 };
 
-create  dataset DBLP1(DBLPType) primary key id;
+create dataset DBLP1(DBLPType) primary key id;
 
 create dataset onek1(onekType1) primary key unique2;
+
+create function drop_fields(obj, field1, field2, field3) {
+  (
+    select value object_remove(t3, field3)
+    from (
+      select value object_remove(t2, field2)
+      from (
+        select value object_remove(t1, field1)
+        from (
+          select value t0 from to_array(obj) t0
+        ) t1
+      ) t2
+    ) t3
+  )[0]
+};
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.8.query.sqlpp
new file mode 100644
index 0000000..d25d975
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.8.query.sqlpp
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/*
+ * Test limit pushdown with UDFs (ASTERIXDB-2798).
+ */
+
+use test;
+
+explain
+
+select value drop_fields(paper, 'title', 'authors', 'misc')
+from DBLP1 as paper
+order by id
+limit 5 offset 5;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.9.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.9.query.sqlpp
new file mode 100644
index 0000000..66309f8
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.9.query.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+/*
+ * Test limit pushdown with UDFs (ASTERIXDB-2798).
+ */
+
+use test;
+
+select value drop_fields(paper, 'title', 'authors', 'misc')
+from DBLP1 as paper
+order by id
+limit 5 offset 5;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.8.adm
new file mode 100644
index 0000000..e11c19d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.8.adm
@@ -0,0 +1,41 @@
+distribute result [$$75]
+-- DISTRIBUTE_RESULT  |UNPARTITIONED|
+  exchange
+  -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
+    limit 5, 5
+    -- STREAM_LIMIT  |UNPARTITIONED|
+      project ([$$75])
+      -- STREAM_PROJECT  |PARTITIONED|
+        assign [$$75] <- [get-item($$73, 0)]
+        -- ASSIGN  |PARTITIONED|
+          project ([$$73])
+          -- STREAM_PROJECT  |PARTITIONED|
+            exchange
+            -- SORT_MERGE_EXCHANGE [$$77(ASC) ]  |PARTITIONED|
+              project ([$$73, $$77])
+              -- STREAM_PROJECT  |PARTITIONED|
+                subplan {
+                          aggregate [$$73] <- [listify($$72)]
+                          -- AGGREGATE  |LOCAL|
+                            assign [$$72] <- [object-remove(object-remove(object-remove($$t1, "title"), "authors"), "misc")]
+                            -- ASSIGN  |LOCAL|
+                              unnest $$t1 <- scan-collection($$64)
+                              -- UNNEST  |LOCAL|
+                                nested tuple source
+                                -- NESTED_TUPLE_SOURCE  |LOCAL|
+                       }
+                -- SUBPLAN  |PARTITIONED|
+                  project ([$$77, $$64])
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    assign [$$64] <- [to-array($$paper)]
+                    -- ASSIGN  |PARTITIONED|
+                      limit 10
+                      -- STREAM_LIMIT  |PARTITIONED|
+                        exchange
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          data-scan []<-[$$77, $$paper] <- test.DBLP1 limit 10
+                          -- DATASOURCE_SCAN  |PARTITIONED|
+                            exchange
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              empty-tuple-source
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.9.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.9.adm
new file mode 100644
index 0000000..77aa145
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.9.adm
@@ -0,0 +1,5 @@
+{ "id": 6, "dblpid": "books/acm/kim95/DittrichD95" }
+{ "id": 7, "dblpid": "books/acm/kim95/Garcia-MolinaH95" }
+{ "id": 8, "dblpid": "books/acm/kim95/Goodman95" }
+{ "id": 9, "dblpid": "books/acm/kim95/Kaiser95" }
+{ "id": 10, "dblpid": "books/acm/kim95/KelleyGKRG95" }
\ No newline at end of file
diff --git a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/CopyLimitDownRule.java b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/CopyLimitDownRule.java
index 382b80d..7dd86b1 100644
--- a/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/CopyLimitDownRule.java
+++ b/hyracks-fullstack/algebricks/algebricks-rewriter/src/main/java/org/apache/hyracks/algebricks/rewriter/rules/CopyLimitDownRule.java
@@ -150,6 +150,7 @@
     private static boolean isSafeOpCandidate(ILogicalOperator op) {
         switch (op.getOperatorTag()) {
             case UNIONALL:
+            case SUBPLAN: // subplan is a 'map' but is not yet marked as such
                 return true;
             // exclude following 'map' operators because they change cardinality
             case SELECT: