From 23ee88a55b2779c8a57559a948d6d0ea2bde75cc Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 12 Feb 2010 06:22:52 +0000 Subject: [PATCH] HHH-4905 - Allow consistent handling of numeric primary key values by any integral data type git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18789 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../org/hibernate/engine/VersionValue.java | 4 +- .../id/IdentifierGeneratorHelper.java | 525 +++++++++++++++++- .../org/hibernate/id/IncrementGenerator.java | 32 +- .../hibernate/id/IntegralDataTypeHolder.java | 206 +++++++ .../id/MultipleHiLoPerTableGenerator.java | 56 +- .../org/hibernate/id/SequenceGenerator.java | 26 +- .../hibernate/id/SequenceHiLoGenerator.java | 43 +- .../java/org/hibernate/id/TableGenerator.java | 63 ++- .../org/hibernate/id/TableHiLoGenerator.java | 38 +- .../hibernate/id/enhanced/AccessCallback.java | 4 +- .../org/hibernate/id/enhanced/Optimizer.java | 8 +- .../id/enhanced/OptimizerFactory.java | 122 ++-- .../id/enhanced/SequenceStructure.java | 20 +- .../id/enhanced/SequenceStyleGenerator.java | 19 +- .../hibernate/id/enhanced/TableGenerator.java | 33 +- .../hibernate/id/enhanced/TableStructure.java | 29 +- .../org/hibernate/id/AbstractHolderTest.java | 167 ++++++ .../hibernate/id/BigDecimalHolderTest.java | 37 ++ .../hibernate/id/BigIntegerHolderTest.java | 37 ++ .../java/org/hibernate/id/LongHolderTest.java | 35 ++ .../BigIntegerIncrementGeneratorTest.java | 73 +++ .../idgen/biginteger/increment/Entity.java | 59 ++ .../biginteger/increment/Mapping.hbm.xml | 42 ++ .../BigIntegerSequenceGeneratorTest.java | 79 +++ .../idgen/biginteger/sequence/Entity.java | 59 ++ .../idgen/biginteger/sequence/Mapping.hbm.xml | 43 ++ .../idgen/enhanced/OptimizerUnitTest.java | 14 +- .../BasicForcedTableSequenceTest.java | 12 +- .../HiLoForcedTableSequenceTest.java | 22 +- .../PooledForcedTableSequenceTest.java | 26 +- .../enhanced/sequence/BasicSequenceTest.java | 4 +- .../enhanced/sequence/HiLoSequenceTest.java | 15 +- .../enhanced/sequence/PooledSequenceTest.java | 12 +- .../idgen/enhanced/table/BasicTableTest.java | 4 +- .../idgen/enhanced/table/HiLoTableTest.java | 14 +- .../idgen/enhanced/table/PooledTableTest.java | 12 +- 36 files changed, 1738 insertions(+), 256 deletions(-) create mode 100644 core/src/main/java/org/hibernate/id/IntegralDataTypeHolder.java create mode 100644 core/src/test/java/org/hibernate/id/AbstractHolderTest.java create mode 100644 core/src/test/java/org/hibernate/id/BigDecimalHolderTest.java create mode 100644 core/src/test/java/org/hibernate/id/BigIntegerHolderTest.java create mode 100644 core/src/test/java/org/hibernate/id/LongHolderTest.java create mode 100644 testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/BigIntegerIncrementGeneratorTest.java create mode 100644 testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/Entity.java create mode 100644 testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/Mapping.hbm.xml create mode 100644 testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/BigIntegerSequenceGeneratorTest.java create mode 100644 testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/Entity.java create mode 100644 testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/Mapping.hbm.xml diff --git a/core/src/main/java/org/hibernate/engine/VersionValue.java b/core/src/main/java/org/hibernate/engine/VersionValue.java index d58fa767bc..fa2ae7c0fc 100755 --- a/core/src/main/java/org/hibernate/engine/VersionValue.java +++ b/core/src/main/java/org/hibernate/engine/VersionValue.java @@ -91,7 +91,9 @@ public class VersionValue { } } public Object getDefaultValue(Object currentValue) { - return IdentifierGeneratorHelper.createNumber( -1l, currentValue.getClass() ); + return IdentifierGeneratorHelper.getIntegralDataTypeHolder( currentValue.getClass() ) + .initialize( -1L ) + .makeValue(); } public String toString() { return "VERSION_NEGATIVE"; diff --git a/core/src/main/java/org/hibernate/id/IdentifierGeneratorHelper.java b/core/src/main/java/org/hibernate/id/IdentifierGeneratorHelper.java index ee4330b220..5dce34f303 100644 --- a/core/src/main/java/org/hibernate/id/IdentifierGeneratorHelper.java +++ b/core/src/main/java/org/hibernate/id/IdentifierGeneratorHelper.java @@ -25,6 +25,9 @@ package org.hibernate.id; import java.io.Serializable; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -119,10 +122,17 @@ public final class IdentifierGeneratorHelper { else if ( clazz == String.class ) { return rs.getString( 1 ); } - else { - throw new IdentifierGenerationException( "this id generator generates long, integer, short or string" ); + else if ( clazz == BigInteger.class ) { + return rs.getBigDecimal( 1 ).setScale( 0, BigDecimal.ROUND_UNNECESSARY ).toBigInteger(); + } + else if ( clazz == BigDecimal.class ) { + return rs.getBigDecimal( 1 ).setScale( 0, BigDecimal.ROUND_UNNECESSARY ); + } + else { + throw new IdentifierGenerationException( + "unrecognized id type : " + type.getName() + " -> " + clazz.getName() + ); } - } /** @@ -130,8 +140,12 @@ public final class IdentifierGeneratorHelper { * * @param value The primitive value to wrap. * @param clazz The Java numeric type in which to wrap the value. + * * @return The wrapped type. + * * @throws IdentifierGenerationException Indicates an unhandled 'clazz'. + * + * @deprecated Use the {@link #getIntegralDataTypeHolder holders} instead. */ public static Number createNumber(long value, Class clazz) throws IdentifierGenerationException { if ( clazz == Long.class ) { @@ -144,7 +158,510 @@ public final class IdentifierGeneratorHelper { return new Short( ( short ) value ); } else { - throw new IdentifierGenerationException( "this id generator generates long, integer, short" ); + throw new IdentifierGenerationException( "unrecognized id type : " + clazz.getName() ); + } + } + + public static IntegralDataTypeHolder getIntegralDataTypeHolder(Class integralType) { + if ( integralType == Long.class + || integralType == Integer.class + || integralType == Short.class ) { + return new BasicHolder( integralType ); + } + else if ( integralType == BigInteger.class ) { + return new BigIntegerHolder(); + } + else if ( integralType == BigDecimal.class ) { + return new BigDecimalHolder(); + } + else { + throw new IdentifierGenerationException( + "Unknown integral data type for ids : " + integralType.getName() + ); + } + } + + public static long extractLong(IntegralDataTypeHolder holder) { + if ( holder.getClass() == BasicHolder.class ) { + ( (BasicHolder) holder ).checkInitialized(); + return ( (BasicHolder) holder ).value; + } + else if ( holder.getClass() == BigIntegerHolder.class ) { + ( (BigIntegerHolder) holder ).checkInitialized(); + return ( (BigIntegerHolder) holder ).value.longValue(); + } + else if ( holder.getClass() == BigDecimalHolder.class ) { + ( (BigDecimalHolder) holder ).checkInitialized(); + return ( (BigDecimalHolder) holder ).value.longValue(); + } + throw new IdentifierGenerationException( "Unknown IntegralDataTypeHolder impl [" + holder + "]" ); + } + + public static BigInteger extractBigInteger(IntegralDataTypeHolder holder) { + if ( holder.getClass() == BasicHolder.class ) { + ( (BasicHolder) holder ).checkInitialized(); + return BigInteger.valueOf( ( (BasicHolder) holder ).value ); + } + else if ( holder.getClass() == BigIntegerHolder.class ) { + ( (BigIntegerHolder) holder ).checkInitialized(); + return ( (BigIntegerHolder) holder ).value; + } + else if ( holder.getClass() == BigDecimalHolder.class ) { + ( (BigDecimalHolder) holder ).checkInitialized(); + // scale should already be set... + return ( (BigDecimalHolder) holder ).value.toBigInteger(); + } + throw new IdentifierGenerationException( "Unknown IntegralDataTypeHolder impl [" + holder + "]" ); + } + + public static BigDecimal extractBigDecimal(IntegralDataTypeHolder holder) { + if ( holder.getClass() == BasicHolder.class ) { + ( (BasicHolder) holder ).checkInitialized(); + return BigDecimal.valueOf( ( (BasicHolder) holder ).value ); + } + else if ( holder.getClass() == BigIntegerHolder.class ) { + ( (BigIntegerHolder) holder ).checkInitialized(); + return new BigDecimal( ( (BigIntegerHolder) holder ).value ); + } + else if ( holder.getClass() == BigDecimalHolder.class ) { + ( (BigDecimalHolder) holder ).checkInitialized(); + // scale should already be set... + return ( (BigDecimalHolder) holder ).value; + } + throw new IdentifierGenerationException( "Unknown IntegralDataTypeHolder impl [" + holder + "]" ); + } + + public static class BasicHolder implements IntegralDataTypeHolder { + private final Class exactType; + private long value = Long.MIN_VALUE; + + public BasicHolder(Class exactType) { + this.exactType = exactType; + if ( exactType != Long.class && exactType != Integer.class && exactType != Short.class ) { + throw new IdentifierGenerationException( "Invalid type for basic integral holder : " + exactType ); + } + } + + public long getActualLongValue() { + return value; + } + + public IntegralDataTypeHolder initialize(long value) { + this.value = value; + return this; + } + + public IntegralDataTypeHolder initialize(ResultSet resultSet, long defaultValue) throws SQLException { + long value = resultSet.getLong( 1 ); + if ( resultSet.wasNull() ) { + value = defaultValue; + } + return initialize( value ); + } + + public void bind(PreparedStatement preparedStatement, int position) throws SQLException { + // TODO : bind it as 'exact type'? Not sure if that gains us anything... + preparedStatement.setLong( position, value ); + } + + public IntegralDataTypeHolder increment() { + checkInitialized(); + value++; + return this; + } + + private void checkInitialized() { + if ( value == Long.MIN_VALUE ) { + throw new IdentifierGenerationException( "integral holder was not initialized" ); + } + } + + public IntegralDataTypeHolder add(long addend) { + checkInitialized(); + value += addend; + return this; + } + + public IntegralDataTypeHolder decrement() { + checkInitialized(); + value--; + return this; + } + + public IntegralDataTypeHolder subtract(long subtrahend) { + checkInitialized(); + value -= subtrahend; + return this; + } + + public IntegralDataTypeHolder multiplyBy(IntegralDataTypeHolder factor) { + return multiplyBy( extractLong( factor ) ); + } + + public IntegralDataTypeHolder multiplyBy(long factor) { + checkInitialized(); + value *= factor; + return this; + } + + public boolean eq(IntegralDataTypeHolder other) { + return eq( extractLong( other ) ); + } + + public boolean eq(long value) { + checkInitialized(); + return this.value == value; + } + + public boolean lt(IntegralDataTypeHolder other) { + return lt( extractLong( other ) ); + } + + public boolean lt(long value) { + checkInitialized(); + return this.value < value; + } + + public boolean gt(IntegralDataTypeHolder other) { + return gt( extractLong( other ) ); + } + + public boolean gt(long value) { + checkInitialized(); + return this.value > value; + } + + public IntegralDataTypeHolder copy() { + BasicHolder copy = new BasicHolder( exactType ); + copy.value = value; + return copy; + } + + public Number makeValue() { + // TODO : should we check for truncation? + checkInitialized(); + if ( exactType == Long.class ) { + return new Long( value ); + } + else if ( exactType == Integer.class ) { + return new Integer( ( int ) value ); + } + else { + return new Short( ( short ) value ); + } + } + + public Number makeValueThenIncrement() { + final Number result = makeValue(); + value++; + return result; + } + + public Number makeValueThenAdd(long addend) { + final Number result = makeValue(); + value += addend; + return result; + } + + public String toString() { + return "BasicHolder[" + exactType.getName() + "[" + value + "]]"; + } + + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + BasicHolder that = (BasicHolder) o; + + return value == that.value; + } + + public int hashCode() { + return (int) ( value ^ ( value >>> 32 ) ); + } + } + + public static class BigIntegerHolder implements IntegralDataTypeHolder { + private BigInteger value; + + public IntegralDataTypeHolder initialize(long value) { + this.value = BigInteger.valueOf( value ); + return this; + } + + public IntegralDataTypeHolder initialize(ResultSet resultSet, long defaultValue) throws SQLException { + final BigDecimal rsValue = resultSet.getBigDecimal( 1 ); + if ( resultSet.wasNull() ) { + return initialize( defaultValue ); + } + this.value = rsValue.setScale( 0, BigDecimal.ROUND_UNNECESSARY ).toBigInteger(); + return this; + } + + public void bind(PreparedStatement preparedStatement, int position) throws SQLException { + preparedStatement.setBigDecimal( position, new BigDecimal( value ) ); + } + + public IntegralDataTypeHolder increment() { + checkInitialized(); + value = value.add( BigInteger.ONE ); + return this; + } + + private void checkInitialized() { + if ( value == null ) { + throw new IdentifierGenerationException( "integral holder was not initialized" ); + } + } + + public IntegralDataTypeHolder add(long increment) { + checkInitialized(); + value = value.add( BigInteger.valueOf( increment ) ); + return this; + } + + public IntegralDataTypeHolder decrement() { + checkInitialized(); + value = value.subtract( BigInteger.ONE ); + return this; + } + + public IntegralDataTypeHolder subtract(long subtrahend) { + checkInitialized(); + value = value.subtract( BigInteger.valueOf( subtrahend ) ); + return this; + } + + public IntegralDataTypeHolder multiplyBy(IntegralDataTypeHolder factor) { + checkInitialized(); + value = value.multiply( extractBigInteger( factor ) ); + return this; + } + + public IntegralDataTypeHolder multiplyBy(long factor) { + checkInitialized(); + value = value.multiply( BigInteger.valueOf( factor ) ); + return this; + } + + public boolean eq(IntegralDataTypeHolder other) { + checkInitialized(); + return value.compareTo( extractBigInteger( other ) ) == 0; + } + + public boolean eq(long value) { + checkInitialized(); + return this.value.compareTo( BigInteger.valueOf( value ) ) == 0; + } + + public boolean lt(IntegralDataTypeHolder other) { + checkInitialized(); + return value.compareTo( extractBigInteger( other ) ) < 0; + } + + public boolean lt(long value) { + checkInitialized(); + return this.value.compareTo( BigInteger.valueOf( value ) ) < 0; + } + + public boolean gt(IntegralDataTypeHolder other) { + checkInitialized(); + return value.compareTo( extractBigInteger( other ) ) > 0; + } + + public boolean gt(long value) { + checkInitialized(); + return this.value.compareTo( BigInteger.valueOf( value ) ) > 0; + } + + public IntegralDataTypeHolder copy() { + BigIntegerHolder copy = new BigIntegerHolder(); + copy.value = value; + return copy; + } + + public Number makeValue() { + checkInitialized(); + return value; + } + + public Number makeValueThenIncrement() { + final Number result = makeValue(); + value = value.add( BigInteger.ONE ); + return result; + } + + public Number makeValueThenAdd(long addend) { + final Number result = makeValue(); + value = value.add( BigInteger.valueOf( addend ) ); + return result; + } + + public String toString() { + return "BigIntegerHolder[" + value + "]"; + } + + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + BigIntegerHolder that = (BigIntegerHolder) o; + + return this.value == null + ? that.value == null + : value.equals( that.value ); + } + + public int hashCode() { + return value != null ? value.hashCode() : 0; + } + } + + public static class BigDecimalHolder implements IntegralDataTypeHolder { + private BigDecimal value; + + public IntegralDataTypeHolder initialize(long value) { + this.value = BigDecimal.valueOf( value ); + return this; + } + + public IntegralDataTypeHolder initialize(ResultSet resultSet, long defaultValue) throws SQLException { + final BigDecimal rsValue = resultSet.getBigDecimal( 1 ); + if ( resultSet.wasNull() ) { + return initialize( defaultValue ); + } + this.value = rsValue.setScale( 0, BigDecimal.ROUND_UNNECESSARY ); + return this; + } + + public void bind(PreparedStatement preparedStatement, int position) throws SQLException { + preparedStatement.setBigDecimal( position, value ); + } + + public IntegralDataTypeHolder increment() { + checkInitialized(); + value = value.add( BigDecimal.ONE ); + return this; + } + + private void checkInitialized() { + if ( value == null ) { + throw new IdentifierGenerationException( "integral holder was not initialized" ); + } + } + + public IntegralDataTypeHolder add(long increment) { + checkInitialized(); + value = value.add( BigDecimal.valueOf( increment ) ); + return this; + } + + public IntegralDataTypeHolder decrement() { + checkInitialized(); + value = value.subtract( BigDecimal.ONE ); + return this; + } + + public IntegralDataTypeHolder subtract(long subtrahend) { + checkInitialized(); + value = value.subtract( BigDecimal.valueOf( subtrahend ) ); + return this; + } + + public IntegralDataTypeHolder multiplyBy(IntegralDataTypeHolder factor) { + checkInitialized(); + value = value.multiply( extractBigDecimal( factor ) ); + return this; + } + + public IntegralDataTypeHolder multiplyBy(long factor) { + checkInitialized(); + value = value.multiply( BigDecimal.valueOf( factor ) ); + return this; + } + + public boolean eq(IntegralDataTypeHolder other) { + checkInitialized(); + return value.compareTo( extractBigDecimal( other ) ) == 0; + } + + public boolean eq(long value) { + checkInitialized(); + return this.value.compareTo( BigDecimal.valueOf( value ) ) == 0; + } + + public boolean lt(IntegralDataTypeHolder other) { + checkInitialized(); + return value.compareTo( extractBigDecimal( other ) ) < 0; + } + + public boolean lt(long value) { + checkInitialized(); + return this.value.compareTo( BigDecimal.valueOf( value ) ) < 0; + } + + public boolean gt(IntegralDataTypeHolder other) { + checkInitialized(); + return value.compareTo( extractBigDecimal( other ) ) > 0; + } + + public boolean gt(long value) { + checkInitialized(); + return this.value.compareTo( BigDecimal.valueOf( value ) ) > 0; + } + + public IntegralDataTypeHolder copy() { + BigDecimalHolder copy = new BigDecimalHolder(); + copy.value = value; + return copy; + } + + public Number makeValue() { + checkInitialized(); + return value; + } + + public Number makeValueThenIncrement() { + final Number result = makeValue(); + value = value.add( BigDecimal.ONE ); + return result; + } + + public Number makeValueThenAdd(long addend) { + final Number result = makeValue(); + value = value.add( BigDecimal.valueOf( addend ) ); + return result; + } + + public String toString() { + return "BigDecimalHolder[" + value + "]"; + } + + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + BigDecimalHolder that = (BigDecimalHolder) o; + + return this.value == null + ? that.value == null + : this.value.equals( that.value ); + } + + public int hashCode() { + return value != null ? value.hashCode() : 0; } } diff --git a/core/src/main/java/org/hibernate/id/IncrementGenerator.java b/core/src/main/java/org/hibernate/id/IncrementGenerator.java index 567d4be0e3..f1485995a0 100644 --- a/core/src/main/java/org/hibernate/id/IncrementGenerator.java +++ b/core/src/main/java/org/hibernate/id/IncrementGenerator.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,7 +20,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.id; @@ -53,20 +52,21 @@ import org.hibernate.util.StringHelper; * (The tables parameter specified a comma-separated list of table names.) * * @author Gavin King + * @author Steve Ebersole */ public class IncrementGenerator implements IdentifierGenerator, Configurable { - private static final Logger log = LoggerFactory.getLogger(IncrementGenerator.class); - private long next; - private String sql; private Class returnClass; + private String sql; + + private IntegralDataTypeHolder previousValueHolder; public synchronized Serializable generate(SessionImplementor session, Object object) throws HibernateException { if ( sql != null ) { - getNext( session ); + initializePreviousValueHolder( session ); } - return IdentifierGeneratorHelper.createNumber( next++, returnClass ); + return previousValueHolder.makeValueThenIncrement(); } public void configure(Type type, Properties params, Dialect dialect) throws MappingException { @@ -117,22 +117,23 @@ public class IncrementGenerator implements IdentifierGenerator, Configurable { sql = "select max(" + column + ") from " + buf.toString(); } - private void getNext( SessionImplementor session ) { + private void initializePreviousValueHolder(SessionImplementor session) { + previousValueHolder = IdentifierGeneratorHelper.getIntegralDataTypeHolder( returnClass ); + log.debug( "fetching initial value: " + sql ); try { - PreparedStatement st = session.getBatcher().prepareSelectStatement(sql); + PreparedStatement st = session.getBatcher().prepareSelectStatement( sql ); try { ResultSet rs = st.executeQuery(); try { if ( rs.next() ) { - next = rs.getLong(1) + 1; - if ( rs.wasNull() ) next = 1; + previousValueHolder.initialize( rs, 0L ).increment(); } else { - next = 1; + previousValueHolder.initialize( 1L ); } - sql=null; - log.debug("first free id: " + next); + sql = null; + log.debug( "first free id: " + previousValueHolder.makeValue() ); } finally { rs.close(); @@ -141,7 +142,6 @@ public class IncrementGenerator implements IdentifierGenerator, Configurable { finally { session.getBatcher().closeStatement(st); } - } catch (SQLException sqle) { throw JDBCExceptionHelper.convert( diff --git a/core/src/main/java/org/hibernate/id/IntegralDataTypeHolder.java b/core/src/main/java/org/hibernate/id/IntegralDataTypeHolder.java new file mode 100644 index 0000000000..c1a547371b --- /dev/null +++ b/core/src/main/java/org/hibernate/id/IntegralDataTypeHolder.java @@ -0,0 +1,206 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.id; + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Defines a common api for dealing with data of integral data type. + * + * @author Steve Ebersole + */ +public interface IntegralDataTypeHolder extends Serializable { + /** + * Initialize the internal value from the given primitive long. + * + * @param value The primitive integral value. + * + * @return this, for method chaining + */ + public IntegralDataTypeHolder initialize(long value); + + /** + * Initialize the internal value from the given result set, using the specified default value + * if we could not get a value from the result set (aka result was null). + * + * @param resultSet The JDBC result set + * @param defaultValue The default value to use if we did not get a result set value. + * + * @return this, for method chaining + * + * @throws SQLException Any exception from accessing the result set + */ + public IntegralDataTypeHolder initialize(ResultSet resultSet, long defaultValue) throws SQLException; + + /** + * Bind this holders internal value to the given result set. + * + * @param preparedStatement The JDBC prepared statement + * @param position The position at which to bind + * + * @throws SQLException Any exception from accessing the statement + */ + public void bind(PreparedStatement preparedStatement, int position) throws SQLException; + + /** + * Equivalent to a ++ operation + * + * @return this, for method chaining + */ + public IntegralDataTypeHolder increment(); + + /** + * Perform an addition + * + * @param addend The value to add to this integral. + * + * @return this, for method chaining + */ + public IntegralDataTypeHolder add(long addend); + + /** + * Equivalent to a -- operation + * + * @return this, for method chaining + */ + public IntegralDataTypeHolder decrement(); + + /** + * Perform a subtraction + * + * @param subtrahend The value to subtract from this integral. + * + * @return this, for method chaining + */ + public IntegralDataTypeHolder subtract(long subtrahend); + + /** + * Perform a multiplication. + * + * @param factor The factor by which to multiple this integral + * + * @return this, for method chaining + */ + public IntegralDataTypeHolder multiplyBy(IntegralDataTypeHolder factor); + + /** + * Perform a multiplication. + * + * @param factor The factor by which to multiple this integral + * + * @return this, for method chaining + */ + public IntegralDataTypeHolder multiplyBy(long factor); + + /** + * Perform an equality comparison check + * + * @param other The other value to check against our internal state + * + * @return True if the two are equal + */ + public boolean eq(IntegralDataTypeHolder other); + + /** + * Perform an equality comparison check + * + * @param other The other value to check against our internal state + * + * @return True if the two are equal + */ + public boolean eq(long other); + + /** + * Perform a "less than" comparison check. We check to see if our value is less than + * the incoming value... + * + * @param other The other value to check against our internal state + * + * @return True if our value is less than the 'other' value. + */ + public boolean lt(IntegralDataTypeHolder other); + + /** + * Perform a "less than" comparison check. We check to see if our value is less than + * the incoming value... + * + * @param other The other value to check against our internal state + * + * @return True if our value is less than the 'other' value. + */ + public boolean lt(long other); + + /** + * Perform a "greater than" comparison check. We check to see if our value is greater + * than the incoming value... + * + * @param other The other value to check against our internal state + * + * @return True if our value is greater than the 'other' value. + */ + public boolean gt(IntegralDataTypeHolder other); + + /** + * Perform a "greater than" comparison check. We check to see if our value is greater + * than the incoming value... + * + * @param other The other value to check against our internal state + * + * @return True if our value is greater than the 'other' value. + */ + public boolean gt(long other); + + /** + * Make a copy of this holder. + * + * @return The copy. + */ + public IntegralDataTypeHolder copy(); + + /** + * Return the internal value. + * + * @return The current internal value + */ + public Number makeValue(); + + /** + * Increment the internal state, but return the pre-incremented value. + * + * @return The pre-incremented internal value + */ + public Number makeValueThenIncrement(); + + /** + * Increment the internal state by the given addend, but return the pre-incremented value. + * + * @param addend The value to be added to our internal state + * + * @return The pre-incremented internal value + */ + public Number makeValueThenAdd(long addend); +} diff --git a/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java b/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java index c386fce502..5831f7b6ca 100644 --- a/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java +++ b/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,7 +20,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.id; @@ -104,9 +103,10 @@ public class MultipleHiLoPerTableGenerator //hilo params public static final String MAX_LO = "max_lo"; - private long hi; - private int lo; private int maxLo; + private int lo; + private IntegralDataTypeHolder value; + private Class returnClass; private int keySize; @@ -146,7 +146,7 @@ public class MultipleHiLoPerTableGenerator } public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException { - int result; + IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( returnClass ); int rows; do { // The loop ensures atomicity of the @@ -158,18 +158,16 @@ public class MultipleHiLoPerTableGenerator PreparedStatement qps = conn.prepareStatement(query); PreparedStatement ips = null; try { - //qps.setString(1, key); ResultSet rs = qps.executeQuery(); boolean isInitialized = rs.next(); if ( !isInitialized ) { - result = 0; - ips = conn.prepareStatement(insert); - //ips.setString(1, key); - ips.setInt(1, result); + value.initialize( 0 ); + ips = conn.prepareStatement( insert ); + value.bind( ips, 1 ); ips.execute(); } else { - result = rs.getInt(1); + value.initialize( rs, 0 ); } rs.close(); } @@ -184,12 +182,10 @@ public class MultipleHiLoPerTableGenerator qps.close(); } - //sql = update; PreparedStatement ups = conn.prepareStatement(update); try { - ups.setInt( 1, result + 1 ); - ups.setInt( 2, result ); - //ups.setString( 3, key ); + value.copy().increment().bind( ups, 1 ); + value.bind( ups, 2 ); rows = ups.executeUpdate(); } catch (SQLException sqle) { @@ -201,24 +197,30 @@ public class MultipleHiLoPerTableGenerator } } while (rows==0); - return new Integer(result); + return value; } public synchronized Serializable generate(SessionImplementor session, Object obj) throws HibernateException { - if (maxLo < 1) { + // maxLo < 1 indicates a hilo generator with no hilo :? + if ( maxLo < 1 ) { //keep the behavior consistent even for boundary usages - int val = ( (Integer) doWorkInNewTransaction(session) ).intValue(); - if (val == 0) val = ( (Integer) doWorkInNewTransaction(session) ).intValue(); - return IdentifierGeneratorHelper.createNumber( val, returnClass ); + IntegralDataTypeHolder value = null; + while ( value == null || value.lt( 1 ) ) { + value = (IntegralDataTypeHolder) doWorkInNewTransaction( session ); + } + return value.makeValue(); } - if (lo>maxLo) { - int hival = ( (Integer) doWorkInNewTransaction(session) ).intValue(); - lo = (hival == 0) ? 1 : 0; - hi = hival * (maxLo+1); - log.debug("new hi value: " + hival); + + if ( lo > maxLo ) { + IntegralDataTypeHolder hiVal = (IntegralDataTypeHolder) doWorkInNewTransaction( session ); + lo = ( hiVal.eq( 0 ) ) ? 1 : 0; + value = hiVal.copy().multiplyBy( maxLo+1 ).add( lo ); + if ( log.isDebugEnabled() ) { + log.debug("new hi value: " + hiVal); + } } - return IdentifierGeneratorHelper.createNumber( hi + lo++, returnClass ); + return value.makeValueThenIncrement(); } public void configure(Type type, Properties params, Dialect dialect) throws MappingException { diff --git a/core/src/main/java/org/hibernate/id/SequenceGenerator.java b/core/src/main/java/org/hibernate/id/SequenceGenerator.java index 1ba3e624cb..8ed3848efe 100644 --- a/core/src/main/java/org/hibernate/id/SequenceGenerator.java +++ b/core/src/main/java/org/hibernate/id/SequenceGenerator.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,7 +20,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.id; @@ -98,19 +97,19 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu sql = dialect.getSequenceNextValString( sequenceName ); } - public Serializable generate(SessionImplementor session, Object obj) - throws HibernateException { - - try { + public Serializable generate(SessionImplementor session, Object obj) { + return generateHolder( session ).makeValue(); + } + protected IntegralDataTypeHolder generateHolder(SessionImplementor session) { + try { PreparedStatement st = session.getBatcher().prepareSelectStatement(sql); try { ResultSet rs = st.executeQuery(); try { rs.next(); - Serializable result = IdentifierGeneratorHelper.get( - rs, identifierType - ); + IntegralDataTypeHolder result = buildHolder(); + result.initialize( rs, 1 ); if ( log.isDebugEnabled() ) { log.debug("Sequence identifier generated: " + result); } @@ -123,7 +122,7 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu finally { session.getBatcher().closeStatement(st); } - + } catch (SQLException sqle) { throw JDBCExceptionHelper.convert( @@ -131,9 +130,12 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu sqle, "could not get next sequence value", sql - ); + ); } + } + protected IntegralDataTypeHolder buildHolder() { + return IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() ); } public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { diff --git a/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java b/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java index 690747e27f..c64ee6ccf0 100644 --- a/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java +++ b/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,7 +20,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.id; @@ -29,7 +28,6 @@ import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.dialect.Dialect; import org.hibernate.engine.SessionImplementor; @@ -59,33 +57,36 @@ public class SequenceHiLoGenerator extends SequenceGenerator { private int maxLo; private int lo; - private long hi; - private Class returnClass; + + private IntegralDataTypeHolder value; public void configure(Type type, Properties params, Dialect d) throws MappingException { super.configure(type, params, d); maxLo = PropertiesHelper.getInt(MAX_LO, params, 9); lo = maxLo + 1; // so we "clock over" on the first invocation - returnClass = type.getReturnedClass(); } - public synchronized Serializable generate(SessionImplementor session, Object obj) - throws HibernateException { - if (maxLo < 1) { + public synchronized Serializable generate(SessionImplementor session, Object obj) { + // maxLo < 1 indicates a hilo generator with no hilo :? + if ( maxLo < 1 ) { //keep the behavior consistent even for boundary usages - long val = ( (Number) super.generate(session, obj) ).longValue(); - if (val == 0) val = ( (Number) super.generate(session, obj) ).longValue(); - return IdentifierGeneratorHelper.createNumber( val, returnClass ); - } - if ( lo>maxLo ) { - long hival = ( (Number) super.generate(session, obj) ).longValue(); - lo = (hival == 0) ? 1 : 0; - hi = hival * ( maxLo+1 ); - if ( log.isDebugEnabled() ) - log.debug("new hi value: " + hival); + IntegralDataTypeHolder value = null; + while ( value == null || value.lt( 0 ) ) { + value = super.generateHolder( session ); + } + return value.makeValue(); } - return IdentifierGeneratorHelper.createNumber( hi + lo++, returnClass ); + if ( lo > maxLo ) { + IntegralDataTypeHolder hiVal = generateHolder( session ); + lo = ( hiVal.eq( 0 ) ) ? 1 : 0; + value = hiVal.copy().multiplyBy( maxLo+1 ).add( lo ); + if ( log.isDebugEnabled() ) { + log.debug("new hi value: " + hiVal); + } + } + + return value.makeValueThenIncrement(); } } diff --git a/core/src/main/java/org/hibernate/id/TableGenerator.java b/core/src/main/java/org/hibernate/id/TableGenerator.java index e0f9fbdec7..644de173c5 100644 --- a/core/src/main/java/org/hibernate/id/TableGenerator.java +++ b/core/src/main/java/org/hibernate/id/TableGenerator.java @@ -50,17 +50,21 @@ import org.hibernate.util.PropertiesHelper; * table to store the last generated value. It is not * intended that applications use this strategy directly. * However, it may be used to build other (efficient) - * strategies. The returned type is Integer.
- *
- * The hi value MUST be fetched in a seperate transaction - * to the Session transaction so the generator must - * be able to obtain a new connection and commit it. Hence - * this implementation may not be used when Hibernate is - * fetching connections when the user is supplying - * connections.
- *
- * The returned value is of type integer.
- *
+ * strategies. The returned type is any supported by + * {@link IntegralDataTypeHolder} + *

+ * The value MUST be fetched in a separate transaction + * from that of the main {@link SessionImplementor session} + * transaction so the generator must be able to obtain a new + * connection and commit it. Hence this implementation may only + * be used when Hibernate is fetching connections, not when the + * user is supplying connections. + *

+ * Again, the return types supported here are any of the ones + * supported by {@link IntegralDataTypeHolder}. This is new + * as of 3.5. Prior to that this generator only returned {@link Integer} + * values. + *

* Mapping parameters supported: table, column * * @see TableHiLoGenerator @@ -83,12 +87,15 @@ public class TableGenerator extends TransactionHelper private static final Logger log = LoggerFactory.getLogger(TableGenerator.class); + private Type identifierType; private String tableName; private String columnName; private String query; private String update; public void configure(Type type, Properties params, Dialect dialect) { + identifierType = type; + ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER ); tableName = PropertiesHelper.getString( TABLE, params, DEFAULT_TABLE_NAME ); @@ -127,12 +134,13 @@ public class TableGenerator extends TransactionHelper " = ?"; } - public synchronized Serializable generate(SessionImplementor session, Object object) - throws HibernateException { - int result = ( (Integer) doWorkInNewTransaction(session) ).intValue(); - return new Integer(result); + public synchronized Serializable generate(SessionImplementor session, Object object) { + return generateHolder( session ).makeValue(); } + protected IntegralDataTypeHolder generateHolder(SessionImplementor session) { + return (IntegralDataTypeHolder) doWorkInNewTransaction( session ); + } public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { return new String[] { @@ -157,8 +165,19 @@ public class TableGenerator extends TransactionHelper return tableName; } + /** + * Get the next value. + * + * @param conn The sql connection to use. + * @param sql n/a + * + * @return Prior to 3.5 this method returned an {@link Integer}. Since 3.5 it now + * returns a {@link IntegralDataTypeHolder} + * + * @throws SQLException + */ public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException { - int result; + IntegralDataTypeHolder value = buildHolder(); int rows; do { // The loop ensures atomicity of the @@ -175,7 +194,7 @@ public class TableGenerator extends TransactionHelper log.error(err); throw new IdentifierGenerationException(err); } - result = rs.getInt(1); + value.initialize( rs, 1 ); rs.close(); } catch (SQLException sqle) { @@ -190,8 +209,8 @@ public class TableGenerator extends TransactionHelper SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC ); PreparedStatement ups = conn.prepareStatement(update); try { - ups.setInt( 1, result + 1 ); - ups.setInt( 2, result ); + value.copy().increment().bind( ups, 1 ); + value.bind( ups, 2 ); rows = ups.executeUpdate(); } catch (SQLException sqle) { @@ -203,6 +222,10 @@ public class TableGenerator extends TransactionHelper } } while (rows==0); - return new Integer(result); + return value; + } + + protected IntegralDataTypeHolder buildHolder() { + return IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() ); } } diff --git a/core/src/main/java/org/hibernate/id/TableHiLoGenerator.java b/core/src/main/java/org/hibernate/id/TableHiLoGenerator.java index d4e43d5ae7..a0133b2f0e 100644 --- a/core/src/main/java/org/hibernate/id/TableHiLoGenerator.java +++ b/core/src/main/java/org/hibernate/id/TableHiLoGenerator.java @@ -29,7 +29,6 @@ import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.hibernate.HibernateException; import org.hibernate.dialect.Dialect; import org.hibernate.engine.SessionImplementor; import org.hibernate.type.Type; @@ -58,10 +57,10 @@ public class TableHiLoGenerator extends TableGenerator { */ public static final String MAX_LO = "max_lo"; - private long hi; - private int lo; private int maxLo; - private Class returnClass; + private int lo; + + private IntegralDataTypeHolder value; private static final Logger log = LoggerFactory.getLogger(TableHiLoGenerator.class); @@ -69,26 +68,29 @@ public class TableHiLoGenerator extends TableGenerator { super.configure(type, params, d); maxLo = PropertiesHelper.getInt(MAX_LO, params, Short.MAX_VALUE); lo = maxLo + 1; // so we "clock over" on the first invocation - returnClass = type.getReturnedClass(); } - public synchronized Serializable generate(SessionImplementor session, Object obj) - throws HibernateException { - if (maxLo < 1) { + public synchronized Serializable generate(SessionImplementor session, Object obj) { + // maxLo < 1 indicates a hilo generator with no hilo :? + if ( maxLo < 1 ) { //keep the behavior consistent even for boundary usages - long val = ( (Number) super.generate(session, obj) ).longValue(); - if (val == 0) val = ( (Number) super.generate(session, obj) ).longValue(); - return IdentifierGeneratorHelper.createNumber( val, returnClass ); - } - if (lo>maxLo) { - long hival = ( (Number) super.generate(session, obj) ).longValue(); - lo = (hival == 0) ? 1 : 0; - hi = hival * (maxLo+1); - log.debug("new hi value: " + hival); + IntegralDataTypeHolder value = null; + while ( value == null || value.lt( 0 ) ) { + value = generateHolder( session ); + } + return value.makeValue(); } - return IdentifierGeneratorHelper.createNumber( hi + lo++, returnClass ); + if ( lo > maxLo ) { + IntegralDataTypeHolder hiVal = generateHolder( session ); + lo = ( hiVal.eq( 0 ) ) ? 1 : 0; + value = hiVal.copy().multiplyBy( maxLo+1 ).add( lo ); + if ( log.isDebugEnabled() ) { + log.debug("new hi value: " + hiVal); + } + } + return value.makeValueThenIncrement(); } } diff --git a/core/src/main/java/org/hibernate/id/enhanced/AccessCallback.java b/core/src/main/java/org/hibernate/id/enhanced/AccessCallback.java index 3dcc0acca1..dcb510ee73 100644 --- a/core/src/main/java/org/hibernate/id/enhanced/AccessCallback.java +++ b/core/src/main/java/org/hibernate/id/enhanced/AccessCallback.java @@ -24,6 +24,8 @@ */ package org.hibernate.id.enhanced; +import org.hibernate.id.IntegralDataTypeHolder; + /** * Contract for providing callback access to a {@link DatabaseStructure}, * typically from the {@link Optimizer}. @@ -36,5 +38,5 @@ public interface AccessCallback { * * @return The next value. */ - public long getNextValue(); + public IntegralDataTypeHolder getNextValue(); } diff --git a/core/src/main/java/org/hibernate/id/enhanced/Optimizer.java b/core/src/main/java/org/hibernate/id/enhanced/Optimizer.java index 70872343e3..0e66dcf550 100644 --- a/core/src/main/java/org/hibernate/id/enhanced/Optimizer.java +++ b/core/src/main/java/org/hibernate/id/enhanced/Optimizer.java @@ -26,6 +26,8 @@ package org.hibernate.id.enhanced; import java.io.Serializable; +import org.hibernate.id.IntegralDataTypeHolder; + /** * Performs optimization on an optimizable identifier generator. Typically * this optimization takes the form of trying to ensure we do not have to @@ -51,12 +53,12 @@ public interface Optimizer { /** * A common means to access the last value obtained from the underlying * source. This is intended for testing purposes, since accessing the - * unerlying database source directly is much more difficult. + * underlying database source directly is much more difficult. * * @return The last value we obtained from the underlying source; - * -1 indicates we have not yet consulted with the source. + * null indicates we have not yet consulted with the source. */ - public long getLastSourceValue(); + public IntegralDataTypeHolder getLastSourceValue(); /** * Retrieves the defined increment size. diff --git a/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java b/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java index e083c8d588..11a6192270 100644 --- a/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java +++ b/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java @@ -31,8 +31,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.hibernate.HibernateException; +import org.hibernate.id.IntegralDataTypeHolder; import org.hibernate.util.ReflectHelper; -import org.hibernate.id.IdentifierGeneratorHelper; /** * Factory for {@link Optimizer} instances. @@ -97,17 +97,6 @@ public class OptimizerFactory { this.incrementSize = incrementSize; } - /** - * Take the primitive long value and "make" (or wrap) it into the - * {@link #getReturnClass id type}. - * - * @param value The primitive value to make/wrap. - * @return The wrapped value. - */ - protected final Serializable make(long value) { - return IdentifierGeneratorHelper.createNumber( value, returnClass ); - } - /** * Getter for property 'returnClass'. This is the Java * class which is used to represent the id (e.g. {@link java.lang.Long}). @@ -131,7 +120,7 @@ public class OptimizerFactory { * every request. */ public static class NoopOptimizer extends OptimizerSupport { - private long lastSourceValue = -1; + private IntegralDataTypeHolder lastSourceValue; public NoopOptimizer(Class returnClass, int incrementSize) { super( returnClass, incrementSize ); @@ -141,21 +130,21 @@ public class OptimizerFactory { * {@inheritDoc} */ public Serializable generate(AccessCallback callback) { - if ( lastSourceValue == -1 ) { - while( lastSourceValue <= 0 ) { + if ( lastSourceValue == null ) { + do { lastSourceValue = callback.getNextValue(); - } + } while ( lastSourceValue.lt( 1 ) ); } else { lastSourceValue = callback.getNextValue(); } - return make( lastSourceValue ); + return lastSourceValue.makeValue(); } /** * {@inheritDoc} */ - public long getLastSourceValue() { + public IntegralDataTypeHolder getLastSourceValue() { return lastSourceValue; } @@ -170,11 +159,40 @@ public class OptimizerFactory { /** * Optimizer which applies a 'hilo' algorithm in memory to achieve * optimization. + *

+ * A 'hilo' algorithm is simply a means for a single value stored in the + * database to represent a "bucket" of possible, contiguous values. The + * database value identifies which particular bucket we are on. + *

+ * This database value must be paired with another value that defines the + * size of the bucket; the number of possible values available. + * The {@link #getIncrementSize() incrementSize} serves this purpose. The + * naming here is meant more for consistency in that this value serves the + * same purpose as the increment supplied to the {@link PooledOptimizer}. + *

+ * The general algorithms used to determine the bucket are:

    + *
  1. {@code upperLimit = (databaseValue * incrementSize) + 1}
  2. + *
  3. {@code lowerLimit = upperLimit - 1}
  4. + *
+ * As an example, consider a case with incrementSize of 10. Initially the + * database holds 1:
    + *
  1. {@code upperLimit = (1 * 20) + 1 = 21}
  2. + *
  3. {@code lowerLimit = 21 - 20 = 1}
  4. + *
+ * From there we increment the value from lowerLimit until we reach the + * upperLimit, at which point we would define a new bucket. The database + * now contains 2, though incrementSize remains unchanged:
    + *
  1. {@code upperLimit = (2 * 20) + 1 = 41}
  2. + *
  3. {@code lowerLimit = 41 - 20 = 21}
  4. + *
+ * And so on... + *

+ * Note, 'value' always (after init) holds the next value to return */ public static class HiLoOptimizer extends OptimizerSupport { - private long lastSourceValue = -1; - private long value; - private long hiValue; + private IntegralDataTypeHolder lastSourceValue; + private IntegralDataTypeHolder upperLimit; + private IntegralDataTypeHolder value; public HiLoOptimizer(Class returnClass, int incrementSize) { super( returnClass, incrementSize ); @@ -190,26 +208,30 @@ public class OptimizerFactory { * {@inheritDoc} */ public synchronized Serializable generate(AccessCallback callback) { - if ( lastSourceValue < 0 ) { + if ( lastSourceValue == null ) { + // first call, so initialize ourselves. we need to read the database + // value and set up the 'bucket' boundaries lastSourceValue = callback.getNextValue(); - while ( lastSourceValue <= 0 ) { + while ( lastSourceValue.lt( 1 ) ) { lastSourceValue = callback.getNextValue(); } - hiValue = ( lastSourceValue * incrementSize ) + 1; - value = hiValue - incrementSize; + // upperLimit defines the upper end of the bucket values + upperLimit = lastSourceValue.copy().multiplyBy( incrementSize ).increment(); + // initialize value to the low end of the bucket + value = upperLimit.copy().subtract( incrementSize ); } - else if ( value >= hiValue ) { + else if ( ! upperLimit.gt( value ) ) { lastSourceValue = callback.getNextValue(); - hiValue = ( lastSourceValue * incrementSize ) + 1; + upperLimit = lastSourceValue.copy().multiplyBy( incrementSize ).increment(); } - return make( value++ ); + return value.makeValueThenIncrement(); } /** * {@inheritDoc} */ - public long getLastSourceValue() { + public IntegralDataTypeHolder getLastSourceValue() { return lastSourceValue; } @@ -222,30 +244,38 @@ public class OptimizerFactory { /** * Getter for property 'lastValue'. + *

+ * Exposure intended for testing purposes. * * @return Value for property 'lastValue'. */ - public long getLastValue() { - return value - 1; + public IntegralDataTypeHolder getLastValue() { + return value.copy().decrement(); } /** - * Getter for property 'hiValue'. + * Getter for property 'upperLimit'. + *

+ * Exposure intended for testing purposes. * - * @return Value for property 'hiValue'. + * @return Value for property 'upperLimit'. */ - public long getHiValue() { - return hiValue; + public IntegralDataTypeHolder getHiValue() { + return upperLimit; } } /** * Optimizer which uses a pool of values, storing the next low value of the * range in the database. + *

+ * Note that this optimizer works essentially the same as the + * {@link HiLoOptimizer} except that here the bucket ranges are actually + * encoded into the database structures. */ public static class PooledOptimizer extends OptimizerSupport { - private long value; - private long hiValue = -1; + private IntegralDataTypeHolder hiValue; + private IntegralDataTypeHolder value; public PooledOptimizer(Class returnClass, int incrementSize) { super( returnClass, incrementSize ); @@ -261,9 +291,9 @@ public class OptimizerFactory { * {@inheritDoc} */ public synchronized Serializable generate(AccessCallback callback) { - if ( hiValue < 0 ) { + if ( hiValue == null ) { value = callback.getNextValue(); - if ( value < 1 ) { + if ( value.lt( 1 ) ) { // unfortunately not really safe to normalize this // to 1 as an initial value like we do the others // because we would not be able to control this if @@ -272,17 +302,17 @@ public class OptimizerFactory { } hiValue = callback.getNextValue(); } - else if ( value >= hiValue ) { + else if ( ! hiValue.gt( value ) ) { hiValue = callback.getNextValue(); - value = hiValue - incrementSize; + value = hiValue.copy().subtract( incrementSize ); } - return make( value++ ); + return value.makeValueThenIncrement(); } /** * {@inheritDoc} */ - public long getLastSourceValue() { + public IntegralDataTypeHolder getLastSourceValue() { return hiValue; } @@ -295,11 +325,13 @@ public class OptimizerFactory { /** * Getter for property 'lastValue'. + *

+ * Exposure intended for testing purposes. * * @return Value for property 'lastValue'. */ - public long getLastValue() { - return value - 1; + public IntegralDataTypeHolder getLastValue() { + return value.copy().decrement(); } } } diff --git a/core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java b/core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java index d4a7c95ad8..7f75e4f609 100644 --- a/core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java +++ b/core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java @@ -35,6 +35,8 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.SessionImplementor; import org.hibernate.exception.JDBCExceptionHelper; import org.hibernate.HibernateException; +import org.hibernate.id.IdentifierGeneratorHelper; +import org.hibernate.id.IntegralDataTypeHolder; /** * Describes a sequence. @@ -47,14 +49,21 @@ public class SequenceStructure implements DatabaseStructure { private final String sequenceName; private final int initialValue; private final int incrementSize; + private final Class numberType; private final String sql; private boolean applyIncrementSizeToSourceValues; private int accessCounter; - public SequenceStructure(Dialect dialect, String sequenceName, int initialValue, int incrementSize) { + public SequenceStructure( + Dialect dialect, + String sequenceName, + int initialValue, + int incrementSize, + Class numberType) { this.sequenceName = sequenceName; this.initialValue = initialValue; this.incrementSize = incrementSize; + this.numberType = numberType; sql = dialect.getSequenceNextValString( sequenceName ); } @@ -91,7 +100,7 @@ public class SequenceStructure implements DatabaseStructure { */ public AccessCallback buildCallback(final SessionImplementor session) { return new AccessCallback() { - public long getNextValue() { + public IntegralDataTypeHolder getNextValue() { accessCounter++; try { PreparedStatement st = session.getBatcher().prepareSelectStatement( sql ); @@ -99,11 +108,12 @@ public class SequenceStructure implements DatabaseStructure { ResultSet rs = st.executeQuery(); try { rs.next(); - long result = rs.getLong( 1 ); + IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( numberType ); + value.initialize( rs, 1 ); if ( log.isDebugEnabled() ) { - log.debug("Sequence identifier generated: " + result); + log.debug( "Sequence value obtained: " + value.makeValue() ); } - return result; + return value; } finally { try { diff --git a/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java b/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java index 0fea9be103..be6c1b9631 100644 --- a/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java +++ b/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java @@ -178,7 +178,15 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co } } - this.databaseStructure = buildDatabaseStructure( params, dialect, forceTableUse, sequenceName, initialValue, incrementSize ); + this.databaseStructure = buildDatabaseStructure( + type, + params, + dialect, + forceTableUse, + sequenceName, + initialValue, + incrementSize + ); this.optimizer = OptimizerFactory.buildOptimizer( optimizationStrategy, identifierType.getReturnedClass(), incrementSize ); this.databaseStructure.prepare( optimizer ); @@ -291,15 +299,16 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co /** * Build the database structure. * + * @param type The Hibernate type of the identifier property * @param params The params supplied in the generator config (plus some standard useful extras). * @param dialect The dialect being used. * @param forceTableUse Should a table be used even if the dialect supports sequences? * @param sequenceName The name to use for the sequence or table. * @param initialValue The initial value. - * @param incrementSize the increment size to use (after any adjustments). - * @return The db structure representation + * @param incrementSize the increment size to use (after any adjustments). @return The db structure representation */ protected DatabaseStructure buildDatabaseStructure( + Type type, Properties params, Dialect dialect, boolean forceTableUse, @@ -308,11 +317,11 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co int incrementSize) { boolean useSequence = dialect.supportsSequences() && !forceTableUse; if ( useSequence ) { - return new SequenceStructure( dialect, sequenceName, initialValue, incrementSize ); + return new SequenceStructure( dialect, sequenceName, initialValue, incrementSize, type.getReturnedClass() ); } else { String valueColumnName = determineValueColumnName( params, dialect ); - return new TableStructure( dialect, sequenceName, valueColumnName, initialValue, incrementSize ); + return new TableStructure( dialect, sequenceName, valueColumnName, initialValue, incrementSize, type.getReturnedClass() ); } } diff --git a/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java index 997b799067..2349067b48 100644 --- a/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java +++ b/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java @@ -39,6 +39,8 @@ import org.slf4j.LoggerFactory; import org.hibernate.engine.TransactionHelper; import org.hibernate.engine.SessionImplementor; +import org.hibernate.id.IdentifierGeneratorHelper; +import org.hibernate.id.IntegralDataTypeHolder; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.id.Configurable; import org.hibernate.type.Type; @@ -287,7 +289,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent public void configure(Type type, Properties params, Dialect dialect) throws MappingException { identifierType = type; - tableName = determneGeneratorTableName( params, dialect ); + tableName = determineGeneratorTableName( params, dialect ); segmentColumnName = determineSegmentColumnName( params, dialect ); valueColumnName = determineValueColumnName( params, dialect ); @@ -316,7 +318,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent * @param dialect The dialect in effect * @return The table name to use. */ - protected String determneGeneratorTableName(Properties params, Dialect dialect) { + protected String determineGeneratorTableName(Properties params, Dialect dialect) { String name = PropertiesHelper.getString( TABLE_PARAM, params, DEF_TABLE ); boolean isGivenNameUnqualified = name.indexOf( '.' ) < 0; if ( isGivenNameUnqualified ) { @@ -450,8 +452,8 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent public synchronized Serializable generate(final SessionImplementor session, Object obj) { return optimizer.generate( new AccessCallback() { - public long getNextValue() { - return ( ( Number ) doWorkInNewTransaction( session ) ).longValue(); + public IntegralDataTypeHolder getNextValue() { + return ( IntegralDataTypeHolder ) doWorkInNewTransaction( session ); } } ); @@ -461,7 +463,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent * {@inheritDoc} */ public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException { - int result; + IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() ); int rows; do { SQL_STATEMENT_LOGGER.logStatement( selectQuery, FormatStyle.BASIC ); @@ -470,13 +472,13 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent selectPS.setString( 1, segmentValue ); ResultSet selectRS = selectPS.executeQuery(); if ( !selectRS.next() ) { + value.initialize( initialValue ); PreparedStatement insertPS = null; try { - result = initialValue; SQL_STATEMENT_LOGGER.logStatement( insertQuery, FormatStyle.BASIC ); insertPS = conn.prepareStatement( insertQuery ); insertPS.setString( 1, segmentValue ); - insertPS.setLong( 2, result ); + value.bind( insertPS, 2 ); insertPS.execute(); } finally { @@ -486,7 +488,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent } } else { - result = selectRS.getInt( 1 ); + value.initialize( selectRS, 1 ); } selectRS.close(); } @@ -501,10 +503,15 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent SQL_STATEMENT_LOGGER.logStatement( updateQuery, FormatStyle.BASIC ); PreparedStatement updatePS = conn.prepareStatement( updateQuery ); try { - long newValue = optimizer.applyIncrementSizeToSourceValues() - ? result + incrementSize : result + 1; - updatePS.setLong( 1, newValue ); - updatePS.setLong( 2, result ); + final IntegralDataTypeHolder updateValue = value.copy(); + if ( optimizer.applyIncrementSizeToSourceValues() ) { + updateValue.add( incrementSize ); + } + else { + updateValue.increment(); + } + updateValue.bind( updatePS, 1 ); + value.bind( updatePS, 2 ); updatePS.setString( 3, segmentValue ); rows = updatePS.executeUpdate(); } @@ -520,7 +527,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent accessCount++; - return new Integer( result ); + return value; } /** diff --git a/core/src/main/java/org/hibernate/id/enhanced/TableStructure.java b/core/src/main/java/org/hibernate/id/enhanced/TableStructure.java index bed34d7741..931128d136 100644 --- a/core/src/main/java/org/hibernate/id/enhanced/TableStructure.java +++ b/core/src/main/java/org/hibernate/id/enhanced/TableStructure.java @@ -40,6 +40,8 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.TransactionHelper; import org.hibernate.id.IdentifierGenerationException; +import org.hibernate.id.IdentifierGeneratorHelper; +import org.hibernate.id.IntegralDataTypeHolder; import org.hibernate.jdbc.util.FormatStyle; import org.hibernate.jdbc.util.SQLStatementLogger; @@ -56,17 +58,25 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu private final String valueColumnName; private final int initialValue; private final int incrementSize; + private final Class numberType; private final String selectQuery; private final String updateQuery; private boolean applyIncrementSizeToSourceValues; private int accessCounter; - public TableStructure(Dialect dialect, String tableName, String valueColumnName, int initialValue, int incrementSize) { + public TableStructure( + Dialect dialect, + String tableName, + String valueColumnName, + int initialValue, + int incrementSize, + Class numberType) { this.tableName = tableName; this.initialValue = initialValue; this.incrementSize = incrementSize; this.valueColumnName = valueColumnName; + this.numberType = numberType; selectQuery = "select " + valueColumnName + " as id_val" + " from " + dialect.appendLockHint( LockMode.PESSIMISTIC_WRITE, tableName ) + @@ -117,8 +127,8 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu */ public AccessCallback buildCallback(final SessionImplementor session) { return new AccessCallback() { - public long getNextValue() { - return ( ( Number ) doWorkInNewTransaction( session ) ).longValue(); + public IntegralDataTypeHolder getNextValue() { + return ( IntegralDataTypeHolder ) doWorkInNewTransaction( session ); } }; } @@ -152,7 +162,7 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu * {@inheritDoc} */ protected Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException { - long result; + IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( numberType ); int rows; do { SQL_STATEMENT_LOGGER.logStatement( selectQuery, FormatStyle.BASIC ); @@ -164,7 +174,7 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu log.error( err ); throw new IdentifierGenerationException( err ); } - result = selectRS.getLong( 1 ); + value.initialize( selectRS, 1 ); selectRS.close(); } catch ( SQLException sqle ) { @@ -178,9 +188,10 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu SQL_STATEMENT_LOGGER.logStatement( updateQuery, FormatStyle.BASIC ); PreparedStatement updatePS = conn.prepareStatement( updateQuery ); try { - int increment = applyIncrementSizeToSourceValues ? incrementSize : 1; - updatePS.setLong( 1, result + increment ); - updatePS.setLong( 2, result ); + final int increment = applyIncrementSizeToSourceValues ? incrementSize : 1; + final IntegralDataTypeHolder updateValue = value.copy().add( increment ); + updateValue.bind( updatePS, 1 ); + value.bind( updatePS, 2 ); rows = updatePS.executeUpdate(); } catch ( SQLException sqle ) { @@ -194,7 +205,7 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu accessCounter++; - return new Long( result ); + return value; } } diff --git a/core/src/test/java/org/hibernate/id/AbstractHolderTest.java b/core/src/test/java/org/hibernate/id/AbstractHolderTest.java new file mode 100644 index 0000000000..5ae614bb26 --- /dev/null +++ b/core/src/test/java/org/hibernate/id/AbstractHolderTest.java @@ -0,0 +1,167 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.id; + +import junit.framework.TestCase; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public abstract class AbstractHolderTest extends TestCase { + protected abstract IntegralDataTypeHolder makeHolder(); + + public void testInitializationChecking() { + IntegralDataTypeHolder holder = makeHolder(); + try { + holder.increment(); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.add( 1 ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.decrement(); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.subtract( 1 ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.multiplyBy( holder ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.multiplyBy( 1 ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.eq( holder ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.eq( 1 ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.lt( holder ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.lt( 1 ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.gt( holder ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.gt( 1 ); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + + try { + holder.makeValue(); + fail(); + } + catch ( IdentifierGenerationException expected ) { + } + } + + public void testIncrement() { + IntegralDataTypeHolder holder = makeHolder(); + holder.initialize( 0 ); + int i = 0; + for ( ; i < 5008; i++ ) { + holder.increment(); + } + assertEquals( holder.copy().initialize( i ), holder ); + } + + public void testBasicHiloAlgorithm() { + // mimic an initialValue of 1 and increment of 20 + final long initialValue = 1; + final long incrementSize = 2; + + // initialization + IntegralDataTypeHolder lastSourceValue = makeHolder().initialize( 1 ); + IntegralDataTypeHolder upperLimit = lastSourceValue.copy().multiplyBy( incrementSize ).increment(); + IntegralDataTypeHolder value = upperLimit.copy().subtract( incrementSize ); + + assertEquals( 1, lastSourceValue.makeValue().longValue() ); + assertEquals( 3, upperLimit.makeValue().longValue() ); + assertEquals( 1, value.makeValue().longValue() ); + + value.increment(); + value.increment(); + + assertFalse( upperLimit.gt( value ) ); + + // at which point we would "clock over" + lastSourceValue.increment(); + upperLimit = lastSourceValue.copy().multiplyBy( incrementSize ).increment(); + + assertEquals( 2, lastSourceValue.makeValue().longValue() ); + assertEquals( 5, upperLimit.makeValue().longValue() ); + assertEquals( 3, value.makeValue().longValue() ); + } +} diff --git a/core/src/test/java/org/hibernate/id/BigDecimalHolderTest.java b/core/src/test/java/org/hibernate/id/BigDecimalHolderTest.java new file mode 100644 index 0000000000..c34599925d --- /dev/null +++ b/core/src/test/java/org/hibernate/id/BigDecimalHolderTest.java @@ -0,0 +1,37 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.id; + +import java.math.BigDecimal; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class BigDecimalHolderTest extends AbstractHolderTest { + protected IntegralDataTypeHolder makeHolder() { + return IdentifierGeneratorHelper.getIntegralDataTypeHolder( BigDecimal.class ); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/hibernate/id/BigIntegerHolderTest.java b/core/src/test/java/org/hibernate/id/BigIntegerHolderTest.java new file mode 100644 index 0000000000..c59b9d692d --- /dev/null +++ b/core/src/test/java/org/hibernate/id/BigIntegerHolderTest.java @@ -0,0 +1,37 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.id; + +import java.math.BigInteger; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class BigIntegerHolderTest extends AbstractHolderTest { + protected IntegralDataTypeHolder makeHolder() { + return IdentifierGeneratorHelper.getIntegralDataTypeHolder( BigInteger.class ); + } +} diff --git a/core/src/test/java/org/hibernate/id/LongHolderTest.java b/core/src/test/java/org/hibernate/id/LongHolderTest.java new file mode 100644 index 0000000000..4ff27fdb79 --- /dev/null +++ b/core/src/test/java/org/hibernate/id/LongHolderTest.java @@ -0,0 +1,35 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.id; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class LongHolderTest extends AbstractHolderTest { + protected IntegralDataTypeHolder makeHolder() { + return IdentifierGeneratorHelper.getIntegralDataTypeHolder( Long.class ); + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/BigIntegerIncrementGeneratorTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/BigIntegerIncrementGeneratorTest.java new file mode 100644 index 0000000000..b9404cd463 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/BigIntegerIncrementGeneratorTest.java @@ -0,0 +1,73 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.idgen.biginteger.increment; + +import java.math.BigInteger; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class BigIntegerIncrementGeneratorTest extends FunctionalTestCase { + public BigIntegerIncrementGeneratorTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/biginteger/increment/Mapping.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BigIntegerIncrementGeneratorTest.class ); + } + + public void testBasics() { + Session s = openSession(); + s.beginTransaction(); + Entity entity = new Entity( "BigInteger + increment #1" ); + s.save( entity ); + Entity entity2 = new Entity( "BigInteger + increment #2" ); + s.save( entity2 ); + s.getTransaction().commit(); + s.close(); + + assertEquals( BigInteger.valueOf( 1 ), entity.getId() ); + assertEquals( BigInteger.valueOf( 2 ), entity2.getId() ); + + s = openSession(); + s.beginTransaction(); + s.delete( entity ); + s.delete( entity2 ); + s.getTransaction().commit(); + s.close(); + + } +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/Entity.java b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/Entity.java new file mode 100644 index 0000000000..3c6607caf1 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/Entity.java @@ -0,0 +1,59 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.idgen.biginteger.increment; + +import java.math.BigInteger; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class Entity { + private BigInteger id; + private String name; + + public Entity() { + } + + public Entity(String name) { + this.name = name; + } + + public BigInteger getId() { + return id; + } + + public void setId(BigInteger id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/Mapping.hbm.xml b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/Mapping.hbm.xml new file mode 100644 index 0000000000..a8304c2718 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/increment/Mapping.hbm.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/BigIntegerSequenceGeneratorTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/BigIntegerSequenceGeneratorTest.java new file mode 100644 index 0000000000..a548fc5c07 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/BigIntegerSequenceGeneratorTest.java @@ -0,0 +1,79 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.idgen.biginteger.sequence; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.dialect.Dialect; +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class BigIntegerSequenceGeneratorTest extends DatabaseSpecificFunctionalTestCase { + public BigIntegerSequenceGeneratorTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/biginteger/sequence/Mapping.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BigIntegerSequenceGeneratorTest.class ); + } + + @Override + public boolean appliesTo(Dialect dialect) { + return dialect.supportsSequences(); + } + + public void testBasics() { + Session s = openSession(); + s.beginTransaction(); + Entity entity = new Entity( "BigInteger + sequence #1" ); + s.save( entity ); + Entity entity2 = new Entity( "BigInteger + sequence #2" ); + s.save( entity2 ); + s.getTransaction().commit(); + s.close(); + +// hsqldb defines different behavior for the initial select from a sequence +// then say oracle +// assertEquals( BigInteger.valueOf( 1 ), entity.getId() ); +// assertEquals( BigInteger.valueOf( 2 ), entity2.getId() ); + + s = openSession(); + s.beginTransaction(); + s.delete( entity ); + s.delete( entity2 ); + s.getTransaction().commit(); + s.close(); + + } +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/Entity.java b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/Entity.java new file mode 100644 index 0000000000..2d654bf868 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/Entity.java @@ -0,0 +1,59 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.idgen.biginteger.sequence; + +import java.math.BigInteger; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class Entity { + private BigInteger id; + private String name; + + public Entity() { + } + + public Entity(String name) { + this.name = name; + } + + public BigInteger getId() { + return id; + } + + public void setId(BigInteger id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/Mapping.hbm.xml b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/Mapping.hbm.xml new file mode 100644 index 0000000000..a00fb27700 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/idgen/biginteger/sequence/Mapping.hbm.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java index 1cad81ff13..604816402f 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java @@ -3,6 +3,8 @@ package org.hibernate.test.idgen.enhanced; import junit.framework.Test; import junit.framework.TestSuite; +import org.hibernate.id.IdentifierGeneratorHelper; +import org.hibernate.id.IntegralDataTypeHolder; import org.hibernate.junit.UnitTestCase; import org.hibernate.id.enhanced.Optimizer; import org.hibernate.id.enhanced.OptimizerFactory; @@ -88,7 +90,7 @@ public class OptimizerUnitTest extends UnitTestCase { next = ( Long ) optimizer.generate( sequence ); assertEquals( i, next.intValue() ); } - assertEquals( 2, sequence.getTimesCalled() ); // twice to initialze state + assertEquals( 2, sequence.getTimesCalled() ); // twice to initialize state assertEquals( 11, sequence.getCurrentValue() ); // force a "clock over" next = ( Long ) optimizer.generate( sequence ); @@ -98,7 +100,7 @@ public class OptimizerUnitTest extends UnitTestCase { } private static class SourceMock implements AccessCallback { - private long value; + private IdentifierGeneratorHelper.BasicHolder value = new IdentifierGeneratorHelper.BasicHolder( Long.class ); private int increment; private int timesCalled = 0; @@ -108,12 +110,12 @@ public class OptimizerUnitTest extends UnitTestCase { public SourceMock(long initialValue, int increment) { this.increment = increment; - this.value = initialValue - increment; + this.value.initialize( initialValue - increment ); } - public long getNextValue() { + public IntegralDataTypeHolder getNextValue() { timesCalled++; - return ( value += increment ); + return value.add( increment ).copy(); } public int getTimesCalled() { @@ -121,7 +123,7 @@ public class OptimizerUnitTest extends UnitTestCase { } public long getCurrentValue() { - return value; + return value.getActualLongValue(); } } diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java index f7b045ff33..4216e964c5 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java @@ -2,13 +2,15 @@ package org.hibernate.test.idgen.enhanced.forcedtable; import junit.framework.Test; +import org.hibernate.Session; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.id.enhanced.TableStructure; import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; import org.hibernate.junit.functional.FunctionalTestClassTestSuite; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.id.enhanced.SequenceStyleGenerator; -import org.hibernate.id.enhanced.TableStructure; -import org.hibernate.id.enhanced.OptimizerFactory; -import org.hibernate.Session; + +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; /** * {@inheritDoc} @@ -54,7 +56,7 @@ public class BasicForcedTableSequenceTest extends DatabaseSpecificFunctionalTest long expectedId = i + 1; assertEquals( expectedId, entities[i].getId().longValue() ); assertEquals( expectedId, generator.getDatabaseStructure().getTimesAccessed() ); - assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() ); + assertEquals( expectedId, ( (BasicHolder) generator.getOptimizer().getLastSourceValue() ).getActualLongValue() ); } s.getTransaction().commit(); diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java index abb1c39074..3c5006fc8f 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java @@ -2,13 +2,15 @@ package org.hibernate.test.idgen.enhanced.forcedtable; import junit.framework.Test; -import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; -import org.hibernate.junit.functional.FunctionalTestClassTestSuite; -import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.Session; import org.hibernate.id.enhanced.OptimizerFactory; import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.id.enhanced.TableStructure; -import org.hibernate.Session; +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; + +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; /** * {@inheritDoc} @@ -54,18 +56,18 @@ public class HiLoForcedTableSequenceTest extends DatabaseSpecificFunctionalTestC s.save( entities[i] ); long expectedId = i + 1; assertEquals( expectedId, entities[i].getId().longValue() ); - assertEquals( 1, generator.getOptimizer().getLastSourceValue() ); - assertEquals( i + 1, optimizer.getLastValue() ); - assertEquals( increment + 1, optimizer.getHiValue() ); + assertEquals( 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); + assertEquals( i + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getHiValue() ).getActualLongValue() ); } // now force a "clock over" entities[ increment ] = new Entity( "" + increment ); s.save( entities[ increment ] ); long expectedId = optimizer.getIncrementSize() + 1; assertEquals( expectedId, entities[ optimizer.getIncrementSize() ].getId().longValue() ); - assertEquals( 2, optimizer.getLastSourceValue() ); // initialization + clokc-over - assertEquals( increment + 1, optimizer.getLastValue() ); - assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() ); + assertEquals( 2, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization + clock-over + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( ( increment * 2 ) + 1, ( (BasicHolder) optimizer.getHiValue() ).getActualLongValue() ); s.getTransaction().commit(); diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java index 162a6f0abe..48233f98fe 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java @@ -2,13 +2,15 @@ package org.hibernate.test.idgen.enhanced.forcedtable; import junit.framework.Test; -import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; -import org.hibernate.junit.functional.FunctionalTestClassTestSuite; -import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.Session; import org.hibernate.id.enhanced.OptimizerFactory; import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.id.enhanced.TableStructure; -import org.hibernate.Session; +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; + +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; /** * {@inheritDoc} @@ -54,19 +56,21 @@ public class PooledForcedTableSequenceTest extends DatabaseSpecificFunctionalTes s.save( entities[i] ); long expectedId = i + 1; assertEquals( expectedId, entities[i].getId().longValue() ); - assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization calls table twice - assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls table twice - assertEquals( i + 1, optimizer.getLastValue() ); - assertEquals( increment + 1, optimizer.getLastSourceValue() ); + // NOTE : initialization calls table twice + assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); + assertEquals( i + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); } // now force a "clock over" entities[ increment ] = new Entity( "" + increment ); s.save( entities[ increment ] ); long expectedId = optimizer.getIncrementSize() + 1; assertEquals( expectedId, entities[ optimizer.getIncrementSize() ].getId().longValue() ); - assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); // initialization (2) + clock over - assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over - assertEquals( increment + 1, optimizer.getLastValue() ); + // initialization (2) + clock over + assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); + assertEquals( ( increment * 2 ) + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); s.getTransaction().commit(); s.beginTransaction(); diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java index a99c395f0b..5b96c6aa7e 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java @@ -8,6 +8,8 @@ import org.hibernate.Session; import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.persister.entity.EntityPersister; +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; + /** * {@inheritDoc} * @@ -41,7 +43,7 @@ public class BasicSequenceTest extends FunctionalTestCase { long expectedId = i + 1; assertEquals( expectedId, entities[i].getId().longValue() ); assertEquals( expectedId, generator.getDatabaseStructure().getTimesAccessed() ); - assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() ); + assertEquals( expectedId, ( (BasicHolder) generator.getOptimizer().getLastSourceValue() ).getActualLongValue() ); } s.getTransaction().commit(); diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java index 77627336f1..0423579b63 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java @@ -9,6 +9,9 @@ import org.hibernate.id.enhanced.OptimizerFactory; import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.persister.entity.EntityPersister; +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; + + /** * {@inheritDoc} * @@ -42,17 +45,17 @@ public class HiLoSequenceTest extends FunctionalTestCase { entities[i] = new Entity( "" + ( i + 1 ) ); s.save( entities[i] ); assertEquals( 1, generator.getDatabaseStructure().getTimesAccessed() ); // initialization - assertEquals( 1, optimizer.getLastSourceValue() ); // initialization - assertEquals( i + 1, optimizer.getLastValue() ); - assertEquals( increment + 1, optimizer.getHiValue() ); + assertEquals( 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization + assertEquals( i + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getHiValue() ).getActualLongValue() ); } // now force a "clock over" entities[ increment ] = new Entity( "" + increment ); s.save( entities[ increment ] ); assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization - assertEquals( 2, optimizer.getLastSourceValue() ); // initialization - assertEquals( increment + 1, optimizer.getLastValue() ); - assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() ); + assertEquals( 2, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( ( increment * 2 ) + 1, ( (BasicHolder) optimizer.getHiValue() ).getActualLongValue() ); s.getTransaction().commit(); diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java index a17cff9009..8332553a79 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java @@ -9,6 +9,8 @@ import org.hibernate.id.enhanced.OptimizerFactory; import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.Session; +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; + /** * {@inheritDoc} * @@ -42,16 +44,16 @@ public class PooledSequenceTest extends FunctionalTestCase { entities[i] = new Entity( "" + ( i + 1 ) ); s.save( entities[i] ); assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization calls seq twice - assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls seq twice - assertEquals( i + 1, optimizer.getLastValue() ); - assertEquals( increment + 1, optimizer.getLastSourceValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization calls seq twice + assertEquals( i + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); } // now force a "clock over" entities[ increment ] = new Entity( "" + increment ); s.save( entities[ increment ] ); assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); // initialization (2) + clock over - assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over - assertEquals( increment + 1, optimizer.getLastValue() ); + assertEquals( ( increment * 2 ) + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization (2) + clock over + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); s.getTransaction().commit(); s.beginTransaction(); diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java index 51d2f4907c..9d6b7e013b 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java @@ -8,6 +8,8 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.id.enhanced.TableGenerator; import org.hibernate.Session; +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; + /** * {@inheritDoc} * @@ -41,7 +43,7 @@ public class BasicTableTest extends FunctionalTestCase { long expectedId = i + 1; assertEquals( expectedId, entities[i].getId().longValue() ); assertEquals( expectedId, generator.getTableAccessCount() ); - assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() ); + assertEquals( expectedId, ( (BasicHolder) generator.getOptimizer().getLastSourceValue() ).getActualLongValue() ); } s.getTransaction().commit(); diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java index 1fcc90d579..3deeeb018c 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java @@ -9,6 +9,8 @@ import org.hibernate.id.enhanced.OptimizerFactory; import org.hibernate.id.enhanced.TableGenerator; import org.hibernate.Session; +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; + /** * {@inheritDoc} * @@ -42,17 +44,17 @@ public class HiLoTableTest extends FunctionalTestCase { entities[i] = new Entity( "" + ( i + 1 ) ); s.save( entities[i] ); assertEquals( 1, generator.getTableAccessCount() ); // initialization - assertEquals( 1, optimizer.getLastSourceValue() ); // initialization - assertEquals( i + 1, optimizer.getLastValue() ); - assertEquals( increment + 1, optimizer.getHiValue() ); + assertEquals( 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization + assertEquals( i + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getHiValue() ).getActualLongValue() ); } // now force a "clock over" entities[ increment ] = new Entity( "" + increment ); s.save( entities[ increment ] ); assertEquals( 2, generator.getTableAccessCount() ); // initialization - assertEquals( 2, optimizer.getLastSourceValue() ); // initialization - assertEquals( increment + 1, optimizer.getLastValue() ); - assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() ); + assertEquals( 2, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( ( increment * 2 ) + 1, ( (BasicHolder) optimizer.getHiValue() ).getActualLongValue() ); s.getTransaction().commit(); diff --git a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java index 75891dcad7..87f8c013dc 100644 --- a/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java +++ b/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java @@ -9,6 +9,8 @@ import org.hibernate.id.enhanced.OptimizerFactory; import org.hibernate.id.enhanced.TableGenerator; import org.hibernate.Session; +import static org.hibernate.id.IdentifierGeneratorHelper.BasicHolder; + /** * {@inheritDoc} * @@ -42,16 +44,16 @@ public class PooledTableTest extends FunctionalTestCase { entities[i] = new Entity( "" + ( i + 1 ) ); s.save( entities[i] ); assertEquals( 2, generator.getTableAccessCount() ); // initialization calls seq twice - assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls seq twice - assertEquals( i + 1, optimizer.getLastValue() ); - assertEquals( increment + 1, optimizer.getLastSourceValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization calls seq twice + assertEquals( i + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); } // now force a "clock over" entities[ increment ] = new Entity( "" + increment ); s.save( entities[ increment ] ); assertEquals( 3, generator.getTableAccessCount() ); // initialization (2) + clock over - assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over - assertEquals( increment + 1, optimizer.getLastValue() ); + assertEquals( ( increment * 2 ) + 1, ( (BasicHolder) optimizer.getLastSourceValue() ).getActualLongValue() ); // initialization (2) + clock over + assertEquals( increment + 1, ( (BasicHolder) optimizer.getLastValue() ).getActualLongValue() ); s.getTransaction().commit(); s.beginTransaction();