HHH-13694 fix numeric overflow exception for large sequence min values

This commit is contained in:
Christian Beikov 2022-03-08 14:50:51 +01:00
parent ac4a792f84
commit 3d55855a87
10 changed files with 151 additions and 33 deletions

View File

@ -202,9 +202,9 @@ public class SequenceStyleGenerator
if ( sequenceMismatchStrategy != SequenceMismatchStrategy.NONE && isPooledOptimizer && isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) { if ( sequenceMismatchStrategy != SequenceMismatchStrategy.NONE && isPooledOptimizer && isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) {
String databaseSequenceName = sequenceName.getObjectName().getText(); 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(); int dbIncrementValue = databaseIncrementValue.intValue();
switch ( sequenceMismatchStrategy ) { switch ( sequenceMismatchStrategy ) {
@ -553,7 +553,7 @@ public class SequenceStyleGenerator
* *
* @return sequence increment value * @return sequence increment value
*/ */
private Long getSequenceIncrementValue(JdbcEnvironment jdbcEnvironment, String sequenceName) { private Number getSequenceIncrementValue(JdbcEnvironment jdbcEnvironment, String sequenceName) {
return jdbcEnvironment.getExtractedDatabaseMetaData().getSequenceInformationList() return jdbcEnvironment.getExtractedDatabaseMetaData().getSequenceInformationList()
.stream() .stream()
.filter( .filter(

View File

@ -105,22 +105,22 @@ public class SequenceInformationExtractorLegacyImpl implements SequenceInformati
return column != null ? resultSet.getString( column ) : null; return column != null ? resultSet.getString( column ) : null;
} }
protected Long resultSetStartValueSize(ResultSet resultSet) throws SQLException { protected Number resultSetStartValueSize(ResultSet resultSet) throws SQLException {
String column = sequenceStartValueColumn(); String column = sequenceStartValueColumn();
return column != null ? resultSet.getLong( column ) : null; return column != null ? resultSet.getLong( column ) : null;
} }
protected Long resultSetMinValue(ResultSet resultSet) throws SQLException { protected Number resultSetMinValue(ResultSet resultSet) throws SQLException {
String column = sequenceMinValueColumn(); String column = sequenceMinValueColumn();
return column != null ? resultSet.getLong( column ) : null; return column != null ? resultSet.getLong( column ) : null;
} }
protected Long resultSetMaxValue(ResultSet resultSet) throws SQLException { protected Number resultSetMaxValue(ResultSet resultSet) throws SQLException {
String column = sequenceMaxValueColumn(); String column = sequenceMaxValueColumn();
return column != null ? resultSet.getLong( column ) : null; return column != null ? resultSet.getLong( column ) : null;
} }
protected Long resultSetIncrementValue(ResultSet resultSet) throws SQLException { protected Number resultSetIncrementValue(ResultSet resultSet) throws SQLException {
String column = sequenceIncrementColumn(); String column = sequenceIncrementColumn();
return column != null ? resultSet.getLong( column ) : null; return column != null ? resultSet.getLong( column ) : null;
} }

View File

@ -39,8 +39,24 @@ public class SequenceInformationExtractorOracleDatabaseImpl extends SequenceInfo
} }
@Override @Override
protected Long resultSetMaxValue(ResultSet resultSet) throws SQLException { protected String sequenceMaxValueColumn() {
return resultSet.getBigDecimal( "max_value" ).longValue(); 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 @Override

View File

@ -110,7 +110,7 @@ public class SequenceInformationExtractorTiDBDatabaseImpl extends SequenceInform
return resultSet.getString( sequenceNameColumn() ); return resultSet.getString( sequenceNameColumn() );
} }
protected Long resultSetIncrementValue(ResultSet resultSet) throws SQLException { protected Number resultSetIncrementValue(ResultSet resultSet) throws SQLException {
String column = sequenceIncrementColumn(); String column = sequenceIncrementColumn();
return column != null ? resultSet.getLong( column ) : null; return column != null ? resultSet.getLong( column ) : null;
} }

View File

@ -17,16 +17,16 @@ import org.hibernate.tool.schema.extract.spi.SequenceInformation;
public class SequenceInformationImpl implements SequenceInformation { public class SequenceInformationImpl implements SequenceInformation {
private final QualifiedSequenceName sequenceName; private final QualifiedSequenceName sequenceName;
private final Long startValue; private final Number startValue;
private final Long minValue; private final Number minValue;
private final Long maxValue; private final Number maxValue;
private final Long incrementValue; private final Number incrementValue;
public SequenceInformationImpl( public SequenceInformationImpl(
QualifiedSequenceName sequenceName, QualifiedSequenceName sequenceName,
Long startValue, Number startValue,
Long minValue, Number minValue,
Long maxValue, Long incrementValue) { Number maxValue, Number incrementValue) {
this.sequenceName = sequenceName; this.sequenceName = sequenceName;
this.startValue = startValue; this.startValue = startValue;
this.minValue = minValue; this.minValue = minValue;
@ -40,21 +40,21 @@ public class SequenceInformationImpl implements SequenceInformation {
} }
@Override @Override
public Long getStartValue() { public Number getStartValue() {
return startValue; return startValue;
} }
@Override @Override
public Long getMinValue() { public Number getMinValue() {
return minValue; return minValue;
} }
public Long getMaxValue() { public Number getMaxValue() {
return maxValue; return maxValue;
} }
@Override @Override
public Long getIncrementValue() { public Number getIncrementValue() {
return incrementValue; return incrementValue;
} }
} }

View File

@ -27,26 +27,26 @@ public interface SequenceInformation {
* *
* @return The extracted start value or null id the value could not be extracted. * @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. * Retrieve the extracted minimum value defined for the sequence.
* *
* @return The extracted minimum value or null id the value could not be extracted. * @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. * Retrieve the extracted maximum value defined for the sequence.
* *
* @return The extracted maximum value or null id the value could not be extracted. * @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. * 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. * @return The extracted increment value; use a negative number to indicate the increment could not be extracted.
*/ */
Long getIncrementValue(); Number getIncrementValue();
} }

View File

@ -184,8 +184,8 @@ public abstract class AbstractSchemaValidator implements SchemaValidator {
); );
} }
if ( sequenceInformation.getIncrementValue() != null && sequenceInformation.getIncrementValue() > 0 if ( sequenceInformation.getIncrementValue() != null && sequenceInformation.getIncrementValue().intValue() > 0
&& sequence.getIncrementSize() != sequenceInformation.getIncrementValue() ) { && sequence.getIncrementSize() != sequenceInformation.getIncrementValue().intValue() ) {
throw new SchemaManagementException( throw new SchemaManagementException(
String.format( String.format(
"Schema-validation: sequence [%s] defined inconsistent increment-size; found [%s] but expecting [%s]", "Schema-validation: sequence [%s] defined inconsistent increment-size; found [%s] but expecting [%s]",

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<SequenceInformation> sequenceInformations = sequenceExtractor.extractMetadata(
new ExtractionContext.EmptyExtractionContext() {
@Override
public Connection getJdbcConnection() {
return connection;
}
@Override
public JdbcEnvironment getJdbcEnvironment() {
return jdbcEnvironment;
}
} );
// lets skip system sequences
Optional<SequenceInformation> 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();
}
}
}

View File

@ -26,14 +26,14 @@ public class OracleSequenceInfoTest extends
@Override @Override
protected void assertProductSequence(SequenceInformation productSequenceInfo) { protected void assertProductSequence(SequenceInformation productSequenceInfo) {
assertNull( productSequenceInfo.getStartValue() ); assertNull( productSequenceInfo.getStartValue() );
assertEquals( Long.valueOf( 1 ), productSequenceInfo.getMinValue() ); assertEquals( Long.valueOf( 1 ), productSequenceInfo.getMinValue().longValue() );
assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue() ); assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue().longValue() );
} }
@Override @Override
protected void assertVehicleSequenceInfo(SequenceInformation vehicleSequenceInfo) { protected void assertVehicleSequenceInfo(SequenceInformation vehicleSequenceInfo) {
assertNull( vehicleSequenceInfo.getStartValue() ); assertNull( vehicleSequenceInfo.getStartValue() );
assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getMinValue() ); assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getMinValue().longValue() );
assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue() ); assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue().longValue() );
} }
} }

View File

@ -88,11 +88,11 @@ public class SequenceInformationTest extends
} }
protected void assertProductSequence(SequenceInformation productSequenceInfo) { protected void assertProductSequence(SequenceInformation productSequenceInfo) {
assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue() ); assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue().longValue() );
} }
protected void assertVehicleSequenceInfo(SequenceInformation vehicleSequenceInfo) { protected void assertVehicleSequenceInfo(SequenceInformation vehicleSequenceInfo) {
assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue() ); assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue().longValue() );
} }
private SequenceInformation sequenceInformation(String sequenceName) { private SequenceInformation sequenceInformation(String sequenceName) {