This is an automated email from the ASF dual-hosted git repository.

wyk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new b5886b11cc [ASTERIXDB-3344][COMP] Support ORDER BY without PARTITION 
BY in COPY TO
b5886b11cc is described below

commit b5886b11cc5e7c4e9a686285345a1118a0a151b0
Author: Wail Alkowaileet <[email protected]>
AuthorDate: Thu Jan 25 12:21:16 2024 -0800

    [ASTERIXDB-3344][COMP] Support ORDER BY without PARTITION BY in COPY TO
    
    - user model changes: yes
    - storage format changes: no
    - interface changes: no
    
    Details:
    Support sorting the written result of COPY TO without PARTITION BY.
    
    Change-Id: I7f3b3e32bd5c40e18111c816b2791f5fff65bc82
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18137
    Reviewed-by: Ali Alsuliman <[email protected]>
    Tested-by: Jenkins <[email protected]>
    Integration-Tests: Wail Alkowaileet <[email protected]>
---
 .../asterix/translator/CompiledStatements.java     | 20 +++---
 .../translator/LangExpressionToPlanTranslator.java | 38 ++++++----
 .../optimizerts/queries/copy-to/copy-to.0.sqlpp    | 39 +++++++++++
 .../optimizerts/queries/copy-to/copy-to.1.sqlpp    | 31 +++++++++
 .../optimizerts/queries/copy-to/copy-to.2.sqlpp    | 39 +++++++++++
 .../optimizerts/queries/copy-to/copy-to.3.sqlpp    | 31 +++++++++
 .../optimizerts/results/copy-to/copy-to.0.plan     | 29 ++++++++
 .../optimizerts/results/copy-to/copy-to.1.plan     | 33 +++++++++
 .../optimizerts/results/copy-to/copy-to.2.plan     | 12 ++++
 .../optimizerts/results/copy-to/copy-to.3.plan     | 14 ++++
 .../negative/empty-over/empty-over.01.ddl.sqlpp    | 39 +++++++++++
 .../negative/empty-over/empty-over.02.update.sqlpp | 36 ++++++++++
 .../copy-to/order-by/order-by.01.ddl.sqlpp         | 39 +++++++++++
 .../copy-to/order-by/order-by.02.update.sqlpp      | 38 ++++++++++
 .../copy-to/order-by/order-by.03.ddl.sqlpp         | 34 +++++++++
 .../copy-to/order-by/order-by.04.query.sqlpp       | 31 +++++++++
 .../copy-to/order-by/order-by.05.query.sqlpp       | 28 ++++++++
 .../copy-to/order-by/order-by.20.update.sqlpp      | 41 +++++++++++
 .../copy-to/order-by/order-by.21.ddl.sqlpp         | 34 +++++++++
 .../copy-to/order-by/order-by.22.query.sqlpp       | 24 +++++++
 .../copy-to/order-by/order-by.30.update.sqlpp      | 41 +++++++++++
 .../copy-to/order-by/order-by.31.ddl.sqlpp         | 34 +++++++++
 .../copy-to/order-by/order-by.32.query.sqlpp       | 24 +++++++
 .../results/copy-to/order-by/order-by.04.adm       | 81 ++++++++++++++++++++++
 .../results/copy-to/order-by/order-by.05.adm       | 81 ++++++++++++++++++++++
 .../results/copy-to/order-by/order-by.22.adm       |  3 +
 .../results/copy-to/order-by/order-by.32.adm       |  3 +
 .../copy-to/simple-write/simple-write.06.adm       | 27 --------
 .../runtimets/testsuite_external_dataset_s3.xml    | 11 +++
 .../lang/common/statement/CopyToStatement.java     | 40 ++++++-----
 .../common/visitor/AbstractInlineUdfsVisitor.java  |  4 +-
 .../lang/common/visitor/FormatPrintVisitor.java    | 31 +++++----
 .../common/visitor/GatherFunctionCallsVisitor.java |  2 +-
 .../lang/sqlpp/visitor/CheckSubqueryVisitor.java   |  2 +-
 .../lang/sqlpp/visitor/FreeVariableVisitor.java    |  2 +-
 .../AbstractSqlppContainsExpressionVisitor.java    |  2 +-
 .../AbstractSqlppExpressionScopingVisitor.java     |  2 +-
 .../base/AbstractSqlppSimpleExpressionVisitor.java |  2 +-
 .../asterix-lang-sqlpp/src/main/javacc/SQLPP.jj    | 11 ++-
 39 files changed, 940 insertions(+), 93 deletions(-)

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/CompiledStatements.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/CompiledStatements.java
index 54d4cfc82c..0ff0b728be 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/CompiledStatements.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/CompiledStatements.java
@@ -600,8 +600,8 @@ public class CompiledStatements {
         private final List<Expression> partitionExpressions;
         private final Map<Integer, VariableExpr> partitionsVariables;
         private final List<Expression> orderbyList;
-        private final List<OrderbyClause.OrderModifier> orderbyModifiers;
-        private final List<OrderbyClause.NullOrderModifier> 
orderbyNullModifierList;
+        private final List<OrderbyClause.OrderModifier> orderByModifiers;
+        private final List<OrderbyClause.NullOrderModifier> 
orderByNullModifierList;
 
         public CompiledCopyToStatement(CopyToStatement copyToStatement) {
             this.query = copyToStatement.getQuery();
@@ -612,9 +612,9 @@ public class CompiledStatements {
             this.pathExpressions = copyToStatement.getPathExpressions();
             this.partitionExpressions = 
copyToStatement.getPartitionExpressions();
             this.partitionsVariables = 
copyToStatement.getPartitionsVariables();
-            this.orderbyList = copyToStatement.getOrderbyList();
-            this.orderbyModifiers = copyToStatement.getOrderbyModifiers();
-            this.orderbyNullModifierList = 
copyToStatement.getOrderbyNullModifierList();
+            this.orderbyList = copyToStatement.getOrderByList();
+            this.orderByModifiers = copyToStatement.getOrderByModifiers();
+            this.orderByNullModifierList = 
copyToStatement.getOrderByNullModifierList();
         }
 
         @Override
@@ -658,16 +658,16 @@ public class CompiledStatements {
             return partitionsVariables.get(index);
         }
 
-        public List<Expression> getOrderbyExpressions() {
+        public List<Expression> getOrderByExpressions() {
             return orderbyList;
         }
 
-        public List<OrderbyClause.OrderModifier> getOrderbyModifiers() {
-            return orderbyModifiers;
+        public List<OrderbyClause.OrderModifier> getOrderByModifiers() {
+            return orderByModifiers;
         }
 
-        public List<OrderbyClause.NullOrderModifier> getOrderbyNullModifiers() 
{
-            return orderbyNullModifierList;
+        public List<OrderbyClause.NullOrderModifier> getOrderByNullModifiers() 
{
+            return orderByNullModifierList;
         }
     }
 
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index 56719e280e..7dd0217192 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -394,21 +394,29 @@ abstract class LangExpressionToPlanTranslator
             }
         }
 
-        // Set order expression(s) if any. We do order first to prevent 
partition variables to be used
+        // Handle order by
+        List<Expression> orderExprList = copyTo.getOrderByExpressions();
+        List<OrderbyClause.OrderModifier> orderModifierList = 
copyTo.getOrderByModifiers();
+        List<OrderbyClause.NullOrderModifier> nullOrderModifierList = 
copyTo.getOrderByNullModifiers();
         List<Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>> 
orderExprListOut = new ArrayList<>();
-        List<Expression> orderExprList = copyTo.getOrderbyExpressions();
-        List<OrderbyClause.OrderModifier> orderModifierList = 
copyTo.getOrderbyModifiers();
-        List<OrderbyClause.NullOrderModifier> nullOrderModifierList = 
copyTo.getOrderbyNullModifiers();
-        for (int i = 0; i < orderExprList.size(); i++) {
-            Expression orderExpr = orderExprList.get(i);
-            OrderbyClause.OrderModifier orderModifier = 
orderModifierList.get(i);
-            OrderbyClause.NullOrderModifier nullOrderModifier = 
nullOrderModifierList.get(i);
-            Pair<ILogicalExpression, Mutable<ILogicalOperator>> 
orderExprResult =
-                    langExprToAlgExpression(orderExpr, topOpRef);
-            Pair<Mutable<ILogicalExpression>, Mutable<ILogicalOperator>> 
wrappedPair =
-                    wrapInAssign(context.newVar(), orderExprResult.first, 
orderExprResult.second);
-            addOrderByExpression(orderExprListOut, 
wrappedPair.first.getValue(), orderModifier, nullOrderModifier);
-            topOpRef = wrappedPair.second;
+        if (!copyTo.isPartitioned() && copyTo.isOrdered()) {
+            // The output must be ordered (sorted) entirely, create an 
implicit orderBy-clause
+            OrderbyClause orderbyClause = new OrderbyClause(orderExprList, 
orderModifierList, nullOrderModifierList);
+            Pair<ILogicalOperator, LogicalVariable> order = 
orderbyClause.accept(this, topOpRef);
+            topOpRef = new MutableObject<>(order.first);
+        } else {
+            // Potentially an ordered partitions. Set order expression(s) if 
any.
+            for (int i = 0; i < orderExprList.size(); i++) {
+                Expression orderExpr = orderExprList.get(i);
+                OrderbyClause.OrderModifier orderModifier = 
orderModifierList.get(i);
+                OrderbyClause.NullOrderModifier nullOrderModifier = 
nullOrderModifierList.get(i);
+                Pair<ILogicalExpression, Mutable<ILogicalOperator>> 
orderExprResult =
+                        langExprToAlgExpression(orderExpr, topOpRef);
+                Pair<Mutable<ILogicalExpression>, Mutable<ILogicalOperator>> 
wrappedPair =
+                        wrapInAssign(context.newVar(), orderExprResult.first, 
orderExprResult.second);
+                addOrderByExpression(orderExprListOut, 
wrappedPair.first.getValue(), orderModifier, nullOrderModifier);
+                topOpRef = wrappedPair.second;
+            }
         }
 
         // Set Path
@@ -445,12 +453,14 @@ abstract class LangExpressionToPlanTranslator
             fullPathExpr = concat;
         }
 
+        // Write adapter configuration
         writeDataSink = new WriteDataSink(copyTo.getAdapter(), 
copyTo.getProperties());
         // writeOperator
         WriteOperator writeOperator = new WriteOperator(sourceExprRef, new 
MutableObject<>(fullPathExpr),
                 partitionExpressionRefs, orderExprListOut, writeDataSink);
         writeOperator.getInputs().add(topOpRef);
 
+        // We need DistributeResultOperator to ensure all warnings to be 
delivered to the user
         ResultSetSinkId rssId = new 
ResultSetSinkId(metadataProvider.getResultSetId());
         ResultSetDataSink sink = new ResultSetDataSink(rssId, null);
         DistributeResultOperator newTop = new DistributeResultOperator(new 
ArrayList<>(), sink, resultMetadata);
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.0.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.0.sqlpp
new file mode 100644
index 0000000000..a742c46067
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.0.sqlpp
@@ -0,0 +1,39 @@
+/*
+ * 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 TYPE OpenType AS {
+    uid: uuid
+};
+
+CREATE DATASET OpenDataset(OpenType)
+PRIMARY KEY uid AUTOGENERATED;
+
+SET `compiler.sort.parallel` "true";
+COPY OpenDataset x
+TO localfs
+PATH("myPath")
+OVER(ORDER BY x.id DESC)
+WITH {
+   "format": "json"
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.1.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.1.sqlpp
new file mode 100644
index 0000000000..ba01aeeac5
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.1.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.
+ */
+
+USE test;
+SET `compiler.sort.parallel` "true";
+COPY (
+   SELECT od.name, od.id
+   FROM OpenDataset od
+) x
+TO localfs
+PATH("myPath")
+OVER(ORDER BY x.id DESC, x.name ASC)
+WITH {
+   "format": "json"
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.2.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.2.sqlpp
new file mode 100644
index 0000000000..b76ae227c3
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.2.sqlpp
@@ -0,0 +1,39 @@
+/*
+ * 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 TYPE OpenType AS {
+    uid: uuid
+};
+
+CREATE DATASET OpenDataset(OpenType)
+PRIMARY KEY uid AUTOGENERATED;
+
+SET `compiler.sort.parallel` "false";
+COPY OpenDataset x
+TO localfs
+PATH("myPath")
+OVER(ORDER BY x.id DESC)
+WITH {
+   "format": "json"
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.3.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.3.sqlpp
new file mode 100644
index 0000000000..38133b346e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/copy-to/copy-to.3.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.
+ */
+
+USE test;
+SET `compiler.sort.parallel` "false";
+COPY (
+   SELECT od.name, od.id
+   FROM OpenDataset od
+) x
+TO localfs
+PATH("myPath")
+OVER(ORDER BY x.id DESC, x.name ASC)
+WITH {
+   "format": "json"
+};
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.0.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.0.plan
new file mode 100644
index 0000000000..bd472794ca
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.0.plan
@@ -0,0 +1,29 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- SINK_WRITE  |PARTITIONED|
+      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+        -- STABLE_SORT [$$25(DESC)]  |PARTITIONED|
+          -- RANGE_PARTITION_EXCHANGE [$$25(DESC)]  |PARTITIONED|
+            -- FORWARD  |PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                -- REPLICATE  |PARTITIONED|
+                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.OpenDataset)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+              -- BROADCAST_EXCHANGE  |PARTITIONED|
+                -- AGGREGATE  |UNPARTITIONED|
+                  -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+                    -- AGGREGATE  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        -- REPLICATE  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- ASSIGN  |PARTITIONED|
+                              -- STREAM_PROJECT  |PARTITIONED|
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  -- DATASOURCE_SCAN (test.OpenDataset)  
|PARTITIONED|
+                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                      -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.1.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.1.plan
new file mode 100644
index 0000000000..cc2cf3b20b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.1.plan
@@ -0,0 +1,33 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- SINK_WRITE  |PARTITIONED|
+      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+        -- STABLE_SORT [$$32(DESC), $$33(ASC)]  |PARTITIONED|
+          -- RANGE_PARTITION_EXCHANGE [$$32(DESC), $$33(ASC)]  |PARTITIONED|
+            -- FORWARD  |PARTITIONED|
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                -- REPLICATE  |PARTITIONED|
+                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ASSIGN  |PARTITIONED|
+                          -- STREAM_PROJECT  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- DATASOURCE_SCAN (test.OpenDataset)  
|PARTITIONED|
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+              -- BROADCAST_EXCHANGE  |PARTITIONED|
+                -- AGGREGATE  |UNPARTITIONED|
+                  -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+                    -- AGGREGATE  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        -- REPLICATE  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- ASSIGN  |PARTITIONED|
+                              -- STREAM_PROJECT  |PARTITIONED|
+                                -- ASSIGN  |PARTITIONED|
+                                  -- STREAM_PROJECT  |PARTITIONED|
+                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                      -- DATASOURCE_SCAN (test.OpenDataset)  
|PARTITIONED|
+                                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                          -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.2.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.2.plan
new file mode 100644
index 0000000000..d6efffc0d0
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.2.plan
@@ -0,0 +1,12 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- SINK_WRITE  |PARTITIONED|
+      -- SORT_MERGE_EXCHANGE [$$25(DESC) ]  |PARTITIONED|
+        -- STABLE_SORT [$$25(DESC)]  |PARTITIONED|
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            -- ASSIGN  |PARTITIONED|
+              -- STREAM_PROJECT  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- DATASOURCE_SCAN (test.OpenDataset)  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.3.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.3.plan
new file mode 100644
index 0000000000..070698ae58
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/copy-to/copy-to.3.plan
@@ -0,0 +1,14 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- SINK_WRITE  |PARTITIONED|
+      -- SORT_MERGE_EXCHANGE [$$32(DESC), $$33(ASC) ]  |PARTITIONED|
+        -- STABLE_SORT [$$32(DESC), $$33(ASC)]  |PARTITIONED|
+          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+            -- ASSIGN  |PARTITIONED|
+              -- STREAM_PROJECT  |PARTITIONED|
+                -- ASSIGN  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- DATASOURCE_SCAN (test.OpenDataset)  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/negative/empty-over/empty-over.01.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/negative/empty-over/empty-over.01.ddl.sqlpp
new file mode 100644
index 0000000000..b68c38b195
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/negative/empty-over/empty-over.01.ddl.sqlpp
@@ -0,0 +1,39 @@
+/*
+ * 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 TYPE OpenType AS {
+};
+
+CREATE EXTERNAL DATASET Customer(OpenType) USING S3 (
+    ("accessKeyId"="dummyAccessKey"),
+    ("secretAccessKey"="dummySecretKey"),
+    ("region"="us-west-2"),
+    ("serviceEndpoint"="http://127.0.0.1:8001";),
+    ("container"="playground"),
+    
("definition"="external-filter/car/{company:string}/customer/{customer_id:int}"),
+    ("embed-filter-values" = "false"),
+    ("format"="json")
+);
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/negative/empty-over/empty-over.02.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/negative/empty-over/empty-over.02.update.sqlpp
new file mode 100644
index 0000000000..cc0c4b4099
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/negative/empty-over/empty-over.02.update.sqlpp
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+COPY Customer c
+TO S3
+PATH ("copy-to-result-with-over")
+OVER()
+WITH {
+    "accessKeyId":"dummyAccessKey",
+    "secretAccessKey":"dummySecretKey",
+    "region":"us-west-2",
+    "serviceEndpoint":"http://127.0.0.1:8001";,
+    "container":"playground",
+    "format":"json"
+}
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.01.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.01.ddl.sqlpp
new file mode 100644
index 0000000000..b68c38b195
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.01.ddl.sqlpp
@@ -0,0 +1,39 @@
+/*
+ * 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 TYPE OpenType AS {
+};
+
+CREATE EXTERNAL DATASET Customer(OpenType) USING S3 (
+    ("accessKeyId"="dummyAccessKey"),
+    ("secretAccessKey"="dummySecretKey"),
+    ("region"="us-west-2"),
+    ("serviceEndpoint"="http://127.0.0.1:8001";),
+    ("container"="playground"),
+    
("definition"="external-filter/car/{company:string}/customer/{customer_id:int}"),
+    ("embed-filter-values" = "false"),
+    ("format"="json")
+);
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.02.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.02.update.sqlpp
new file mode 100644
index 0000000000..66bb70961e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.02.update.sqlpp
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+COPY Customer c
+TO S3
+PATH ("copy-to-result", "order-by1")
+-- We do not have a way to determine the output is sorted
+-- However, this test ensures that there's no regressions when having ORDER BY 
only in the OVER-clause
+OVER (ORDER BY c.company)
+WITH {
+    "accessKeyId":"dummyAccessKey",
+    "secretAccessKey":"dummySecretKey",
+    "region":"us-west-2",
+    "serviceEndpoint":"http://127.0.0.1:8001";,
+    "container":"playground",
+    "format":"json"
+}
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.03.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.03.ddl.sqlpp
new file mode 100644
index 0000000000..03803325a4
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.03.ddl.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+CREATE EXTERNAL DATASET CustomerCopy(OpenType) USING S3 (
+    ("accessKeyId"="dummyAccessKey"),
+    ("secretAccessKey"="dummySecretKey"),
+    ("region"="us-west-2"),
+    ("serviceEndpoint"="http://127.0.0.1:8001";),
+    ("container"="playground"),
+    ("definition"="copy-to-result/order-by1"),
+    ("embed-filter-values" = "false"),
+    ("format"="json")
+);
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.04.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.04.query.sqlpp
new file mode 100644
index 0000000000..eace40cc0b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.04.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.
+ */
+
+USE test;
+
+SELECT VALUE c
+FROM Customer c
+ORDER BY c.customer_id,
+         c.company,
+         c.year,
+         c.month,
+         c.day;
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.05.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.05.query.sqlpp
new file mode 100644
index 0000000000..7c3dab0167
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.05.query.sqlpp
@@ -0,0 +1,28 @@
+/*
+ * 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 VALUE c
+FROM CustomerCopy c
+ORDER BY c.customer_id,
+         c.company,
+         c.year,
+         c.month,
+         c.day;
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.20.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.20.update.sqlpp
new file mode 100644
index 0000000000..1fae58f6d2
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.20.update.sqlpp
@@ -0,0 +1,41 @@
+/*
+ * 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 `compiler.sort.parallel` "true";
+COPY (
+   SELECT c.company make
+   FROM Customer c
+) x
+TO S3
+PATH ("copy-to-result", "order-by2")
+-- We do not have a way to determine the output is sorted
+-- However, this test ensures that there's no regressions when having ORDER BY 
only in the OVER-clause
+OVER (ORDER BY x.make)
+WITH {
+    "accessKeyId":"dummyAccessKey",
+    "secretAccessKey":"dummySecretKey",
+    "region":"us-west-2",
+    "serviceEndpoint":"http://127.0.0.1:8001";,
+    "container":"playground",
+    "format":"json"
+}
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.21.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.21.ddl.sqlpp
new file mode 100644
index 0000000000..fab69643c4
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.21.ddl.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+CREATE EXTERNAL DATASET CustomerCarMake1(OpenType) USING S3 (
+    ("accessKeyId"="dummyAccessKey"),
+    ("secretAccessKey"="dummySecretKey"),
+    ("region"="us-west-2"),
+    ("serviceEndpoint"="http://127.0.0.1:8001";),
+    ("container"="playground"),
+    ("definition"="copy-to-result/order-by2"),
+    ("embed-filter-values" = "false"),
+    ("format"="json")
+);
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.22.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.22.query.sqlpp
new file mode 100644
index 0000000000..321f545344
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.22.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;
+
+SELECT DISTINCT VALUE c
+FROM CustomerCarMake1 c
+ORDER BY c.make
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.30.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.30.update.sqlpp
new file mode 100644
index 0000000000..dc0a6316c3
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.30.update.sqlpp
@@ -0,0 +1,41 @@
+/*
+ * 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 `compiler.sort.parallel` "false";
+COPY (
+   SELECT c.company make
+   FROM Customer c
+) x
+TO S3
+PATH ("copy-to-result", "order-by3")
+-- We do not have a way to determine the output is sorted
+-- However, this test ensures that there's no regressions when having ORDER BY 
only in the OVER-clause
+OVER (ORDER BY x.make)
+WITH {
+    "accessKeyId":"dummyAccessKey",
+    "secretAccessKey":"dummySecretKey",
+    "region":"us-west-2",
+    "serviceEndpoint":"http://127.0.0.1:8001";,
+    "container":"playground",
+    "format":"json"
+}
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.31.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.31.ddl.sqlpp
new file mode 100644
index 0000000000..e3369bebc5
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.31.ddl.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+CREATE EXTERNAL DATASET CustomerCarMake2(OpenType) USING S3 (
+    ("accessKeyId"="dummyAccessKey"),
+    ("secretAccessKey"="dummySecretKey"),
+    ("region"="us-west-2"),
+    ("serviceEndpoint"="http://127.0.0.1:8001";),
+    ("container"="playground"),
+    ("definition"="copy-to-result/order-by2"),
+    ("embed-filter-values" = "false"),
+    ("format"="json")
+);
+
+
+
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.32.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.32.query.sqlpp
new file mode 100644
index 0000000000..42b0e32897
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/copy-to/order-by/order-by.32.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;
+
+SELECT DISTINCT VALUE c
+FROM CustomerCarMake2 c
+ORDER BY c.make
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.04.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.04.adm
new file mode 100644
index 0000000000..4e13836ca1
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.04.adm
@@ -0,0 +1,81 @@
+{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.05.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.05.adm
new file mode 100644
index 0000000000..4e13836ca1
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.05.adm
@@ -0,0 +1,81 @@
+{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 1, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 1, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 1, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 2, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 2, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 2, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "lexus", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "lexus", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "lexus", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "toyota", "year": 2001, "month": 1, "day": 1 }
+{ "customer_id": 3, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "toyota", "year": 2002, "month": 2, "day": 2 }
+{ "customer_id": 3, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
+{ "customer_id": 3, "company": "toyota", "year": 2003, "month": 3, "day": 3 }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.22.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.22.adm
new file mode 100644
index 0000000000..d7ebf6406b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.22.adm
@@ -0,0 +1,3 @@
+{ "make": "ford" }
+{ "make": "lexus" }
+{ "make": "toyota" }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.32.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.32.adm
new file mode 100644
index 0000000000..d7ebf6406b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/order-by/order-by.32.adm
@@ -0,0 +1,3 @@
+{ "make": "ford" }
+{ "make": "lexus" }
+{ "make": "toyota" }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/simple-write/simple-write.06.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/simple-write/simple-write.06.adm
deleted file mode 100644
index 330cafe6a3..0000000000
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/copy-to/simple-write/simple-write.06.adm
+++ /dev/null
@@ -1,27 +0,0 @@
-{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 1, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 1, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
-{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
-{ "customer_id": 1, "company": "ford", "year": 2003, "month": 3, "day": 3 }
-{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 2, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 2, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
-{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
-{ "customer_id": 2, "company": "ford", "year": 2003, "month": 3, "day": 3 }
-{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 3, "company": "ford", "year": 2001, "month": 1, "day": 1 }
-{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 3, "company": "ford", "year": 2002, "month": 2, "day": 2 }
-{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
-{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
-{ "customer_id": 3, "company": "ford", "year": 2003, "month": 3, "day": 3 }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_external_dataset_s3.xml
 
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_external_dataset_s3.xml
index 421aacddeb..db4b5a8e8f 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_external_dataset_s3.xml
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_external_dataset_s3.xml
@@ -44,6 +44,11 @@
         <output-dir compare="Text">empty-path</output-dir>
       </compilation-unit>
     </test-case>
+    <test-case FilePath="copy-to">
+      <compilation-unit name="order-by">
+        <output-dir compare="Text">order-by</output-dir>
+      </compilation-unit>
+    </test-case>
     <test-case FilePath="copy-to/negative">
       <compilation-unit name="early-missing">
         <output-dir compare="Text">early-missing</output-dir>
@@ -79,6 +84,12 @@
         <expected-error>ASX1096: Unknown compression scheme rar. Supported 
schemes are [gzip]</expected-error>
       </compilation-unit>
     </test-case>
+    <test-case FilePath="copy-to/negative">
+      <compilation-unit name="empty-over">
+        <output-dir compare="Text">empty-over</output-dir>
+        <expected-error>ASX1001: Syntax error: OVER-clause cannot be 
empty</expected-error>
+      </compilation-unit>
+    </test-case>
   </test-group>
   <test-group name="aws-s3-external-dataset">
     <test-case FilePath="external-dataset">
diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CopyToStatement.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CopyToStatement.java
index c6ca34978b..dbe7b35b2b 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CopyToStatement.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CopyToStatement.java
@@ -40,22 +40,22 @@ public class CopyToStatement extends AbstractStatement 
implements IReturningStat
     private final VariableExpr sourceVariable;
     private final ExternalDetailsDecl externalDetailsDecl;
     private final Map<Integer, VariableExpr> partitionsVariables;
-    private final List<OrderbyClause.OrderModifier> orderbyModifiers;
-    private final List<OrderbyClause.NullOrderModifier> 
orderbyNullModifierList;
+    private final List<OrderbyClause.OrderModifier> orderByModifiers;
+    private final List<OrderbyClause.NullOrderModifier> 
orderByNullModifierList;
 
     private Namespace namespace;
     private Query query;
     private List<Expression> pathExpressions;
 
     private List<Expression> partitionExpressions;
-    private List<Expression> orderbyList;
+    private List<Expression> orderByList;
     private int varCounter;
 
     public CopyToStatement(Namespace namespace, String datasetName, Query 
query, VariableExpr sourceVariable,
             ExternalDetailsDecl externalDetailsDecl, List<Expression> 
pathExpressions,
             List<Expression> partitionExpressions, Map<Integer, VariableExpr> 
partitionsVariables,
-            List<Expression> orderbyList, List<OrderbyClause.OrderModifier> 
orderbyModifiers,
-            List<OrderbyClause.NullOrderModifier> orderbyNullModifierList, int 
varCounter) {
+            List<Expression> orderbyList, List<OrderbyClause.OrderModifier> 
orderByModifiers,
+            List<OrderbyClause.NullOrderModifier> orderByNullModifierList, int 
varCounter) {
         this.namespace = namespace;
         this.datasetName = datasetName;
         this.query = query;
@@ -64,9 +64,9 @@ public class CopyToStatement extends AbstractStatement 
implements IReturningStat
         this.pathExpressions = pathExpressions;
         this.partitionExpressions = partitionExpressions;
         this.partitionsVariables = partitionsVariables;
-        this.orderbyList = orderbyList;
-        this.orderbyModifiers = orderbyModifiers;
-        this.orderbyNullModifierList = orderbyNullModifierList;
+        this.orderByList = orderbyList;
+        this.orderByModifiers = orderByModifiers;
+        this.orderByNullModifierList = orderByNullModifierList;
         this.varCounter = varCounter;
 
         if (pathExpressions.isEmpty()) {
@@ -141,28 +141,32 @@ public class CopyToStatement extends AbstractStatement 
implements IReturningStat
         return partitionsVariables;
     }
 
-    public List<Expression> getOrderbyList() {
-        return orderbyList;
+    public List<Expression> getOrderByList() {
+        return orderByList;
     }
 
-    public void setOrderbyList(List<Expression> orderbyList) {
-        this.orderbyList = orderbyList;
+    public void setOrderByList(List<Expression> orderbyList) {
+        this.orderByList = orderbyList;
     }
 
-    public List<OrderbyClause.OrderModifier> getOrderbyModifiers() {
-        return orderbyModifiers;
+    public List<OrderbyClause.OrderModifier> getOrderByModifiers() {
+        return orderByModifiers;
     }
 
-    public List<OrderbyClause.NullOrderModifier> getOrderbyNullModifierList() {
-        return orderbyNullModifierList;
+    public List<OrderbyClause.NullOrderModifier> getOrderByNullModifierList() {
+        return orderByNullModifierList;
     }
 
     public boolean hasOverClause() {
+        return hasPartitionClause() || hasOrderClause();
+    }
+
+    public boolean hasPartitionClause() {
         return !partitionExpressions.isEmpty();
     }
 
     public boolean hasOrderClause() {
-        return !orderbyList.isEmpty();
+        return !orderByList.isEmpty();
     }
 
     @Override
@@ -186,7 +190,7 @@ public class CopyToStatement extends AbstractStatement 
implements IReturningStat
         topLevelExpressions.add(query.getBody());
         topLevelExpressions.addAll(pathExpressions);
         topLevelExpressions.addAll(partitionExpressions);
-        topLevelExpressions.addAll(orderbyList);
+        topLevelExpressions.addAll(orderByList);
         return topLevelExpressions;
     }
 
diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java
index 22c011a6d0..8c7b9151f3 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/AbstractInlineUdfsVisitor.java
@@ -298,9 +298,9 @@ public abstract class AbstractInlineUdfsVisitor extends 
AbstractQueryExpressionV
         changed |= part.first;
         stmtCopy.setPartitionExpressions(part.second);
 
-        Pair<Boolean, List<Expression>> order = 
inlineUdfsInExprList(stmtCopy.getOrderbyList());
+        Pair<Boolean, List<Expression>> order = 
inlineUdfsInExprList(stmtCopy.getOrderByList());
         changed |= order.first;
-        stmtCopy.setOrderbyList(order.second);
+        stmtCopy.setOrderByList(order.second);
 
         return changed;
     }
diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
index 9c904dab88..3091b3087e 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
@@ -581,27 +581,30 @@ public abstract class FormatPrintVisitor implements 
ILangVisitor<Void, Integer>
 
         if (cto.hasOverClause()) {
             out.print("over (");
-            List<Expression> partitionExprs = cto.getPartitionExpressions();
-            Map<Integer, VariableExpr> partitionVars = 
cto.getPartitionsVariables();
-            out.print(skip(step + 1) + "partition ");
-            for (int i = 0; i < partitionExprs.size(); i++) {
-                if (i > 0) {
-                    out.print(COMMA + " ");
-                }
-                partitionExprs.get(i).accept(this, step + 2);
-                VariableExpr partVar = partitionVars.get(i);
-                if (partVar != null) {
-                    out.print(" as ");
-                    partVar.accept(this, step);
+            if (cto.hasPartitionClause()) {
+                List<Expression> partitionExprs = 
cto.getPartitionExpressions();
+                Map<Integer, VariableExpr> partitionVars = 
cto.getPartitionsVariables();
+                out.print(skip(step + 1) + "partition ");
+                for (int i = 0; i < partitionExprs.size(); i++) {
+                    if (i > 0) {
+                        out.print(COMMA + " ");
+                    }
+                    partitionExprs.get(i).accept(this, step + 2);
+                    VariableExpr partVar = partitionVars.get(i);
+                    if (partVar != null) {
+                        out.print(" as ");
+                        partVar.accept(this, step);
+                    }
                 }
             }
             out.println();
             if (cto.hasOrderClause()) {
                 out.print(skip(step + 1) + "order ");
-                printDelimitedObyExpressions(cto.getOrderbyList(), 
cto.getOrderbyModifiers(),
-                        cto.getOrderbyNullModifierList(), step + 1);
+                printDelimitedObyExpressions(cto.getOrderByList(), 
cto.getOrderByModifiers(),
+                        cto.getOrderByNullModifierList(), step + 1);
                 out.println();
             }
+            out.println(')');
         }
 
         out.println("with ");
diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
index 33734950f4..febc9d83d1 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
@@ -254,7 +254,7 @@ public abstract class GatherFunctionCallsVisitor extends 
AbstractQueryExpression
         stmtCopy.getQuery().accept(this, arg);
         acceptList(stmtCopy.getPathExpressions(), arg);
         acceptList(stmtCopy.getPartitionExpressions(), arg);
-        acceptList(stmtCopy.getOrderbyList(), arg);
+        acceptList(stmtCopy.getOrderByList(), arg);
         return null;
     }
 
diff --git 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java
 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java
index abae3ee428..18639562de 100644
--- 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java
+++ 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java
@@ -317,7 +317,7 @@ public class CheckSubqueryVisitor extends 
AbstractSqlppQueryExpressionVisitor<Bo
     public Boolean visit(CopyToStatement stmtCopy, ILangExpression arg) throws 
CompilationException {
         return stmtCopy.getQuery().accept(this, arg) || 
visitExprList(stmtCopy.getPathExpressions(), arg)
                 || visitExprList(stmtCopy.getPartitionExpressions(), arg)
-                || visitExprList(stmtCopy.getOrderbyList(), arg);
+                || visitExprList(stmtCopy.getOrderByList(), arg);
     }
 
     @Override
diff --git 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java
 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java
index 37dd1f1120..bfa5c91b6b 100644
--- 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java
+++ 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java
@@ -523,7 +523,7 @@ public class FreeVariableVisitor extends 
AbstractSqlppQueryExpressionVisitor<Voi
         stmtCopy.getBody().accept(this, freeVars);
         visit(stmtCopy.getPathExpressions(), freeVars);
         visit(stmtCopy.getPartitionExpressions(), freeVars);
-        visit(stmtCopy.getOrderbyList(), freeVars);
+        visit(stmtCopy.getOrderByList(), freeVars);
         return null;
     }
 
diff --git 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppContainsExpressionVisitor.java
 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppContainsExpressionVisitor.java
index 39fe905a11..e4117f020b 100644
--- 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppContainsExpressionVisitor.java
+++ 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppContainsExpressionVisitor.java
@@ -312,7 +312,7 @@ public abstract class 
AbstractSqlppContainsExpressionVisitor<T>
     public Boolean visit(CopyToStatement stmtCopy, T arg) throws 
CompilationException {
         return stmtCopy.accept(this, arg) || 
visitExprList(stmtCopy.getPathExpressions(), arg)
                 || visitExprList(stmtCopy.getPartitionExpressions(), arg)
-                || visitExprList(stmtCopy.getOrderbyList(), arg);
+                || visitExprList(stmtCopy.getOrderByList(), arg);
     }
 
     private boolean visit(ILangExpression expr, T arg) throws 
CompilationException {
diff --git 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
index 1ecc3a221b..e3e248480d 100644
--- 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
+++ 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppExpressionScopingVisitor.java
@@ -432,7 +432,7 @@ public class AbstractSqlppExpressionScopingVisitor extends 
AbstractSqlppSimpleEx
         }
 
         // Visit order by
-        stmtCopy.setOrderbyList(visit(stmtCopy.getOrderbyList(), stmtCopy));
+        stmtCopy.setOrderByList(visit(stmtCopy.getOrderByList(), stmtCopy));
 
         // Visit path exprs
         stmtCopy.setPathExpressions(visit(stmtCopy.getPathExpressions(), 
stmtCopy));
diff --git 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
index 9b2501d2a2..f3d26750da 100644
--- 
a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
+++ 
b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
@@ -363,7 +363,7 @@ public class AbstractSqlppSimpleExpressionVisitor
         stmtCopy.setBody(stmtCopy.getBody().accept(this, arg));
         stmtCopy.setPathExpressions(visit(stmtCopy.getPathExpressions(), arg));
         
stmtCopy.setPartitionExpressions(visit(stmtCopy.getPartitionExpressions(), 
arg));
-        stmtCopy.setOrderbyList(visit(stmtCopy.getOrderbyList(), arg));
+        stmtCopy.setOrderByList(visit(stmtCopy.getOrderByList(), arg));
         return null;
     }
 
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj 
b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 73f6da693c..a81807ce7d 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -2959,13 +2959,15 @@ CopyToStatement CopyToStatement(Token startToken, 
Pair<Namespace, Identifier> na
   OrderbyClause orderByClause = null;
 }
 {
-   <OVER> <LEFTPAREN> <IDENTIFIER> {expectToken(PARTITION);} <BY>
+   <OVER> <LEFTPAREN>
+
+   (<IDENTIFIER> {expectToken(PARTITION);} <BY>
    partitionExpr = Expression() { partitionExprs.add(partitionExpr);}
    ((<AS>)? partitionVar = Variable() { partitionVarExprs.put(0, 
partitionVar); })?
    (
      <COMMA> partitionExpr = Expression() { partitionExprs.add(partitionExpr); 
}
      ((<AS>)? partitionVar = Variable() { 
partitionVarExprs.put(partitionExprs.size() - 1, partitionVar); })?
-   )*
+   )*)?
    (
       orderByClause = OrderbyClause()
       {
@@ -2975,6 +2977,11 @@ CopyToStatement CopyToStatement(Token startToken, 
Pair<Namespace, Identifier> na
       }
    )?
    <RIGHTPAREN>
+   {
+     if(partitionExprs.isEmpty() && orderbyList.isEmpty()) {
+       throw new SqlppParseException(getSourceLocation(token), "OVER-clause 
cannot be empty");
+     }
+   }
 }
 
 

Reply via email to