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