Author: tv
Date: Sun Jan  6 18:46:35 2019
New Revision: 1850586

URL: http://svn.apache.org/viewvc?rev=1850586&view=rev
Log:
TORQUE-357: Add feature to use JDBC-3.0-Statement.getGeneratedKeys() if the 
driver supports it.

Modified:
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/TorqueInstance.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AdapterFactory.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AbstractIdGenerator.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AutoIncrementIdGenerator.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDBroker.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDGeneratorFactory.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IdGenerator.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/SequenceIdGenerator.java
    
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java
    
db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/TorqueInstance.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/TorqueInstance.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/TorqueInstance.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/TorqueInstance.java
 Sun Jan  6 18:46:35 2019
@@ -372,6 +372,17 @@ public class TorqueInstance
                     log.debug("Adding " + adapterKey + " -> "
                             + handle + " as Adapter");
 
+                    // try to get additional meta data from the driver
+                    try (Connection con = database.getDataSourceFactory()
+                            .getDataSource().getConnection())
+                    {
+                        AdapterFactory.setCapabilities(con, adapter);
+                    }
+                    catch (SQLException e)
+                    {
+                        log.debug("Could not get database meta data from 
JDBC");
+                    }
+
                     // add Id generators
                     for (IDMethod idMethod : 
IDGeneratorFactory.ID_GENERATOR_METHODS)
                     {

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java
 Sun Jan  6 18:46:35 2019
@@ -20,6 +20,7 @@ package org.apache.torque.adapter;
  */
 
 import java.sql.Connection;
+import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 
 import org.apache.torque.TorqueException;
@@ -51,6 +52,9 @@ public abstract class AbstractAdapter im
     /** Serial version UID. */
     private static final long serialVersionUID = 1L;
 
+    /** A flag to determine whether Statement#getGeneratedKeys() should be 
used. */
+    private boolean useGetGeneratedKeys = false;
+
     /**
      * Empty constructor.
      */
@@ -280,4 +284,26 @@ public abstract class AbstractAdapter im
     {
         return false;
     }
+
+    /**
+     * whether Statement#getGeneratedKeys() should be used.
+     *
+     * @return a <code>boolean</code> value
+     */
+    public boolean useGetGeneratedKeys()
+    {
+        return this.useGetGeneratedKeys;
+    }
+
+    /**
+     * Update static capabilities of the adapter with actual
+     * readings based on the JDBC meta-data
+     *
+     * @param dmd database meta data
+     * @throws SQLException if there are problems getting the JDBC meta data
+     */
+    public void setCapabilities(DatabaseMetaData dmd) throws SQLException
+    {
+        this.useGetGeneratedKeys = dmd.supportsGetGeneratedKeys();
+    }
 }

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java
 Sun Jan  6 18:46:35 2019
@@ -21,6 +21,7 @@ package org.apache.torque.adapter;
 
 import java.io.Serializable;
 import java.sql.Connection;
+import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 
 import org.apache.torque.TorqueException;
@@ -226,4 +227,20 @@ public interface Adapter extends Seriali
      * @return whether to use the MINUS operator instead of the EXCEPT 
operator.
      */
     boolean useMinusForExcept();
+
+    /**
+     * whether Statement#getGeneratedKeys() should be used.
+     *
+     * @return a <code>boolean</code> value
+     */
+    boolean useGetGeneratedKeys();
+
+    /**
+     * Update static capabilities of the adapter with actual
+     * readings based on the JDBC meta-data
+     *
+     * @param dmd database meta data
+     * @throws SQLException if there are problems getting the JDBC meta data
+     */
+    void setCapabilities(DatabaseMetaData dmd) throws SQLException;
 }

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AdapterFactory.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AdapterFactory.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AdapterFactory.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AdapterFactory.java
 Sun Jan  6 18:46:35 2019
