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

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

commit 37ee115185a3234c14d7dcf1bc6afc014e7225c1
Author: Nikita Timofeev <stari...@gmail.com>
AuthorDate: Thu Feb 25 15:21:36 2021 +0300

    CAY-2587 SQLServer Limit Offset translation
     - refactoring and cleanup
     - release notes
---
 RELEASE-NOTES.txt                                  |  1 +
 .../access/sqlbuilder/sqltree/NodeType.java        |  3 +-
 .../access/sqlbuilder/sqltree/OrderByNode.java     |  5 +++
 .../dba/sqlserver/SQLServerActionBuilder.java      | 41 ++++++++++----------
 .../cayenne/dba/sqlserver/SQLServerAdapter.java    | 26 +++++++------
 .../dba/sqlserver/SQLServerSelectAction.java       | 15 +++-----
 .../dba/sqlserver/SQLServerTreeProcessor.java      | 26 +------------
 ...ocessor.java => SQLServerTreeProcessorV12.java} | 44 ++++++++++------------
 8 files changed, 70 insertions(+), 91 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 5b821b1..ddd59d4 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -13,6 +13,7 @@ Date:
 ----------------------------------
 Changes/New Features:
 
+CAY-2587 SQLServer Limit Offset translation
 CAY-2677 Custom Class Generation Templates for Embeddables and DataMaps
 CAY-2689 ServerRuntime API: missing some variants of the 
