.
+ */
+package org.hibernate.id;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Describes the strategy for handling the mismatch between a database sequence configuration and
+ * the one defined by the entity mapping.
+ *
+ * @author Vlad Mihalcea
+ */
+public enum SequenceMismatchStrategy {
+
+ /**
+ * When detecting a mismatch, Hibernate simply logs the sequence whose entity mapping configuration conflicts
+ * with the one found in the database.
+ */
+ LOG,
+
+ /**
+ * When detecting a mismatch, Hibernate throws a {@link org.hibernate.MappingException} indicating the sequence
+ * whose entity mapping configuration conflict with the one found in the database.
+ */
+ EXCEPTION,
+
+ /**
+ * When detecting a mismatch, Hibernate tries to fix it by overriding the entity sequence mapping using the one
+ * found in the database.
+ */
+ FIX;
+
+ /**
+ * Interpret the configured SequenceMismatchStrategy value.
+ *
+ * Valid values are either a {@link SequenceMismatchStrategy} object or its String representation.
+ *
+ * For string values, the matching is case insensitive, so you can use either {@code FIX} or {@code fix}.
+ *
+ * @param sequenceMismatchStrategy configured {@link SequenceMismatchStrategy} representation
+ *
+ * @return associated {@link SequenceMismatchStrategy} object
+ */
+ public static SequenceMismatchStrategy interpret(Object sequenceMismatchStrategy) {
+ if ( sequenceMismatchStrategy == null ) {
+ return EXCEPTION;
+ }
+ else if ( sequenceMismatchStrategy instanceof SequenceMismatchStrategy ) {
+ return (SequenceMismatchStrategy) sequenceMismatchStrategy;
+ }
+ else if ( sequenceMismatchStrategy instanceof String ) {
+ String sequenceMismatchStrategyString = (String) sequenceMismatchStrategy;
+ for ( SequenceMismatchStrategy value : values() ) {
+ if ( value.name().equalsIgnoreCase( sequenceMismatchStrategyString ) ) {
+ return value;
+ }
+ }
+ }
+ throw new HibernateException(
+ "Unrecognized sequence.increment_size_mismatch_strategy value : [" + sequenceMismatchStrategy
+ + "]. Supported values include [log], [exception], and [fix]."
+ );
+ }
+}
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 e4b80e562696..eb475effb279 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
@@ -25,10 +25,12 @@
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.id.SequenceMismatchStrategy;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.ServiceRegistry;
+import org.hibernate.tool.schema.extract.spi.SequenceInformation;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@@ -218,12 +220,13 @@ public Type getIdentifierType() {
}
-
// Configurable implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
+ final ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class );
+
final Dialect dialect = jdbcEnvironment.getDialect();
this.identifierType = type;
@@ -234,6 +237,37 @@ public void configure(Type type, Properties params, ServiceRegistry serviceRegis
final int initialValue = determineInitialValue( params );
int incrementSize = determineIncrementSize( params );
+ if ( isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) {
+ String databaseSequenceName = sequenceName.getObjectName().getText();
+ Long databaseIncrementValue = getSequenceIncrementValue( jdbcEnvironment, databaseSequenceName );
+
+ if ( databaseIncrementValue != null && !databaseIncrementValue.equals( (long) incrementSize ) ) {
+ int dbIncrementValue = databaseIncrementValue.intValue();
+
+ SequenceMismatchStrategy sequenceMismatchStrategy = configurationService.getSetting(
+ AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY,
+ SequenceMismatchStrategy::interpret,
+ SequenceMismatchStrategy.EXCEPTION
+ );
+
+ switch ( sequenceMismatchStrategy ) {
+ case EXCEPTION:
+ throw new MappingException(
+ String.format(
+ "The increment size of the [%s] sequence is set to [%d] in the entity mapping " +
+ "while the associated database sequence increment size is [%d].",
+ databaseSequenceName, incrementSize, dbIncrementValue
+ )
+ );
+ case FIX:
+ incrementSize = dbIncrementValue;
+ case LOG:
+ LOG.sequenceIncrementSizeMismatch( databaseSequenceName, incrementSize, dbIncrementValue );
+ break;
+ }
+ }
+ }
+
final String optimizationStrategy = determineOptimizationStrategy( params, incrementSize );
incrementSize = determineAdjustedIncrementSize( optimizationStrategy, incrementSize );
@@ -443,8 +477,7 @@ protected DatabaseStructure buildDatabaseStructure(
QualifiedName sequenceName,
int initialValue,
int incrementSize) {
- final boolean useSequence = jdbcEnvironment.getDialect().supportsSequences() && !forceTableUse;
- if ( useSequence ) {
+ if ( isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) {
return buildSequenceStructure( type, params, jdbcEnvironment, sequenceName, initialValue, incrementSize );
}
else {
@@ -452,6 +485,10 @@ protected DatabaseStructure buildDatabaseStructure(
}
}
+ protected boolean isPhysicalSequence(JdbcEnvironment jdbcEnvironment, boolean forceTableUse) {
+ return jdbcEnvironment.getDialect().supportsSequences() && !forceTableUse;
+ }
+
protected DatabaseStructure buildSequenceStructure(
Type type,
Properties params,
@@ -521,4 +558,24 @@ public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect d
public void registerExportables(Database database) {
databaseStructure.registerExportables( database );
}
+
+ /**
+ * Get the database sequence increment value from the associated {@link SequenceInformation} object.
+ *
+ * @param jdbcEnvironment the current JdbcEnvironment
+ * @param sequenceName sequence name
+ *
+ * @return sequence increment value
+ */
+ private Long getSequenceIncrementValue(JdbcEnvironment jdbcEnvironment, String sequenceName) {
+ return jdbcEnvironment.getExtractedDatabaseMetaData().getSequenceInformationList().stream().filter(
+ sequenceInformation -> {
+ Identifier catalog = sequenceInformation.getSequenceName().getCatalogName();
+ Identifier schema = sequenceInformation.getSequenceName().getSchemaName();
+ return sequenceName.equalsIgnoreCase( sequenceInformation.getSequenceName().getSequenceName().getText() ) &&
+ ( catalog == null || catalog.equals( jdbcEnvironment.getCurrentCatalog() ) ) &&
+ ( schema == null || schema.equals( jdbcEnvironment.getCurrentSchema() ) );
+ }
+ ).map( SequenceInformation::getIncrementValue ).findFirst().orElse( null );
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java
index 99fa6dd97431..bde56cf1e4c1 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java
@@ -1843,4 +1843,8 @@ void attemptToAssociateProxyWithTwoOpenSessions(
@LogMessage(level = WARN)
@Message(value = "Detaching an uninitialized collection with queued operations from a session: %s", id = 496)
void queuedOperationWhenDetachFromSession(String collectionInfoString);
+
+ @LogMessage(level = WARN)
+ @Message(value = "The increment size of the [%s] sequence is set to [%d] in the entity mapping while the associated database sequence increment size is [%d]. The database sequence increment size will take precedence to avoid identifier allocation conflicts.", id = 497)
+ void sequenceIncrementSizeMismatch(String sequenceName, int incrementSize, int databaseIncrementSize);
}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorCUBRIDDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorCUBRIDDatabaseImpl.java
new file mode 100644
index 000000000000..ad3c37aa1710
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorCUBRIDDatabaseImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorCUBRIDDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorCUBRIDDatabaseImpl INSTANCE = new SequenceInformationExtractorCUBRIDDatabaseImpl();
+
+ @Override
+ protected String sequenceNameColumn() {
+ return "name";
+ }
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return "started";
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "min_val";
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return "max_val";
+ }
+
+ @Override
+ protected String sequenceIncrementColumn() {
+ return "increment_val";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorDB2DatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorDB2DatabaseImpl.java
new file mode 100644
index 000000000000..40aa2907c249
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorDB2DatabaseImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorDB2DatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorDB2DatabaseImpl INSTANCE = new SequenceInformationExtractorDB2DatabaseImpl();
+
+ @Override
+ protected String sequenceNameColumn() {
+ return "seqname";
+ }
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return "seqschema";
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return "start";
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "minvalue";
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return "maxvalue";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorDerbyDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorDerbyDatabaseImpl.java
new file mode 100644
index 000000000000..b139c32d47ed
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorDerbyDatabaseImpl.java
@@ -0,0 +1,42 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorDerbyDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorDerbyDatabaseImpl INSTANCE = new SequenceInformationExtractorDerbyDatabaseImpl();
+
+ @Override
+ protected String sequenceNameColumn() {
+ return "sequencename";
+ }
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return "startvalue";
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "minimumvalue";
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return "maximumvalue";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorH2DatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorH2DatabaseImpl.java
index 9049807e4432..860b47b06da8 100644
--- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorH2DatabaseImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorH2DatabaseImpl.java
@@ -8,72 +8,28 @@
import java.sql.ResultSet;
import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.hibernate.boot.model.relational.QualifiedSequenceName;
-import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
-import org.hibernate.tool.schema.extract.spi.ExtractionContext;
-import org.hibernate.tool.schema.extract.spi.SequenceInformation;
-import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
/**
- * Temporary implementation that works for H2.
- *
* @author Steve Ebersole
*/
-public class SequenceInformationExtractorH2DatabaseImpl implements SequenceInformationExtractor {
+public class SequenceInformationExtractorH2DatabaseImpl extends SequenceInformationExtractorLegacyImpl {
/**
* Singleton access
*/
public static final SequenceInformationExtractorH2DatabaseImpl INSTANCE = new SequenceInformationExtractorH2DatabaseImpl();
@Override
- public Iterable extractMetadata(ExtractionContext extractionContext) throws SQLException {
- final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment().getIdentifierHelper();
- final Statement statement = extractionContext.getJdbcConnection().createStatement();
- try {
- ResultSet resultSet = statement.executeQuery(
- "select SEQUENCE_CATALOG, SEQUENCE_SCHEMA, SEQUENCE_NAME, INCREMENT " +
- "from information_schema.sequences"
- );
- try {
- final List sequenceInformationList = new ArrayList();
- while ( resultSet.next() ) {
- sequenceInformationList.add(
- new SequenceInformationImpl(
- new QualifiedSequenceName(
- identifierHelper.toIdentifier(
- resultSet.getString( "SEQUENCE_CATALOG" )
- ),
- identifierHelper.toIdentifier(
- resultSet.getString( "SEQUENCE_SCHEMA" )
- ),
- identifierHelper.toIdentifier(
- resultSet.getString( "SEQUENCE_NAME" )
- )
- ),
- resultSet.getInt( "INCREMENT" )
- )
- );
- }
- return sequenceInformationList;
- }
- finally {
- try {
- resultSet.close();
- }
- catch (SQLException ignore) {
- }
- }
- }
- finally {
- try {
- statement.close();
- }
- catch (SQLException ignore) {
- }
- }
+ protected String sequenceStartValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "min_value";
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return "max_value";
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorHANADatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorHANADatabaseImpl.java
new file mode 100644
index 000000000000..943ddc4901d0
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorHANADatabaseImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorHANADatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorHANADatabaseImpl INSTANCE = new SequenceInformationExtractorHANADatabaseImpl();
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return "schema_name";
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return "start_number";
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "min_value";
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return "max_value";
+ }
+
+ @Override
+ protected String sequenceIncrementColumn() {
+ return "increment_by";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorHSQLDBDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorHSQLDBDatabaseImpl.java
new file mode 100644
index 000000000000..9da2d724301d
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorHSQLDBDatabaseImpl.java
@@ -0,0 +1,23 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorHSQLDBDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorHSQLDBDatabaseImpl INSTANCE = new SequenceInformationExtractorHSQLDBDatabaseImpl();
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return "start_with";
+ }
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorInformixDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorInformixDatabaseImpl.java
new file mode 100644
index 000000000000..f4d8a1e73055
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorInformixDatabaseImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorInformixDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorInformixDatabaseImpl INSTANCE = new SequenceInformationExtractorInformixDatabaseImpl();
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return "start_val";
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "min_val";
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return "max_val";
+ }
+
+ @Override
+ protected String sequenceIncrementColumn() {
+ return "inc_val";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorIngresDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorIngresDatabaseImpl.java
new file mode 100644
index 000000000000..8178a406f2e4
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorIngresDatabaseImpl.java
@@ -0,0 +1,52 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorIngresDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorIngresDatabaseImpl INSTANCE = new SequenceInformationExtractorIngresDatabaseImpl();
+
+ @Override
+ protected String sequenceNameColumn() {
+ return "seq_name";
+ }
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceIncrementColumn() {
+ return null;
+ }
+}
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 d661c584f1fe..c8e4ae09abe3 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
@@ -41,18 +41,25 @@ public Iterable extractMetadata(ExtractionContext extractio
try {
final ResultSet resultSet = statement.executeQuery( lookupSql );
try {
- final List sequenceInformationList = new ArrayList();
+ final List sequenceInformationList = new ArrayList<>();
while ( resultSet.next() ) {
sequenceInformationList.add(
new SequenceInformationImpl(
new QualifiedSequenceName(
- null,
- null,
identifierHelper.toIdentifier(
- resultSet.getString( 1 )
+ resultSetCatalogName( resultSet )
+ ),
+ identifierHelper.toIdentifier(
+ resultSetSchemaName( resultSet )
+ ),
+ identifierHelper.toIdentifier(
+ resultSetSequenceName( resultSet )
)
),
- -1
+ resultSetStartValueSize( resultSet ),
+ resultSetMinValue( resultSet ),
+ resultSetMaxValue( resultSet ),
+ resultSetIncrementValue( resultSet )
)
);
}
@@ -74,4 +81,66 @@ public Iterable extractMetadata(ExtractionContext extractio
}
}
}
+
+ protected String sequenceNameColumn() {
+ return "sequence_name";
+ }
+
+ protected String sequenceCatalogColumn() {
+ return "sequence_catalog";
+ }
+
+ protected String sequenceSchemaColumn() {
+ return "sequence_schema";
+ }
+
+ protected String sequenceStartValueColumn() {
+ return "start_value";
+ }
+
+ protected String sequenceMinValueColumn() {
+ return "minimum_value";
+ }
+
+ protected String sequenceMaxValueColumn() {
+ return "maximum_value";
+ }
+
+ protected String sequenceIncrementColumn() {
+ return "increment";
+ }
+
+ protected String resultSetSequenceName(ResultSet resultSet) throws SQLException {
+ return resultSet.getString( sequenceNameColumn() );
+ }
+
+ protected String resultSetCatalogName(ResultSet resultSet) throws SQLException {
+ String column = sequenceCatalogColumn();
+ return column != null ? resultSet.getString( column ) : null;
+ }
+
+ protected String resultSetSchemaName(ResultSet resultSet) throws SQLException {
+ String column = sequenceSchemaColumn();
+ return column != null ? resultSet.getString( column ) : null;
+ }
+
+ protected Long resultSetStartValueSize(ResultSet resultSet) throws SQLException {
+ String column = sequenceStartValueColumn();
+ return column != null ? resultSet.getLong( column ) : null;
+ }
+
+ protected Long resultSetMinValue(ResultSet resultSet) throws SQLException {
+ String column = sequenceMinValueColumn();
+ return column != null ? resultSet.getLong( column ) : null;
+ }
+
+ protected Long resultSetMaxValue(ResultSet resultSet) throws SQLException {
+ String column = sequenceMaxValueColumn();
+ return column != null ? resultSet.getLong( column ) : null;
+ }
+
+ protected Long 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/SequenceInformationExtractorMimerSQLDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorMimerSQLDatabaseImpl.java
new file mode 100644
index 000000000000..0d8551d80d05
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorMimerSQLDatabaseImpl.java
@@ -0,0 +1,27 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorMimerSQLDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorMimerSQLDatabaseImpl INSTANCE = new SequenceInformationExtractorMimerSQLDatabaseImpl();
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return "initial_value";
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return 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
new file mode 100644
index 000000000000..b4706177b904
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorOracleDatabaseImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorOracleDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorOracleDatabaseImpl INSTANCE = new SequenceInformationExtractorOracleDatabaseImpl();
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "min_value";
+ }
+
+ @Override
+ protected Long resultSetMaxValue(ResultSet resultSet) throws SQLException {
+ return resultSet.getBigDecimal( "max_value" ).longValue();
+ }
+
+ @Override
+ protected String sequenceIncrementColumn() {
+ return "increment_by";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorSAPDBDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorSAPDBDatabaseImpl.java
new file mode 100644
index 000000000000..de7ab98927d5
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorSAPDBDatabaseImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorSAPDBDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorSAPDBDatabaseImpl INSTANCE = new SequenceInformationExtractorSAPDBDatabaseImpl();
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return "schemaname";
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "min_value";
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return "max_value";
+ }
+
+ @Override
+ protected String sequenceIncrementColumn() {
+ return "increment_by";
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTimesTenDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTimesTenDatabaseImpl.java
new file mode 100644
index 000000000000..7c0eba504bf6
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTimesTenDatabaseImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceInformationExtractorTimesTenDatabaseImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceInformationExtractorTimesTenDatabaseImpl INSTANCE = new SequenceInformationExtractorTimesTenDatabaseImpl();
+
+ @Override
+ protected String sequenceNameColumn() {
+ return "name";
+ }
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return "minval";
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return "maxval";
+ }
+}
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 6838a0fa49fb..f83dd7e710e2 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
@@ -16,11 +16,22 @@
*/
public class SequenceInformationImpl implements SequenceInformation {
private final QualifiedSequenceName sequenceName;
- private final int incrementSize;
- public SequenceInformationImpl(QualifiedSequenceName sequenceName, int incrementSize) {
+ private final Long startValue;
+ private final Long minValue;
+ private final Long maxValue;
+ private final Long incrementValue;
+
+ public SequenceInformationImpl(
+ QualifiedSequenceName sequenceName,
+ Long startValue,
+ Long minValue,
+ Long maxValue, Long incrementValue) {
this.sequenceName = sequenceName;
- this.incrementSize = incrementSize;
+ this.startValue = startValue;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ this.incrementValue = incrementValue;
}
@Override
@@ -29,7 +40,21 @@ public QualifiedSequenceName getSequenceName() {
}
@Override
- public int getIncrementSize() {
- return incrementSize;
+ public Long getStartValue() {
+ return startValue;
+ }
+
+ @Override
+ public Long getMinValue() {
+ return minValue;
+ }
+
+ public Long getMaxValue() {
+ return maxValue;
+ }
+
+ @Override
+ public Long getIncrementValue() {
+ return incrementValue;
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceNameExtractorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceNameExtractorImpl.java
new file mode 100644
index 000000000000..28960447e600
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceNameExtractorImpl.java
@@ -0,0 +1,54 @@
+/*
+ * 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.tool.schema.extract.internal;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author Vlad Mihalcea
+ */
+public class SequenceNameExtractorImpl extends SequenceInformationExtractorLegacyImpl {
+ /**
+ * Singleton access
+ */
+ public static final SequenceNameExtractorImpl INSTANCE = new SequenceNameExtractorImpl();
+
+ protected String resultSetSequenceName(ResultSet resultSet) throws SQLException {
+ return resultSet.getString( 1 );
+ }
+
+ @Override
+ protected String sequenceCatalogColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceSchemaColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceStartValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceMinValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceMaxValueColumn() {
+ return null;
+ }
+
+ @Override
+ protected String sequenceIncrementColumn() {
+ return null;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java
index 5f1b3f80542f..6709039b2d82 100644
--- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java
+++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java
@@ -45,4 +45,46 @@ interface DatabaseObjectAccess {
DatabaseObjectAccess getDatabaseObjectAccess();
void cleanup();
+
+ abstract class EmptyExtractionContext implements ExtractionContext {
+ @Override
+ public ServiceRegistry getServiceRegistry() {
+ return null;
+ }
+
+ @Override
+ public JdbcEnvironment getJdbcEnvironment() {
+ return null;
+ }
+
+ @Override
+ public Connection getJdbcConnection() {
+ return null;
+ }
+
+ @Override
+ public DatabaseMetaData getJdbcDatabaseMetaData() {
+ return null;
+ }
+
+ @Override
+ public Identifier getDefaultCatalog() {
+ return null;
+ }
+
+ @Override
+ public Identifier getDefaultSchema() {
+ return null;
+ }
+
+ @Override
+ public DatabaseObjectAccess getDatabaseObjectAccess() {
+ return null;
+ }
+
+ @Override
+ public void cleanup() {
+
+ }
+ }
}
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 92c16ded9172..355a3ead6c66 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
@@ -14,17 +14,52 @@
* @author Steve Ebersole
*/
public interface SequenceInformation {
+
/**
* The qualified sequence name.
*
* @return The sequence name
*/
- public QualifiedSequenceName getSequenceName();
+ QualifiedSequenceName getSequenceName();
/**
* Retrieve the extracted increment-size defined for the sequence.
*
* @return The extracted increment size; use a negative number to indicate the increment could not be extracted.
+ *
+ * @deprecated use {@link #getIncrementValue()} instead.
+ */
+ @Deprecated
+ default int getIncrementSize() {
+ Long incrementSize = getIncrementValue();
+ return incrementSize != null ? incrementSize.intValue() : -1;
+ }
+
+ /**
+ * Retrieve the extracted start value defined for the sequence.
+ *
+ * @return The extracted start value or null id the value could not be extracted.
+ */
+ Long 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();
+
+ /**
+ * 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();
+
+ /**
+ * 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.
*/
- public int getIncrementSize();
+ Long getIncrementValue();
}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/PostgreSQLSequenceGeneratorWithSerialTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/PostgreSQLSequenceGeneratorWithSerialTest.java
new file mode 100644
index 000000000000..a30693bcf9c6
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/PostgreSQLSequenceGeneratorWithSerialTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.id.hhh12973;
+
+import java.io.StringReader;
+import java.sql.Statement;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.boot.registry.StandardServiceRegistry;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.dialect.PostgreSQL82Dialect;
+import org.hibernate.id.SequenceMismatchStrategy;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.internal.CoreMessageLogger;
+import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
+
+import org.hibernate.testing.RequiresDialect;
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.logger.LoggerInspectionRule;
+import org.hibernate.testing.logger.Triggerable;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.jboss.logging.Logger;
+
+import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+@RequiresDialect(PostgreSQL82Dialect.class)
+public class PostgreSQLSequenceGeneratorWithSerialTest extends BaseEntityManagerFunctionalTestCase {
+
+ @Rule
+ public LoggerInspectionRule logInspection = new LoggerInspectionRule( Logger.getMessageLogger( CoreMessageLogger.class,
+ SequenceStyleGenerator.class
+ .getName()
+ ) );
+
+ private Triggerable triggerable = logInspection.watchForLogMessages( "HHH000497:" );
+
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class>[] {
+ ApplicationConfiguration.class,
+ };
+ }
+
+ private static final String DROP_SEQUENCE = "DROP SEQUENCE IF EXISTS application_configurations_id_seq";
+ private static final String DROP_TABLE = "DROP TABLE IF EXISTS application_configurations CASCADE";
+ private static final String CREATE_TABLE = "CREATE TABLE application_configurations (id BIGSERIAL NOT NULL PRIMARY KEY)";
+
+ @Override
+ protected void addMappings(Map settings) {
+ triggerable.reset();
+ assertFalse( triggerable.wasTriggered() );
+
+ //For this test, we need to make sure the DB is created prior to bootstrapping Hibernate
+ StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
+ .build();
+
+ SessionFactory sessionFactory = null;
+
+ try {
+ Configuration config = new Configuration();
+ sessionFactory = config.buildSessionFactory( ssr );
+
+ try(Session session = sessionFactory.openSession()) {
+ session.doWork( connection -> {
+ try(Statement statement = connection.createStatement()) {
+ statement.execute( DROP_TABLE );
+ statement.execute( DROP_SEQUENCE );
+ statement.execute( CREATE_TABLE );
+ }
+ } );
+ }
+ }
+ finally {
+ if ( sessionFactory != null ) {
+ sessionFactory.close();
+ }
+ ssr.close();
+ }
+
+ settings.put( AvailableSettings.HBM2DDL_DROP_SCRIPT_SOURCE, new StringReader(
+ DROP_TABLE + ";" + DROP_SEQUENCE
+ ) );
+ settings.put( AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, SequenceMismatchStrategy.FIX);
+ }
+
+ @Override
+ protected void afterEntityManagerFactoryBuilt() {
+ assertTrue( triggerable.wasTriggered() );
+ }
+
+ @Test
+ public void test() {
+
+ final AtomicLong id = new AtomicLong();
+
+ final int ITERATIONS = 51;
+
+ doInJPA( this::entityManagerFactory, entityManager -> {
+ for ( int i = 1; i <= ITERATIONS; i++ ) {
+ ApplicationConfiguration model = new ApplicationConfiguration();
+
+ entityManager.persist( model );
+
+ id.set( model.getId() );
+ }
+ } );
+
+ assertEquals( ITERATIONS, id.get() );
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfiguration {
+
+ @Id
+ @javax.persistence.SequenceGenerator(
+ name = "application_configurations_id_seq",
+ sequenceName = "application_configurations_id_seq"
+ )
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "application_configurations_id_seq")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyDefaultExceptionTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyDefaultExceptionTest.java
new file mode 100644
index 000000000000..f7c60efca7e3
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyDefaultExceptionTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.id.hhh12973;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.hibernate.MappingException;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.boot.spi.MetadataImplementor;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.internal.CoreMessageLogger;
+import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
+import org.hibernate.service.ServiceRegistry;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.tool.schema.TargetType;
+
+import org.hibernate.testing.DialectChecks;
+import org.hibernate.testing.RequiresDialectFeature;
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.logger.LoggerInspectionRule;
+import org.hibernate.testing.logger.Triggerable;
+import org.hibernate.testing.util.ExceptionUtil;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.jboss.logging.Logger;
+
+import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
+public class SequenceMismatchStrategyDefaultExceptionTest extends BaseEntityManagerFunctionalTestCase {
+
+ protected ServiceRegistry serviceRegistry;
+ protected MetadataImplementor metadata;
+
+ @Override
+ public void buildEntityManagerFactory() {
+ serviceRegistry = new StandardServiceRegistryBuilder().build();
+ metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
+ .addAnnotatedClass( ApplicationConfigurationHBM2DDL.class )
+ .buildMetadata();
+
+ new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata );
+ try {
+ super.buildEntityManagerFactory();
+
+ fail("Should throw MappingException!");
+ }
+ catch (Exception e) {
+ Throwable rootCause = ExceptionUtil.rootCause( e );
+ assertTrue( rootCause instanceof MappingException );
+ assertTrue( rootCause.getMessage().contains( "in the entity mapping while the associated database sequence increment size is" ) );
+ }
+ }
+
+ @Override
+ public void releaseResources() {
+ super.releaseResources();
+
+ new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
+ StandardServiceRegistryBuilder.destroy( serviceRegistry );
+ }
+
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class>[] {
+ ApplicationConfiguration.class,
+ };
+ }
+
+ @Override
+ protected void addMappings(Map settings) {
+ settings.put( AvailableSettings.HBM2DDL_AUTO, "none" );
+ }
+
+ @Test
+ public void test() {
+
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfigurationHBM2DDL {
+
+ @Id
+ @javax.persistence.SequenceGenerator(
+ name = "app_config_sequence",
+ sequenceName = "app_config_sequence",
+ allocationSize = 1
+ )
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "app_config_sequence")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfiguration {
+
+ @Id
+ @javax.persistence.SequenceGenerator(
+ name = "app_config_sequence",
+ sequenceName = "app_config_sequence"
+ )
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "app_config_sequence")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyExceptionEnumTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyExceptionEnumTest.java
new file mode 100644
index 000000000000..cae595e45ab7
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyExceptionEnumTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.id.hhh12973;
+
+import java.util.Map;
+
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.id.SequenceMismatchStrategy;
+
+import org.hibernate.testing.DialectChecks;
+import org.hibernate.testing.RequiresDialectFeature;
+import org.hibernate.testing.TestForIssue;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
+public class SequenceMismatchStrategyExceptionEnumTest extends SequenceMismatchStrategyDefaultExceptionTest {
+
+ @Override
+ protected void addMappings(Map settings) {
+ super.addMappings( settings );
+ settings.put( AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, SequenceMismatchStrategy.EXCEPTION );
+ }
+
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyFixWithSequenceGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyFixWithSequenceGeneratorTest.java
new file mode 100644
index 000000000000..6d2e86ae88f7
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyFixWithSequenceGeneratorTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.id.hhh12973;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.boot.spi.MetadataImplementor;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.dialect.Oracle8iDialect;
+import org.hibernate.dialect.PostgreSQL82Dialect;
+import org.hibernate.dialect.SQLServer2012Dialect;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.internal.CoreMessageLogger;
+import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
+import org.hibernate.service.ServiceRegistry;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.tool.schema.TargetType;
+
+import org.hibernate.testing.DialectChecks;
+import org.hibernate.testing.RequiresDialect;
+import org.hibernate.testing.RequiresDialectFeature;
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.logger.LoggerInspectionRule;
+import org.hibernate.testing.logger.Triggerable;
+import org.hibernate.test.schemaupdate.SchemaExportWithGlobalQuotingEnabledTest;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.jboss.logging.Logger;
+
+import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
+public class SequenceMismatchStrategyFixWithSequenceGeneratorTest extends BaseEntityManagerFunctionalTestCase {
+
+ @Rule
+ public LoggerInspectionRule logInspection = new LoggerInspectionRule(
+ Logger.getMessageLogger(
+ CoreMessageLogger.class,
+ SequenceStyleGenerator.class.getName()
+ )
+ );
+
+ private Triggerable triggerable = logInspection.watchForLogMessages( "HHH000497:" );
+
+ protected ServiceRegistry serviceRegistry;
+ protected MetadataImplementor metadata;
+
+ @Override
+ public void buildEntityManagerFactory() {
+ serviceRegistry = new StandardServiceRegistryBuilder().build();
+ metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
+ .addAnnotatedClass( ApplicationConfigurationHBM2DDL.class )
+ .buildMetadata();
+
+ new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata );
+ super.buildEntityManagerFactory();
+ }
+
+ @Override
+ public void releaseResources() {
+ super.releaseResources();
+
+ new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
+ StandardServiceRegistryBuilder.destroy( serviceRegistry );
+ }
+
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class>[] {
+ ApplicationConfiguration.class,
+ };
+ }
+
+ @Override
+ protected void addMappings(Map settings) {
+ settings.put( AvailableSettings.HBM2DDL_AUTO, "none" );
+ settings.put( AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, "fix" );
+ triggerable.reset();
+ }
+
+ @Override
+ protected void afterEntityManagerFactoryBuilt() {
+ assertTrue( triggerable.wasTriggered() );
+ }
+
+ @Test
+ public void test() {
+
+ final AtomicLong id = new AtomicLong();
+
+ final int ITERATIONS = 51;
+
+ doInJPA( this::entityManagerFactory, entityManager -> {
+ for ( int i = 1; i <= ITERATIONS; i++ ) {
+ ApplicationConfiguration model = new ApplicationConfiguration();
+
+ entityManager.persist( model );
+
+ id.set( model.getId() );
+ }
+ } );
+
+ assertEquals( ITERATIONS, id.get() );
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfigurationHBM2DDL {
+
+ @Id
+ @javax.persistence.SequenceGenerator(
+ name = "app_config_sequence",
+ sequenceName = "app_config_sequence",
+ allocationSize = 1
+ )
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "app_config_sequence")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfiguration {
+
+ @Id
+ @javax.persistence.SequenceGenerator(
+ name = "app_config_sequence",
+ sequenceName = "app_config_sequence"
+ )
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "app_config_sequence")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyLogTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyLogTest.java
new file mode 100644
index 000000000000..ac5824a0f968
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyLogTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.id.hhh12973;
+
+import java.util.EnumSet;
+import java.util.Map;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.boot.spi.MetadataImplementor;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.internal.CoreMessageLogger;
+import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
+import org.hibernate.service.ServiceRegistry;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.tool.schema.TargetType;
+
+import org.hibernate.testing.DialectChecks;
+import org.hibernate.testing.RequiresDialectFeature;
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.logger.LoggerInspectionRule;
+import org.hibernate.testing.logger.Triggerable;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.jboss.logging.Logger;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
+public class SequenceMismatchStrategyLogTest extends BaseEntityManagerFunctionalTestCase {
+
+ @Rule
+ public LoggerInspectionRule logInspection = new LoggerInspectionRule(
+ Logger.getMessageLogger(
+ CoreMessageLogger.class,
+ SequenceStyleGenerator.class.getName()
+ )
+ );
+
+ private Triggerable triggerable = logInspection.watchForLogMessages( "HHH000497:" );
+
+ protected ServiceRegistry serviceRegistry;
+ protected MetadataImplementor metadata;
+
+ @Override
+ public void buildEntityManagerFactory() {
+ serviceRegistry = new StandardServiceRegistryBuilder().build();
+ metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
+ .addAnnotatedClass( ApplicationConfigurationHBM2DDL.class )
+ .buildMetadata();
+
+ new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata );
+ super.buildEntityManagerFactory();
+ }
+
+ @Override
+ public void releaseResources() {
+ super.releaseResources();
+
+ new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
+ StandardServiceRegistryBuilder.destroy( serviceRegistry );
+ }
+
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class>[] {
+ ApplicationConfiguration.class,
+ };
+ }
+
+ @Override
+ protected void addMappings(Map settings) {
+ settings.put( AvailableSettings.HBM2DDL_AUTO, "none" );
+ settings.put( AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, "log" );
+ triggerable.reset();
+ assertFalse( triggerable.wasTriggered() );
+ }
+
+ @Override
+ protected void afterEntityManagerFactoryBuilt() {
+ assertTrue( triggerable.wasTriggered() );
+ }
+
+ @Test
+ public void test() {
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfigurationHBM2DDL {
+
+ @Id
+ @javax.persistence.SequenceGenerator(
+ name = "app_config_sequence",
+ sequenceName = "app_config_sequence",
+ allocationSize = 1
+ )
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "app_config_sequence")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfiguration {
+
+ @Id
+ @javax.persistence.SequenceGenerator(
+ name = "app_config_sequence",
+ sequenceName = "app_config_sequence"
+ )
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "app_config_sequence")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyLowerCaseStringValueTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyLowerCaseStringValueTest.java
new file mode 100644
index 000000000000..7fd79352ebeb
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyLowerCaseStringValueTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.id.hhh12973;
+
+import org.hibernate.id.SequenceMismatchStrategy;
+
+import org.hibernate.testing.DialectChecks;
+import org.hibernate.testing.RequiresDialectFeature;
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.junit4.BaseUnitTestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+public class SequenceMismatchStrategyLowerCaseStringValueTest extends BaseUnitTestCase {
+
+ @Test
+ public void test() {
+ assertEquals( SequenceMismatchStrategy.EXCEPTION, SequenceMismatchStrategy.interpret( "exception" ) );
+ assertEquals( SequenceMismatchStrategy.LOG, SequenceMismatchStrategy.interpret( "log" ) );
+ assertEquals( SequenceMismatchStrategy.FIX, SequenceMismatchStrategy.interpret( "fix" ) );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyNullValueTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyNullValueTest.java
new file mode 100644
index 000000000000..ced57af2ccb8
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyNullValueTest.java
@@ -0,0 +1,27 @@
+/*
+ * 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.id.hhh12973;
+
+import org.hibernate.id.SequenceMismatchStrategy;
+
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.junit4.BaseUnitTestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+public class SequenceMismatchStrategyNullValueTest extends BaseUnitTestCase {
+
+ @Test
+ public void test() {
+ assertEquals( SequenceMismatchStrategy.EXCEPTION, SequenceMismatchStrategy.interpret( null ) );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyUnknownEnumValueTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyUnknownEnumValueTest.java
new file mode 100644
index 000000000000..bb6bf72eb342
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyUnknownEnumValueTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.id.hhh12973;
+
+import org.hibernate.HibernateException;
+import org.hibernate.id.SequenceMismatchStrategy;
+
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.junit4.BaseUnitTestCase;
+import org.hibernate.testing.util.ExceptionUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+public class SequenceMismatchStrategyUnknownEnumValueTest extends BaseUnitTestCase {
+
+ @Test
+ public void test() {
+ try {
+ SequenceMismatchStrategy.interpret( "acme" );
+
+ fail("Should throw HibernateException!");
+ }
+ catch (Exception e) {
+ Throwable rootCause = ExceptionUtil.rootCause( e );
+ assertTrue( rootCause instanceof HibernateException );
+ assertEquals( "Unrecognized sequence.increment_size_mismatch_strategy value : [acme]. Supported values include [log], [exception], and [fix].", rootCause.getMessage() );
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyUpperCaseStringValueTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyUpperCaseStringValueTest.java
new file mode 100644
index 000000000000..cbb9d57c2954
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyUpperCaseStringValueTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.id.hhh12973;
+
+import org.hibernate.id.SequenceMismatchStrategy;
+
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.junit4.BaseUnitTestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+public class SequenceMismatchStrategyUpperCaseStringValueTest extends BaseUnitTestCase {
+
+ @Test
+ public void test() {
+ assertEquals( SequenceMismatchStrategy.EXCEPTION, SequenceMismatchStrategy.interpret( "EXCEPTION" ) );
+ assertEquals( SequenceMismatchStrategy.LOG, SequenceMismatchStrategy.interpret( "LOG" ) );
+ assertEquals( SequenceMismatchStrategy.FIX, SequenceMismatchStrategy.interpret( "FIX" ) );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyWithoutSequenceGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyWithoutSequenceGeneratorTest.java
new file mode 100644
index 000000000000..51ef22de42ca
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/id/hhh12973/SequenceMismatchStrategyWithoutSequenceGeneratorTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.id.hhh12973;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.boot.spi.MetadataImplementor;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.internal.CoreMessageLogger;
+import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
+import org.hibernate.service.ServiceRegistry;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.tool.schema.TargetType;
+
+import org.hibernate.testing.DialectChecks;
+import org.hibernate.testing.RequiresDialectFeature;
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.logger.LoggerInspectionRule;
+import org.hibernate.testing.logger.Triggerable;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.jboss.logging.Logger;
+
+import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
+public class SequenceMismatchStrategyWithoutSequenceGeneratorTest extends BaseEntityManagerFunctionalTestCase {
+
+ @Rule
+ public LoggerInspectionRule logInspection = new LoggerInspectionRule(
+ Logger.getMessageLogger(
+ CoreMessageLogger.class,
+ SequenceStyleGenerator.class.getName()
+ )
+ );
+
+ private Triggerable triggerable = logInspection.watchForLogMessages( "HHH000497:" );
+
+ protected ServiceRegistry serviceRegistry;
+ protected MetadataImplementor metadata;
+
+ @Override
+ public void buildEntityManagerFactory() {
+ serviceRegistry = new StandardServiceRegistryBuilder().build();
+ metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
+ .addAnnotatedClass( ApplicationConfigurationHBM2DDL.class )
+ .buildMetadata();
+
+ new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata );
+ super.buildEntityManagerFactory();
+ }
+
+ @Override
+ public void releaseResources() {
+ super.releaseResources();
+
+ new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
+ StandardServiceRegistryBuilder.destroy( serviceRegistry );
+ }
+
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class>[] {
+ ApplicationConfiguration.class,
+ };
+ }
+
+ @Override
+ protected void addMappings(Map settings) {
+ settings.put( AvailableSettings.HBM2DDL_AUTO, "none" );
+ triggerable.reset();
+ }
+
+ @Override
+ protected void afterEntityManagerFactoryBuilt() {
+ assertFalse( triggerable.wasTriggered() );
+ }
+
+ @Test
+ public void test() {
+
+ final AtomicLong id = new AtomicLong();
+
+ final int ITERATIONS = 51;
+
+ doInJPA( this::entityManagerFactory, entityManager -> {
+ for ( int i = 1; i <= ITERATIONS; i++ ) {
+ ApplicationConfiguration model = new ApplicationConfiguration();
+
+ entityManager.persist( model );
+
+ id.set( model.getId() );
+ }
+ } );
+
+ assertEquals( ITERATIONS, id.get() );
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfigurationHBM2DDL {
+
+ @Id
+ @javax.persistence.SequenceGenerator(
+ name = "hibernate_sequence",
+ sequenceName = "hibernate_sequence",
+ allocationSize = 1
+ )
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hibernate_sequence")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+
+ @Entity
+ @Table(name = "application_configurations")
+ public static class ApplicationConfiguration {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(final Long id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/connection/DataSourceInjectionTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/connection/DataSourceInjectionTest.java
index 8a113e016f89..c34a643b632f 100644
--- a/hibernate-core/src/test/java/org/hibernate/jpa/test/connection/DataSourceInjectionTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/connection/DataSourceInjectionTest.java
@@ -15,6 +15,7 @@
import org.hibernate.jpa.HibernatePersistenceProvider;
+import org.hibernate.testing.util.ExceptionUtil;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
@@ -49,7 +50,7 @@ public void testDatasourceInjection() throws Exception {
if(emf != null){
emf.close();
}
- Assert.assertTrue( pe.getCause() instanceof FakeDataSourceException );
+ Assert.assertTrue( ExceptionUtil.rootCause( pe ) instanceof FakeDataSourceException );
}
catch (FakeDataSourceException fde) {
//success
diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleSequenceInfoTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleSequenceInfoTest.java
new file mode 100644
index 000000000000..234ba4d4a6a5
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleSequenceInfoTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.test.dialect.functional;
+
+import org.hibernate.dialect.Oracle8iDialect;
+import org.hibernate.tool.schema.extract.spi.SequenceInformation;
+
+import org.hibernate.testing.RequiresDialect;
+import org.hibernate.testing.TestForIssue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+@RequiresDialect(value = {
+ Oracle8iDialect.class
+})
+public class OracleSequenceInfoTest extends
+ SequenceInformationTest {
+
+ @Override
+ protected void assertProductSequence(SequenceInformation productSequenceInfo) {
+ assertNull( productSequenceInfo.getStartValue() );
+ assertEquals( Long.valueOf( 1 ), productSequenceInfo.getMinValue() );
+ assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue() );
+ }
+
+ @Override
+ protected void assertVehicleSequenceInfo(SequenceInformation vehicleSequenceInfo) {
+ assertNull( vehicleSequenceInfo.getStartValue() );
+ assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getMinValue() );
+ assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue() );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SequenceInformationTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SequenceInformationTest.java
new file mode 100644
index 000000000000..0d2868c649ef
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SequenceInformationTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.test.dialect.functional;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
+
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.boot.spi.MetadataImplementor;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.dialect.AbstractHANADialect;
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.InformixDialect;
+import org.hibernate.dialect.PostgreSQL81Dialect;
+import org.hibernate.dialect.SQLServer2012Dialect;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
+import org.hibernate.service.ServiceRegistry;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.tool.schema.TargetType;
+import org.hibernate.tool.schema.extract.spi.SequenceInformation;
+
+import org.hibernate.testing.DialectChecks;
+import org.hibernate.testing.RequiresDialect;
+import org.hibernate.testing.RequiresDialectFeature;
+import org.hibernate.testing.TestForIssue;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@TestForIssue(jiraKey = "HHH-12973")
+@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
+public class SequenceInformationTest extends
+ BaseEntityManagerFunctionalTestCase {
+
+ @Override
+ protected Class>[] getAnnotatedClasses() {
+ return new Class[] {
+ Product.class,
+ Vehicle.class
+ };
+ }
+
+ protected ServiceRegistry serviceRegistry;
+ protected MetadataImplementor metadata;
+
+ @Override
+ public void buildEntityManagerFactory() {
+ serviceRegistry = new StandardServiceRegistryBuilder().build();
+ metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
+ .addAnnotatedClass( Product.class )
+ .addAnnotatedClass( Vehicle.class )
+ .buildMetadata();
+
+ new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
+ new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata );
+ super.buildEntityManagerFactory();
+ }
+
+ @Override
+ public void releaseResources() {
+ super.releaseResources();
+
+ new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
+ StandardServiceRegistryBuilder.destroy( serviceRegistry );
+ }
+
+ @Override
+ protected void addMappings(Map settings) {
+ settings.put( AvailableSettings.HBM2DDL_AUTO, "none" );
+ }
+
+ @Test
+ public void test() {
+
+ SequenceInformation productSequenceInfo = sequenceInformation("product_sequence");
+
+ assertNotNull( productSequenceInfo );
+ assertEquals( "product_sequence", productSequenceInfo.getSequenceName().getSequenceName().getText().toLowerCase() );
+ assertProductSequence( productSequenceInfo );
+
+ SequenceInformation vehicleSequenceInfo = sequenceInformation("vehicle_sequence");
+
+ assertNotNull( vehicleSequenceInfo );
+ assertEquals( "vehicle_sequence", vehicleSequenceInfo.getSequenceName().getSequenceName().getText().toLowerCase() );
+ assertVehicleSequenceInfo( vehicleSequenceInfo );
+ }
+
+ protected void assertProductSequence(SequenceInformation productSequenceInfo) {
+ assertEquals( Long.valueOf( 10 ), productSequenceInfo.getIncrementValue() );
+ }
+
+ protected void assertVehicleSequenceInfo(SequenceInformation vehicleSequenceInfo) {
+ assertEquals( Long.valueOf( 1 ), vehicleSequenceInfo.getIncrementValue() );
+ }
+
+ private SequenceInformation sequenceInformation(String sequenceName) {
+ List sequenceInformationList = entityManagerFactory().unwrap( SessionFactoryImplementor.class ).getJdbcServices().getExtractedMetaDataSupport().getSequenceInformationList();
+
+ return sequenceInformationList.stream().filter(
+ sequenceInformation -> sequenceName.equalsIgnoreCase( sequenceInformation.getSequenceName().getSequenceName().getText() )
+ ).findFirst().orElse( null );
+ }
+
+ @Entity(name = "Product")
+ public static class Product {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_sequence")
+ @SequenceGenerator( name = "product_sequence", sequenceName = "product_sequence", initialValue = 1, allocationSize = 10)
+ private Long id;
+
+ private String name;
+ }
+
+ @Entity(name = "Vehicle")
+ public static class Vehicle {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "vehicle_sequence")
+ @SequenceGenerator( name = "vehicle_sequence", sequenceName = "vehicle_sequence", initialValue = 1, allocationSize = 1)
+ private Long id;
+
+ private String name;
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java
index c7030f93a0fe..166544245eef 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java
@@ -25,7 +25,7 @@ public Dialect getDialect() {
@Override
public String expectedQuerySequencesString() {
- return "select SEQUENCENAME from SYS.SYSSEQUENCES";
+ return "select sys.sysschemas.schemaname as sequence_schema, sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid = sys.sysschemas.schemaid";
}
@Override
diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java
index 9a8480422218..a3835bddf534 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java
@@ -25,7 +25,7 @@ public Dialect getDialect() {
@Override
public String expectedQuerySequencesString() {
- return "select SEQUENCENAME from SYS.SYSSEQUENCES";
+ return "select sys.sysschemas.schemaname as sequence_schema, sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid = sys.sysschemas.schemaid";
}
@Override