@@ -128,6 +128,21 @@ public final class AdapterFactory
     }
 
     /**
+     * Update static capabilities of the Torque database adapter with actual
+     * readings based on the JDBC meta-data
+     *
+     * @param con a database connection
+     * @param adapter an adapter
+     * @throws SQLException if there are problems getting the JDBC meta data
+     */
+    public static void setCapabilities(Connection con, Adapter adapter)
+            throws SQLException
+    {
+        DatabaseMetaData dmd = con.getMetaData();
+        adapter.setCapabilities(dmd);
+    }
+
+    /**
      * Creates a new instance of the Torque database adapter associated
      * with the specified JDBC driver or adapter key.
      *

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AbstractIdGenerator.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AbstractIdGenerator.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AbstractIdGenerator.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AbstractIdGenerator.java
 Sun Jan  6 18:46:35 2019
@@ -21,6 +21,9 @@ package org.apache.torque.oid;
 
 import java.math.BigDecimal;
 import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.List;
 
 import org.apache.torque.TorqueException;
@@ -158,6 +161,15 @@ public abstract class AbstractIdGenerato
     public abstract boolean isConnectionRequired();
 
     /**
+     * A flag to determine whether Statement#getGeneratedKeys()
+     * should be used.
+     *
+     * @return a <code>boolean</code> value
+     */
+    @Override
+    public abstract boolean isGetGeneratedKeysSupported();
+
+    /**
      * Returns the last ID used by this connection.
      *
      * @param connection A Connection.
@@ -174,11 +186,32 @@ public abstract class AbstractIdGenerato
             final RecordMapper<T> mapper)
                     throws TorqueException
     {
-        String idSql = getIdSql(keyInfo);
-
-        BasePeerImpl<T> peer = new BasePeerImpl<>(mapper, null, databaseName);
-        List<T> result = peer.doSelect(idSql, connection);
-        return result.get(0);
+        if (isGetGeneratedKeysSupported() && keyInfo instanceof Statement)
+        {
+            try (ResultSet generatedKeys = ((Statement) 
keyInfo).getGeneratedKeys())
+            {
+                if (generatedKeys.next())
+                {
+                    return mapper.processRow(generatedKeys, 0, null);
+                }
+                else
+                {
+                    throw new SQLException("Could not obtain ID from 
statement, result set is empty");
+                }
+            }
+            catch (SQLException e)
+            {
+                throw new TorqueException("Error getting ID", e);
+            }
+        }
+        else
+        {
+            String idSql = getIdSql(keyInfo);
+
+            BasePeerImpl<T> peer = new BasePeerImpl<>(mapper, null, 
databaseName);
+            List<T> result = peer.doSelect(idSql, connection);
+            return result.get(0);
+        }
     }
 
     /**

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AutoIncrementIdGenerator.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AutoIncrementIdGenerator.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AutoIncrementIdGenerator.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/AutoIncrementIdGenerator.java
 Sun Jan  6 18:46:35 2019
@@ -78,4 +78,16 @@ public class AutoIncrementIdGenerator ex
     {
         return true;
     }
+
+    /**
+     * A flag to determine whether Statement#getGeneratedKeys()
+     * should be used.
+     *
+     * @return a <code>boolean</code> value
+     */
+    @Override
+    public boolean isGetGeneratedKeysSupported()
+    {
+        return adapter.useGetGeneratedKeys();
+    }
 }

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDBroker.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDBroker.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDBroker.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDBroker.java
 Sun Jan  6 18:46:35 2019
@@ -374,6 +374,18 @@ public class IDBroker implements Runnabl
     }
 
     /**
+     * A flag to determine whether Statement#getGeneratedKeys()
+     * should be used.
+     *
+     * @return a <code>boolean</code> value
+     */
+    @Override
+    public boolean isGetGeneratedKeysSupported()
+    {
+        return false;
+    }
+
+    /**
      * Returns whether the idbroker thread is running.
      *
      * @return true if the thread is running, false otherwise.

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDGeneratorFactory.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDGeneratorFactory.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDGeneratorFactory.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IDGeneratorFactory.java
 Sun Jan  6 18:46:35 2019
@@ -19,9 +19,10 @@ package org.apache.torque.oid;
  * under the License.
  */
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.adapter.IDMethod;
@@ -39,16 +40,12 @@ public final class IDGeneratorFactory
      * The list of ID generation method types which have associated
      * {@link org.apache.torque.oid.IdGenerator} implementations.
      */
