From 3d55855a873558c3cd8f68a2c12cc7c849762464 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 8 Mar 2022 14:50:51 +0100 Subject: [PATCH] HHH-13694 fix numeric overflow exception for large sequence min values --- .../id/enhanced/SequenceStyleGenerator.java | 6 +- ...equenceInformationExtractorLegacyImpl.java | 8 +- ...nformationExtractorOracleDatabaseImpl.java | 20 +++- ...eInformationExtractorTiDBDatabaseImpl.java | 2 +- .../internal/SequenceInformationImpl.java | 22 ++-- .../extract/spi/SequenceInformation.java | 8 +- .../internal/AbstractSchemaValidator.java | 4 +- .../OracleDialectSequenceInformationTest.java | 102 ++++++++++++++++++ .../functional/OracleSequenceInfoTest.java | 8 +- .../functional/SequenceInformationTest.java | 4 +- 10 files changed, 151 insertions(+), 33 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleDialectSequenceInformationTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java index 9e59bbb06c..9caff9fdc3 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java @@ -202,9 +202,9 @@ public class SequenceStyleGenerator if ( sequenceMismatchStrategy != SequenceMismatchStrategy.NONE && isPooledOptimizer && isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) { String databaseSequenceName = sequenceName.getObjectName().getText(); - Long databaseIncrementValue = getSequenceIncrementValue( jdbcEnvironment, databaseSequenceName ); + Number databaseIncrementValue = getSequenceIncrementValue( jdbcEnvironment, databaseSequenceName ); - if ( databaseIncrementValue != null && !databaseIncrementValue.equals( (long) incrementSize ) ) { + if ( databaseIncrementValue != null && databaseIncrementValue.intValue() != incrementSize ) { int dbIncrementValue = databaseIncrementValue.intValue(); switch ( sequenceMismatchStrategy ) { @@ -553,7 +553,7 @@ public class SequenceStyleGenerator * * @return sequence increment value */ - private Long getSequenceIncrementValue(JdbcEnvironment jdbcEnvironment, String sequenceName) { + private Number getSequenceIncrementValue(JdbcEnvironment jdbcEnvironment, String sequenceName) { return jdbcEnvironment.getExtractedDatabaseMetaData().getSequenceInformationList() .stream() .filter( diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorLegacyImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorLegacyImpl.java index a99f94938c..1b980c813f 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorLegacyImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorLegacyImpl.java @@ -105,22 +105,22 @@ public class SequenceInformationExtractorLegacyImpl implements SequenceInformati return column != null ? resultSet.getString( column ) : null; } - protected Long resultSetStartValueSize(ResultSet resultSet) throws SQLException { + protected Number resultSetStartValueSize(ResultSet resultSet) throws SQLException { String column = sequenceStartValueColumn(); return column != null ? resultSet.getLong( column ) : null; } - protected Long resultSetMinValue(ResultSet resultSet) throws SQLException { + protected Number resultSetMinValue(ResultSet resultSet) throws SQLException { String column = sequenceMinValueColumn(); return column != null ? resultSet.getLong( column ) : null; } - protected Long resultSetMaxValue(ResultSet resultSet) throws SQLException { + protected Number resultSetMaxValue(ResultSet resultSet) throws SQLException { String column = sequenceMaxValueColumn(); return column != null ? resultSet.getLong( column ) : null; } - protected Long resultSetIncrementValue(ResultSet resultSet) throws SQLException { + protected Number resultSetIncrementValue(ResultSet resultSet) throws SQLException { String column = sequenceIncrementColumn(); return column != null ? resultSet.getLong( column ) : null; } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorOracleDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorOracleDatabaseImpl.java index b4706177b9..31e76ffc57 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorOracleDatabaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorOracleDatabaseImpl.java @@ -39,8 +39,24 @@ public class SequenceInformationExtractorOracleDatabaseImpl extends SequenceInfo } @Override - protected Long resultSetMaxValue(ResultSet resultSet) throws SQLException { - return resultSet.getBigDecimal( "max_value" ).longValue(); + protected String sequenceMaxValueColumn() { + return "max_value"; + } + + + @Override + protected Number resultSetIncrementValue(ResultSet resultSet) throws SQLException { + return resultSet.getBigDecimal( sequenceIncrementColumn() ); + } + + @Override + protected Number resultSetMinValue(ResultSet resultSet) throws SQLException { + return resultSet.getBigDecimal( sequenceMinValueColumn() ); + } + + @Override + protected Number resultSetMaxValue(ResultSet resultSet) throws SQLException { + return resultSet.getBigDecimal( sequenceMaxValueColumn() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTiDBDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTiDBDatabaseImpl.java index c00d9e2502..bf2ee562c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTiDBDatabaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTiDBDatabaseImpl.java @@ -110,7 +110,7 @@ public class SequenceInformationExtractorTiDBDatabaseImpl extends SequenceInform return resultSet.getString( sequenceNameColumn() ); } - protected Long resultSetIncrementValue(ResultSet resultSet) throws SQLException { + protected Number resultSetIncrementValue(ResultSet resultSet) throws SQLException { String column = sequenceIncrementColumn(); return column != null ? resultSet.getLong( column ) : null; } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationImpl.java index f83dd7e710..2c098c1eb8 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationImpl.java @@ -17,16 +17,16 @@ import org.hibernate.tool.schema.extract.spi.SequenceInformation; public class SequenceInformationImpl implements SequenceInformation { private final QualifiedSequenceName sequenceName; - private final Long startValue; - private final Long minValue; - private final Long maxValue; - private final Long incrementValue; + private final Number startValue; + private final Number minValue; + private final Number maxValue; + private final Number incrementValue; public SequenceInformationImpl( QualifiedSequenceName sequenceName, - Long startValue, - Long minValue, - Long maxValue, Long incrementValue) { + Number startValue, + Number minValue, + Number maxValue, Number incrementValue) { this.sequenceName = sequenceName; this.startValue = startValue; this.minValue = minValue; @@ -40,21 +40,21 @@ public class SequenceInformationImpl implements SequenceInformation { } @Override - public Long getStartValue() { + public Number getStartValue() { return startValue; } @Override - public Long getMinValue() { + public Number getMinValue() { return minValue; } - public Long getMaxValue() { + public Number getMaxValue() { return maxValue; } @Override - public Long getIncrementValue() { + public Number getIncrementValue() { return incrementValue; } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformation.java index 49ddb5d8f3..e6507dbe71 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/SequenceInformation.java @@ -27,26 +27,26 @@ public interface SequenceInformation { * * @return The extracted start value or null id the value could not be extracted. */ - Long getStartValue(); + Number getStartValue(); /** * Retrieve the extracted minimum value defined for the sequence. * * @return The extracted minimum value or null id the value could not be extracted. */ - Long getMinValue(); + Number getMinValue(); /** * Retrieve the extracted maximum value defined for the sequence. * * @return The extracted maximum value or null id the value could not be extracted. */ - Long getMaxValue(); + Number getMaxValue(); /** * Retrieve the extracted increment value defined for the sequence. * * @return The extracted increment value; use a negative number to indicate the increment could not be extracted. */ - Long getIncrementValue(); + Number getIncrementValue(); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java index 9f2898ccf6..a2e5b33084 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java @@ -184,8 +184,8 @@ public abstract class AbstractSchemaValidator implements SchemaValidator { ); } - if ( sequenceInformation.getIncrementValue() != null && sequenceInformation.getIncrementValue() > 0 - && sequence.getIncrementSize() != sequenceInformation.getIncrementValue() ) { + if ( sequenceInformation.getIncrementValue() != null && sequenceInformation.getIncrementValue().intValue() > 0 + && sequence.getIncrementSize() != sequenceInformation.getIncrementValue().intValue() ) { throw new SchemaManagementException( String.format( "Schema-validation: sequence [%s] defined inconsistent increment-size; found [%s] but expecting [%s]", diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleDialectSequenceInformationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleDialectSequenceInformationTest.java new file mode 100644 index 0000000000..61e446eef1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleDialectSequenceInformationTest.java @@ -0,0 +1,102 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.dialect.functional; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Optional; +import java.util.stream.StreamSupport; + +import org.hibernate.dialect.OracleDialect; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.extract.spi.SequenceInformation; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInAutoCommit; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RequiresDialect(value = { OracleDialect.class }) +@TestForIssue(jiraKey = "HHH-13694") +public class OracleDialectSequenceInformationTest extends BaseNonConfigCoreFunctionalTestCase { + + private static final String MIN_SEQUENCE_NAME = "SEQ_MIN_TEST"; + private static final String MAX_SEQUENCE_NAME = "SEQ_MAX_TEST"; + private static final String MIN_VALUE = "-99999999999999999999999999"; + private static final String MAX_VALUE = "99999999999999999999999999"; + + @Before + public void prepareTest() throws Exception { + doInAutoCommit( + "DROP SEQUENCE " + MIN_SEQUENCE_NAME, + "CREATE SEQUENCE " + MIN_SEQUENCE_NAME + " MINVALUE " + MIN_VALUE + " MAXVALUE -1 INCREMENT BY -1", + "DROP SEQUENCE " + MAX_SEQUENCE_NAME, + "CREATE SEQUENCE " + MAX_SEQUENCE_NAME + " MINVALUE 0 MAXVALUE " + MAX_VALUE + " INCREMENT BY 1" ); + } + + @After + public void cleanupTest() throws Exception { + doInAutoCommit( + "DROP SEQUENCE " + MIN_SEQUENCE_NAME, + "DROP SEQUENCE " + MAX_SEQUENCE_NAME ); + } + + @Test + public void testExtractSequenceWithMinValueLowerThanLongMinValue() throws SQLException { + SequenceInformation sequence = fetchSequenceInformation( MIN_SEQUENCE_NAME ); + + assertEquals( -1L, sequence.getIncrementValue().longValue() ); + assertEquals( new BigDecimal( MIN_VALUE ), sequence.getMinValue() ); + } + + @Test + public void testExtractSequenceWithMaxValueGreaterThanLongMaxValue() throws SQLException { + SequenceInformation sequence = fetchSequenceInformation( MAX_SEQUENCE_NAME ); + + assertEquals( 1L, sequence.getIncrementValue().longValue() ); + assertEquals( new BigDecimal( MAX_VALUE ), sequence.getMaxValue() ); + } + + private SequenceInformation fetchSequenceInformation(String sequenceName) throws SQLException { + try ( Connection connection = sessionFactory().getJdbcServices() + .getBootstrapJdbcConnectionAccess() + .obtainConnection() ) { + JdbcEnvironment jdbcEnvironment = sessionFactory().getJdbcServices().getJdbcEnvironment(); + SequenceInformationExtractorOracleDatabaseImpl sequenceExtractor = SequenceInformationExtractorOracleDatabaseImpl.INSTANCE; + Iterable sequenceInformations = sequenceExtractor.extractMetadata( + new ExtractionContext.EmptyExtractionContext() { + + @Override + public Connection getJdbcConnection() { + return connection; + } + + @Override + public JdbcEnvironment getJdbcEnvironment() { + return jdbcEnvironment; + } + } ); + + // lets skip system sequences + Optional foundSequence = StreamSupport.stream( sequenceInformations.spliterator(), false ) + .filter( sequence -> sequenceName.equals( sequence.getSequenceName().getSequenceName().getText().toUpperCase() ) ) + .findFirst(); + + assertTrue( sequenceName + " not found", foundSequence.isPresent() ); + + return foundSequence.get(); + } + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleSequenceInfoTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleSequenceInfoTest.java index b3da49b7d4..838a6fcbc9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleSequenceInfoTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleSequenceInfoTest.java @@ -26,14 +26,14 @@ public class OracleSequenceInfoTest extends @Override protected void assertProductSequence(SequenceInformation productSequenceInfo) { assertNull( productSequenceInfo.getStartValue() ); - assertEquals( Long.valueOf( 1 ), productSequenceInfo.getMinValue() ); - assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue() ); + assertEquals( Long.valueOf( 1 ), productSequenceInfo.getMinValue().longValue() ); + assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue().longValue() ); } @Override protected void assertVehicleSequenceInfo(SequenceInformation vehicleSequenceInfo) { assertNull( vehicleSequenceInfo.getStartValue() ); - assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getMinValue() ); - assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue() ); + assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getMinValue().longValue() ); + assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue().longValue() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/SequenceInformationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/SequenceInformationTest.java index 615b99d6d2..1170f90156 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/SequenceInformationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/SequenceInformationTest.java @@ -88,11 +88,11 @@ public class SequenceInformationTest extends } protected void assertProductSequence(SequenceInformation productSequenceInfo) { - assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue() ); + assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue().longValue() ); } protected void assertVehicleSequenceInfo(SequenceInformation vehicleSequenceInfo) { - assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue() ); + assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue().longValue() ); } private SequenceInformation sequenceInformation(String sequenceName) {