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; - } }