-    public static final List<IDMethod> ID_GENERATOR_METHODS;
-
-    static
-    {
-        List<IDMethod> idGeneratorMethods = new ArrayList<>();
-        idGeneratorMethods.add(IDMethod.NATIVE);
-        idGeneratorMethods.add(IDMethod.AUTO_INCREMENT);
-        idGeneratorMethods.add(IDMethod.SEQUENCE);
-        ID_GENERATOR_METHODS = 
Collections.unmodifiableList(idGeneratorMethods);
-    }
+    public static final List<IDMethod> ID_GENERATOR_METHODS =
+            Collections.unmodifiableList(Stream.of(
+                IDMethod.NATIVE,
+                IDMethod.AUTO_INCREMENT,
+                IDMethod.SEQUENCE
+                ).collect(Collectors.toList()));
 
     /**
      * Private constructor to prevent initialisation.
@@ -74,18 +71,16 @@ public final class IDGeneratorFactory
      */
     public static IdGenerator create(Adapter adapter, String name)
     {
-        IDMethod idMethod = adapter.getIDMethodType();
-        if (IDMethod.AUTO_INCREMENT == idMethod)
-        {
-            return new AutoIncrementIdGenerator(adapter, name);
-        }
-        else if (IDMethod.SEQUENCE == idMethod)
+        switch (adapter.getIDMethodType())
         {
-            return new SequenceIdGenerator(adapter, name);
-        }
-        else
-        {
-            return null;
+            case AUTO_INCREMENT:
+                return new AutoIncrementIdGenerator(adapter, name);
+
+            case SEQUENCE:
+                return new SequenceIdGenerator(adapter, name);
+
+            default:
+                return null;
         }
     }
 }

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IdGenerator.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IdGenerator.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IdGenerator.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/IdGenerator.java
 Sun Jan  6 18:46:35 2019
@@ -113,4 +113,12 @@ public interface IdGenerator
      * @return a <code>boolean</code> value
      */
     boolean isConnectionRequired();
+
+    /**
+     * A flag to determine whether Statement#getGeneratedKeys()
+     * should be used.
+     *
+     * @return a <code>boolean</code> value
+     */
+    boolean isGetGeneratedKeysSupported();
 }

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/SequenceIdGenerator.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/SequenceIdGenerator.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/SequenceIdGenerator.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/oid/SequenceIdGenerator.java
 Sun Jan  6 18:46:35 2019
@@ -75,4 +75,16 @@ public class SequenceIdGenerator extends
     {
         return true;
     }
+
+    /**
+     * A flag to determine whether Statement#getGeneratedKeys()
+     * should be used.
+     *
+     * @return a <code>boolean</code> value
+     */
+    @Override
+    public boolean isGetGeneratedKeysSupported()
+    {
+        return false;
+    }
 }

Modified: 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java
 Sun Jan  6 18:46:35 2019
@@ -391,8 +391,7 @@ public class BasePeerImpl<T> implements
             // primaryKey will be null if there is no primary key
             // defined for the table we're inserting into.
             if (keyGen.isPriorToInsert() && primaryKey != null
-                    && !insertValues.containsKey(
-                            primaryKey))
+                    && !insertValues.containsKey(primaryKey))
             {
                 id = getId(primaryKey, keyGen, connection, keyInfo);
                 insertValues.put(
@@ -401,21 +400,20 @@ public class BasePeerImpl<T> implements
             }
         }
 
-        List<String> columnNames = new ArrayList<>();
-        insertValues.keySet().forEach((column) -> 
columnNames.add(column.getColumnName()));
+        String columnNamesList = insertValues.keySet().stream()
+                .map((column) -> column.getColumnName())
+                .collect(Collectors.joining(",", "(", ")"));
 
         String fullTableName = SqlBuilder.getFullTableName(
                 getTableMap().getFullyQualifiedTableName(),
                 databaseNameFromInsertValues);
         StringBuilder query = new StringBuilder("INSERT INTO ")
                 .append(fullTableName)