performInTransaction() method
 CAY-2692 Add entity lifecycle callbacks via annotated methods
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java
index 575d330..f463c07 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java
@@ -38,5 +38,6 @@ public enum NodeType {
     FROM,
     UPDATE_SET,
     INSERT_COLUMNS,
-    INSERT_VALUES
+    INSERT_VALUES,
+    ORDER_BY
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OrderByNode.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OrderByNode.java
index 7e54ae6..663f66c 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OrderByNode.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OrderByNode.java
@@ -40,4 +40,9 @@ public class OrderByNode extends Node {
     public Node copy() {
         return new OrderByNode();
     }
+
+    @Override
+    public NodeType getType() {
+        return NodeType.ORDER_BY;
+    }
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerActionBuilder.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerActionBuilder.java
index bd43ee9..bb82143 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerActionBuilder.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerActionBuilder.java
@@ -33,23 +33,32 @@ public class SQLServerActionBuilder extends 
JdbcActionBuilder {
         *
         * @since 4.2
         */
-       private Integer version;
+       private final Integer version;
 
        /**
+        * @param dataNode current data node
         * @since 4.0
         */
        public SQLServerActionBuilder(DataNode dataNode) {
+               this(dataNode, null);
+       }
+
+       /**
+        * @param dataNode current data node
+        * @param version database server version
+        * @since 4.2
+        */
+       public SQLServerActionBuilder(DataNode dataNode, Integer version) {
                super(dataNode);
+               this.version = version;
        }
 
        @Override
        public SQLAction batchAction(BatchQuery query) {
                // check run strategy...
 
-               // optimistic locking is not supported in batches due to JDBC 
driver
-               // limitations
+               // optimistic locking is not supported in batches due to JDBC 
driver limitations
                boolean useOptimisticLock = query.isUsingOptimisticLocking();
-
                boolean runningAsBatch = !useOptimisticLock && 
dataNode.getAdapter().supportsBatchUpdates();
                return new SQLServerBatchAction(query, dataNode, 
runningAsBatch);
        }
@@ -64,12 +73,7 @@ public class SQLServerActionBuilder extends 
JdbcActionBuilder {
         */
        @Override
        public <T> SQLAction objectSelectAction(SelectQuery<T> query) {
-               if (query.getOrderings() == null || query.getOrderings().size() 
== 0 ||
-                               version == null || version < 12) {
-                       return new SQLServerSelectAction(query, dataNode, true);
-               }
-
-               return new SQLServerSelectAction(query, dataNode, false);
+               return new SQLServerSelectAction(query, dataNode, 
needInMemoryOffset(query));
        }
 
        /**
@@ -77,19 +81,16 @@ public class SQLServerActionBuilder extends 
JdbcActionBuilder {
         */
        @Override
        public <T> SQLAction objectSelectAction(FluentSelect<T> query) {
-               if (query.getOrderings() == null || query.getOrderings().size() 
== 0 ||
-                               version == null || version < 12) {
-                       return new SQLServerSelectAction(query, dataNode, true);
-               }
-
-               return new SQLServerSelectAction(query, dataNode, false);
+               return new SQLServerSelectAction(query, dataNode, 
needInMemoryOffset(query));
        }
 
-       public Integer getVersion() {
-               return version;
+       private boolean needInMemoryOffset(SelectQuery<?> query) {
+               return query.getOrderings() == null || 
query.getOrderings().size() == 0
+                               || version == null || version < 12;
        }
 
-       public void setVersion(Integer version) {
-               this.version = version;
+       private boolean needInMemoryOffset(FluentSelect<?> query) {
+               return query.getOrderings() == null || 
query.getOrderings().size() == 0
+                               || version == null || version < 12;
        }
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
index 9805e0d..6642e8e 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
@@ -76,8 +76,7 @@ public class SQLServerAdapter extends SybaseAdapter {
 
        /**
         * Stores the major version of the database.
-        * Database versions 12 and higher support the use of LIMIT,
-        * lower versions use TOP N
+        * Database versions 12 and higher supports the use of LIMIT,lower 
versions use TOP N.
         *
         * @since 4.2
         */
@@ -89,10 +88,12 @@ public class SQLServerAdapter extends SybaseAdapter {
        @Deprecated
        public static final String TRIM_FUNCTION = "RTRIM";
 
-       private List<String> SYSTEM_SCHEMAS = Arrays.asList("db_accessadmin", 
"db_backupoperator",
+       private final List<String> SYSTEM_SCHEMAS = Arrays.asList(
+                       "db_accessadmin", "db_backupoperator",
                        "db_datareader", "db_datawriter", "db_ddladmin", 
"db_denydatareader",
                        "db_denydatawriter","dbo", "sys", "db_owner", 
"db_securityadmin", "guest",
-                       "INFORMATION_SCHEMA");
+                       "INFORMATION_SCHEMA"
+       );
 
        public SQLServerAdapter(@Inject RuntimeProperties runtimeProperties,
                                                        
@Inject(Constants.SERVER_DEFAULT_TYPES_LIST) List<ExtendedType> 
defaultExtendedTypes,
@@ -106,7 +107,7 @@ public class SQLServerAdapter extends SybaseAdapter {
        }
 
     /**
-     * Not supported, see: <a 
href="http://microsoft/mssql-jdbc#245";>mssql-jdbc #245</a>
+     * Not supported, see: <a 
href="https://github.com/microsoft/mssql-jdbc/issues/245";>mssql-jdbc #245</a>
      */
        @Override
        public boolean supportsGeneratedKeysForBatchInserts() {
@@ -118,9 +119,10 @@ public class SQLServerAdapter extends SybaseAdapter {
         */
        @Override
        public SQLTreeProcessor getSqlTreeProcessor() {
-               SQLServerTreeProcessor sqlServerTreeProcessor = new 
SQLServerTreeProcessor();
-               sqlServerTreeProcessor.setVersion(getVersion());
-               return sqlServerTreeProcessor;
+               if(getVersion() != null && getVersion() >= 12) {
+                       return new SQLServerTreeProcessorV12();
+               }
+               return new SQLServerTreeProcessor();
        }
 
        /**
@@ -130,9 +132,7 @@ public class SQLServerAdapter extends SybaseAdapter {
         */
        @Override
        public SQLAction getAction(Query query, DataNode node) {
-               SQLServerActionBuilder sqlServerActionBuilder = new 
SQLServerActionBuilder(node);
-               sqlServerActionBuilder.setVersion(this.version);
-               return query.createSQLAction(sqlServerActionBuilder);
+               return query.createSQLAction(new SQLServerActionBuilder(node, 
getVersion()));
        }
 
        @Override
@@ -144,6 +144,10 @@ public class SQLServerAdapter extends SybaseAdapter {
                return version;
        }
 
+       /**
+        * @since 4.2
+        * @param version of the server as provided by the JDBC driver
+        */
        public void setVersion(Integer version) {
                this.version = version;
        }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSelectAction.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSelectAction.java
index 7c09eef..5c9d7d2 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSelectAction.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSelectAction.java
@@ -29,22 +29,17 @@ import org.apache.cayenne.query.Select;
 public class SQLServerSelectAction extends SelectAction {
 
     /**
-     * When using TOP N instead of LIMIT. The offset will be manual.
-     *
+     * When using TOP N instead of LIMIT the offset will be processed 
in-memory.
      */
-    private Boolean isManualOffset;
+    private final boolean needsInMemoryOffset;
 
-    public SQLServerSelectAction(Select<?> query, DataNode dataNode, Boolean 
isManualOffset) {
+    public SQLServerSelectAction(Select<?> query, DataNode dataNode, boolean 
needsInMemoryOffset) {
         super(query, dataNode);
-
-        this.isManualOffset = isManualOffset;
+        this.needsInMemoryOffset = needsInMemoryOffset;
     }
 
     @Override
     protected int getInMemoryOffset(int queryOffset) {
-        if (isManualOffset) {
-            return super.getInMemoryOffset(queryOffset);
-        }
-        return 0;
+        return needsInMemoryOffset ? super.getInMemoryOffset(queryOffset) : 0;
     }
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessor.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessor.java
index 347da1f..46be80d 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessor.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessor.java
@@ -21,7 +21,6 @@ package org.apache.cayenne.dba.sqlserver;
 
 import org.apache.cayenne.access.sqlbuilder.sqltree.*;
 import org.apache.cayenne.dba.sqlserver.sqltree.SQLServerColumnNode;
-import org.apache.cayenne.dba.sqlserver.sqltree.SQLServerLimitOffsetNode;
 import org.apache.cayenne.dba.sybase.SybaseSQLTreeProcessor;
 
 /**
@@ -29,32 +28,9 @@ import org.apache.cayenne.dba.sybase.SybaseSQLTreeProcessor;
  */
 public class SQLServerTreeProcessor extends SybaseSQLTreeProcessor {
 
-    private Integer version;
-
     @Override
     protected void onColumnNode(Node parent, ColumnNode child, int index) {
-        replaceChild(parent, index,  new SQLServerColumnNode(child));
-    }
-
-    @Override
-    protected void onLimitOffsetNode(Node parent, LimitOffsetNode child, int 
index) {
-        if (version != null && version >= 12) {
-            for (int i = 0; i < parent.getChildrenCount(); i++) {
-                if (parent.getChild(i) instanceof OrderByNode) {
-                    replaceChild(parent, index,  new 
SQLServerLimitOffsetNode(child.getLimit(), child.getOffset()), false);
-                    return;
-                }
-            }
-        }
-
-        super.onLimitOffsetNode(parent, child, index);
-    }
-
-    public Integer getVersion() {
-        return version;
+        replaceChild(parent, index, new SQLServerColumnNode(child));
     }
 
-    public void setVersion(Integer version) {
-        this.version = version;
-    }
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessor.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessorV12.java
similarity index 57%
copy from 
cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessor.java
copy to 
cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessorV12.java
index 347da1f..7a7bb27 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessor.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessorV12.java
@@ -19,42 +19,38 @@
 
 package org.apache.cayenne.dba.sqlserver;
 
-import org.apache.cayenne.access.sqlbuilder.sqltree.*;
-import org.apache.cayenne.dba.sqlserver.sqltree.SQLServerColumnNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.LimitOffsetNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
+import org.apache.cayenne.access.sqlbuilder.sqltree.NodeType;
 import org.apache.cayenne.dba.sqlserver.sqltree.SQLServerLimitOffsetNode;
-import org.apache.cayenne.dba.sybase.SybaseSQLTreeProcessor;
 
 /**
+ * SQL tree processor that supports OFFSET X ROWS FETCH NEXT Y ROWS ONLY clause
+ * for the SQLServer 2012 and later.
+ *
  * @since 4.2
  */
-public class SQLServerTreeProcessor extends SybaseSQLTreeProcessor {
-
-    private Integer version;
-
-    @Override
-    protected void onColumnNode(Node parent, ColumnNode child, int index) {
-        replaceChild(parent, index,  new SQLServerColumnNode(child));
-    }
+public class SQLServerTreeProcessorV12 extends SQLServerTreeProcessor {
 
     @Override
     protected void onLimitOffsetNode(Node parent, LimitOffsetNode child, int 
index) {
-        if (version != null && version >= 12) {
-            for (int i = 0; i < parent.getChildrenCount(); i++) {
-                if (parent.getChild(i) instanceof OrderByNode) {
-                    replaceChild(parent, index,  new 
SQLServerLimitOffsetNode(child.getLimit(), child.getOffset()), false);
-                    return;
-                }
-            }
+        if (hasOrderingClause(parent)) {
+            replaceChild(parent, index, new 
SQLServerLimitOffsetNode(child.getLimit(), child.getOffset()), false);
+            return;
         }
-
         super.onLimitOffsetNode(parent, child, index);
     }
 
-    public Integer getVersion() {
-        return version;
+    protected boolean hasOrderingClause(Node parent) {
+        if(parent == null) {
+            return false;
+        }
+        for (int i = 0; i < parent.getChildrenCount(); i++) {
+            if (parent.getChild(i).getType() == NodeType.ORDER_BY) {
+                return true;
+            }
+        }
+        return hasOrderingClause(parent.getParent());
     }
 
-    public void setVersion(Integer version) {
-        this.version = version;
-    }
 }

Reply via email to