Merge branch 'pr/448' into asf-master
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
index 54baa19..87d0972 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
@@ -270,4 +270,5 @@
public List<String> getSystemSchemas() {
return getAdapter().getSystemSchemas();
}
+
}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java
index a043e2f..54e8580 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/DbAdapter.java
@@ -255,4 +255,5 @@
* @return list of system schemas
*/
List<String> getSystemSchemas();
+
}
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 4ebde3f..bd43ee9 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
@@ -21,9 +21,7 @@
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.dba.JdbcActionBuilder;
-import org.apache.cayenne.query.BatchQuery;
-import org.apache.cayenne.query.ProcedureQuery;
-import org.apache.cayenne.query.SQLAction;
+import org.apache.cayenne.query.*;
/**
* @since 1.2
@@ -31,6 +29,13 @@
public class SQLServerActionBuilder extends JdbcActionBuilder {
/**
+ * Stores the major version of the database.
+ *
+ * @since 4.2
+ */
+ private Integer version;
+
+ /**
* @since 4.0
*/
public SQLServerActionBuilder(DataNode dataNode) {
@@ -53,4 +58,38 @@
public SQLAction procedureAction(ProcedureQuery query) {
return new SQLServerProcedureAction(query, dataNode);
}
+
+ /**
+ * @since 4.2
+ */
+ @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);
+ }
+
+ /**
+ * @since 4.2
+ */
+ @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);
+ }
+
+ public Integer getVersion() {
+ return version;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
}
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 92fcd46..9805e0d 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
@@ -75,6 +75,15 @@
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
+ *
+ * @since 4.2
+ */
+ private Integer version;
+
+ /**
* @deprecated since 4.2 unused
*/
@Deprecated
@@ -109,7 +118,9 @@
*/
@Override
public SQLTreeProcessor getSqlTreeProcessor() {
- return new SQLServerTreeProcessor();
+ SQLServerTreeProcessor sqlServerTreeProcessor = new SQLServerTreeProcessor();
+ sqlServerTreeProcessor.setVersion(getVersion());
+ return sqlServerTreeProcessor;
}
/**
@@ -119,7 +130,9 @@
*/
@Override
public SQLAction getAction(Query query, DataNode node) {
- return query.createSQLAction(new SQLServerActionBuilder(node));
+ SQLServerActionBuilder sqlServerActionBuilder = new SQLServerActionBuilder(node);
+ sqlServerActionBuilder.setVersion(this.version);
+ return query.createSQLAction(sqlServerActionBuilder);
}
@Override
@@ -127,4 +140,11 @@
return SYSTEM_SCHEMAS;
}
+ public Integer getVersion() {
+ return version;
+ }
+
+ 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
new file mode 100644
index 0000000..7c09eef
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSelectAction.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ *
+ * https://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.
+ */
+
+package org.apache.cayenne.dba.sqlserver;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.jdbc.SelectAction;
+import org.apache.cayenne.query.Select;
+
+/**
+ * @since 4.2
+ */
+public class SQLServerSelectAction extends SelectAction {
+
+ /**
+ * When using TOP N instead of LIMIT. The offset will be manual.
+ *
+ */
+ private Boolean isManualOffset;
+
+ public SQLServerSelectAction(Select<?> query, DataNode dataNode, Boolean isManualOffset) {
+ super(query, dataNode);
+
+ this.isManualOffset = isManualOffset;
+ }
+
+ @Override
+ protected int getInMemoryOffset(int queryOffset) {
+ if (isManualOffset) {
+ return super.getInMemoryOffset(queryOffset);
+ }
+ return 0;
+ }
+}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSniffer.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSniffer.java
index 052e8eb..f0c7d6f 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSniffer.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerSniffer.java
@@ -50,6 +50,7 @@
SQLServerAdapter adapter = objectFactory.newInstance(
SQLServerAdapter.class,
SQLServerAdapter.class.getName());
+ adapter.setVersion(md.getDatabaseMajorVersion());
// detect whether generated keys are supported
boolean generatedKeys = false;
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 e2ecd53..347da1f 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
@@ -19,9 +19,9 @@
package org.apache.cayenne.dba.sqlserver;
-import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode;
-import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
+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,8 +29,32 @@
*/
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;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/sqltree/SQLServerLimitOffsetNode.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/sqltree/SQLServerLimitOffsetNode.java
new file mode 100644
index 0000000..1b916aa
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/sqltree/SQLServerLimitOffsetNode.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ * https://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.
+ */
+
+package org.apache.cayenne.dba.sqlserver.sqltree;
+
+import org.apache.cayenne.access.sqlbuilder.QuotingAppendable;
+import org.apache.cayenne.access.sqlbuilder.sqltree.LimitOffsetNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
+
+/**
+ * @since 4.2
+ */
+public class SQLServerLimitOffsetNode extends LimitOffsetNode {
+
+ public SQLServerLimitOffsetNode(int limit, int offset) {
+ super(limit, offset);
+ }
+
+ @Override
+ public QuotingAppendable append(QuotingAppendable buffer) {
+ // OFFSET X ROWS FETCH NEXT Y ROWS ONLY
+ if(limit == 0 && offset == 0) {
+ return buffer;
+ }
+ buffer.append(" OFFSET ").append(offset).append(" ROWS");
+ if (limit > 0) {
+ return buffer.append(" FETCH NEXT ").append(limit).append(" ROWS ONLY");
+ }
+ return buffer;
+ }
+
+ @Override
+ public Node copy() {
+ return new SQLServerLimitOffsetNode(limit, offset);
+ }
+
+}