CAY-2650 Support using generated primary keys along with batch inserts

Fixed unit tests for Derby and MSSQL
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java
index 3bcea41..e8ba334 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java
@@ -86,12 +86,16 @@
 	public void performAction(Connection connection, OperationObserver observer) throws SQLException, Exception {
 
 		BatchTranslator translator = createTranslator();
-		boolean generatesKeys = hasGeneratedKeys();
-
-		if (runningAsBatch) {
-			runAsBatch(connection, translator, observer, generatesKeys);
+		
+		boolean isBatch = runningAsBatch && query.getRows().size() > 1;
+		if (isBatch && hasGeneratedKeys() && !supportsGeneratedKeys(isBatch)) {
+			isBatch = false; // turn off batch mode if we generate keys but can't do so in a batch
+		}
+		
+		if (isBatch) {
+			runAsBatch(connection, translator, observer, hasGeneratedKeys() && supportsGeneratedKeys(isBatch));
 		} else {
-			runAsIndividualQueries(connection, translator, observer, generatesKeys);
+			runAsIndividualQueries(connection, translator, observer, hasGeneratedKeys() && supportsGeneratedKeys(isBatch));
 		}
 	}
 
@@ -200,15 +204,18 @@
 				: connection.prepareStatement(queryStr);
 	}
 
+	protected boolean supportsGeneratedKeys(boolean isBatch) {
+		// see if we are configured to support generated keys
+		boolean isSupported = isBatch 
+				? dataNode.getAdapter().supportsGeneratedKeysForBatchInserts() 
+				: dataNode.getAdapter().supportsGeneratedKeys();
+		return isSupported;
+	}
+				
 	/**
 	 * Returns whether BatchQuery generates any keys.
 	 */
 	protected boolean hasGeneratedKeys() {
-		// see if we are configured to support generated keys
-		if (!dataNode.getAdapter().supportsGeneratedKeys()) {
-			return false;
-		}
-
 		// see if the query needs them
 		if (query instanceof InsertBatchQuery) {
 
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 caf61df..c657d6d 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
@@ -103,6 +103,13 @@
 	 */
 	boolean supportsGeneratedKeys();
 
+    /**
+     * @since 4.2
+     */
+    default boolean supportsGeneratedKeysForBatchInserts() {
+    	return supportsGeneratedKeys();
+    }
+    
 	/**
 	 * Returns <code>true</code> if the target database supports batch updates.
 	 */
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyAdapter.java
index 14001b2..aaa4864 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyAdapter.java
@@ -88,6 +88,14 @@
         setSupportsBatchUpdates(true);
     }
 
+    /**
+     * Not supported, see: <a href="https://issues.apache.org/jira/browse/DERBY-3609">DERBY-3609</a>
+     */
+	@Override
+	public boolean supportsGeneratedKeysForBatchInserts() {
+		return false;
+	}
+	
     @Override
     protected PkGenerator createPkGenerator() {
         return new DerbyPkGenerator(this);
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 0da1518..470444f 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
@@ -97,6 +97,14 @@
 		this.setSupportsBatchUpdates(true);
 	}
 
+    /**
+     * Not supported, see: <a href="http://microsoft/mssql-jdbc#245">mssql-jdbc #245</a>
+     */
+	@Override
+	public boolean supportsGeneratedKeysForBatchInserts() {
+		return false;
+	}
+	
 	/**
 	 * @since 4.2
 	 */
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BatchActionGeneratedIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BatchActionGeneratedIT.java
index d226553..166762c 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BatchActionGeneratedIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BatchActionGeneratedIT.java
@@ -79,7 +79,9 @@
         node.setEntityResolver(resolver);
         node.setRowReaderFactory(mock(RowReaderFactory.class));
 
-        assertFalse(new BatchAction(batch1, node, false).hasGeneratedKeys());
+        assertTrue(new BatchAction(batch1, node, false).hasGeneratedKeys());
+        assertFalse(new BatchAction(batch1, node, false).supportsGeneratedKeys(true));
+
     }
 
     JdbcAdapter buildAdapter(boolean supportGeneratedKeys) {