-                .append("(")
-                .append(StringUtils.join(columnNames, ","))
-                .append(") VALUES (");
+                .append(columnNamesList)
+                .append(" VALUES (");
 
         boolean first = true;
-        List<JdbcTypedValue> replacementObjects
-            = new ArrayList<>();
+        List<JdbcTypedValue> replacementObjects = new ArrayList<>();
         for (Map.Entry<Column, JdbcTypedValue> columnValue
                 : insertValues.entrySet())
         {
@@ -430,15 +428,21 @@ public class BasePeerImpl<T> implements
             }
             else
             {
-                Column sqlExpression
-                = columnValue.getValue().getSqlExpression();
+                Column sqlExpression = 
columnValue.getValue().getSqlExpression();
                 query.append(sqlExpression.getSqlExpression());
             }
             first = false;
         }
         query.append(")");
 
-        try (PreparedStatement preparedStatement = 
connection.prepareStatement(query.toString()))
+        boolean useGetGeneratedKeys = keyGen != null
+                && keyGen.isGetGeneratedKeysSupported()
+                && primaryKey != null && !insertValues.containsKey(primaryKey);
+
+        try (PreparedStatement preparedStatement = useGetGeneratedKeys ?
+                        connection.prepareStatement(query.toString(),
+                                Statement.RETURN_GENERATED_KEYS) :
+                        connection.prepareStatement(query.toString()))
         {
             int position = 1;
             for (JdbcTypedValue replacementObject : replacementObjects)
@@ -477,22 +481,30 @@ public class BasePeerImpl<T> implements
             stopWatch.start();
             preparedStatement.executeUpdate();
             log.trace("Insert took " + stopWatch.getTime() + " milliseconds");
+
+            if (keyGen != null && keyGen.isPostInsert()
+                && primaryKey != null
+                && !insertValues.containsKey(primaryKey))
+            {
+                if (keyGen.isGetGeneratedKeysSupported())
+                {
+                    // If the id-generator supports getGeneratedKeys(), get id
+                    // now.
+                    id = getId(primaryKey, keyGen, connection, 
preparedStatement);
+                }
+                else
+                {
+                    // If the primary key column is auto-incremented, get the 
id
+                    // now.
+                    id = getId(primaryKey, keyGen, connection, keyInfo);
+                }
+            }
         }
         catch (SQLException e)
         {
             throw ExceptionMapper.getInstance().toTorqueException(e);
         }
 
-        // If the primary key column is auto-incremented, get the id
-        // now.
-        if (keyGen != null && keyGen.isPostInsert()
-                && primaryKey != null
-                && !insertValues.containsKey(
-                        primaryKey))
-        {
-            id = getId(primaryKey, keyGen, connection, keyInfo);
-        }
-
         return id;
     }
 

Modified: 
db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java?rev=1850586&r1=1850585&r2=1850586&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java
 (original)
+++ 
db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java
 Sun Jan  6 18:46:35 2019
@@ -111,6 +111,7 @@ public class BasePeerImplTest extends Ba
         .thenReturn(DEFAULT_GENERATED_ID);
         when(idGenerator.isPriorToInsert()).thenReturn(true);
         when(idGenerator.isPostInsert()).thenReturn(false);
+        when(idGenerator.isGetGeneratedKeysSupported()).thenReturn(false);
         Transaction.setTransactionManager(transactionManager);
     }
 
@@ -519,6 +520,7 @@ public class BasePeerImplTest extends Ba
         verify(transactionManager).commit(connection);
         verify(idGenerator).isPriorToInsert();
         verify(idGenerator).isPostInsert();
+        verify(idGenerator).isGetGeneratedKeysSupported();
         verify(idGenerator).getIdAsBigDecimal(connection, null);
         verifyNoMoreInteractions(connection, preparedStatement, resultSet, 
transactionManager, idGenerator);
         // verify result



---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscr...@db.apache.org
For additional commands, e-mail: torque-dev-h...@db.apache.org

Reply via email to