diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java index eb67ef858b..dac8429285 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java @@ -85,6 +85,7 @@ import org.hibernate.hql.internal.ast.util.NodeTraverser; import org.hibernate.hql.internal.ast.util.SessionFactoryHelper; import org.hibernate.hql.internal.ast.util.SyntheticAndFactory; import org.hibernate.hql.spi.QueryTranslator; +import org.hibernate.id.BulkInsertionCapableIdentifierGenerator; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.PostInsertIdentifierGenerator; import org.hibernate.id.SequenceGenerator; @@ -724,11 +725,6 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par postProcessDML( ( DeleteStatement ) delete ); } - public static boolean supportsIdGenWithBulkInsertion(IdentifierGenerator generator) { - return SequenceGenerator.class.isAssignableFrom( generator.getClass() ) - || PostInsertIdentifierGenerator.class.isAssignableFrom( generator.getClass() ); - } - @Override protected void postProcessInsert(AST insert) throws SemanticException, QueryException { InsertStatement insertStatement = ( InsertStatement ) insert; @@ -738,37 +734,37 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par Queryable persister = insertStatement.getIntoClause().getQueryable(); if ( !insertStatement.getIntoClause().isExplicitIdInsertion() ) { - // We need to generate ids as part of this bulk insert. - // - // Note that this is only supported for sequence-style generators and - // post-insert-style generators; basically, only in-db generators - IdentifierGenerator generator = persister.getIdentifierGenerator(); - if ( !supportsIdGenWithBulkInsertion( generator ) ) { - throw new QueryException( "can only generate ids as part of bulk insert with either sequence or post-insert style generators" ); + // the insert did not explicitly reference the id. See if + // 1) that is allowed + // 2) whether we need to alter the SQL tree to account for id + final IdentifierGenerator generator = persister.getIdentifierGenerator(); + if ( !BulkInsertionCapableIdentifierGenerator.class.isInstance( generator ) ) { + throw new QueryException( + "Invalid identifier generator encountered for implicit id handling as part of bulk insertions" + ); + } + final BulkInsertionCapableIdentifierGenerator capableGenerator = + BulkInsertionCapableIdentifierGenerator.class.cast( generator ); + if ( ! capableGenerator.supportsBulkInsertionIdentifierGeneration() ) { + throw new QueryException( + "Identifier generator reported it does not support implicit id handling as part of bulk insertions" + ); } - AST idSelectExprNode = null; - - if ( SequenceGenerator.class.isAssignableFrom( generator.getClass() ) ) { - String seqName = ( String ) ( ( SequenceGenerator ) generator ).generatorKey(); - String nextval = sessionFactoryHelper.getFactory().getDialect().getSelectSequenceNextValString( seqName ); - idSelectExprNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, nextval ); - } - else { - //Don't need this, because we should never ever be selecting no columns in an insert ... select... - //and because it causes a bug on DB2 - /*String idInsertString = sessionFactoryHelper.getFactory().getDialect().getIdentityInsertString(); - if ( idInsertString != null ) { - idSelectExprNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, idInsertString ); - }*/ - } - - if ( idSelectExprNode != null ) { - AST currentFirstSelectExprNode = selectClause.getFirstChild(); - selectClause.setFirstChild( idSelectExprNode ); - idSelectExprNode.setNextSibling( currentFirstSelectExprNode ); - - insertStatement.getIntoClause().prependIdColumnSpec(); + final String fragment = capableGenerator.determineBulkInsertionIdentifierGenerationSelectFragment( + sessionFactoryHelper.getFactory().getDialect() + ); + if ( fragment != null ) { + // we got a fragment from the generator, so alter the sql tree... + // + // first, wrap the fragment as a node + AST fragmentNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, fragment ); + // next, rearrange the SQL tree to add the fragment node as the first select expression + AST originalFirstSelectExprNode = selectClause.getFirstChild(); + selectClause.setFirstChild( fragmentNode ); + fragmentNode.setNextSibling( originalFirstSelectExprNode ); + // finally, prepend the id column name(s) to the insert-spec + insertStatement.getIntoClause().prependIdColumnSpec(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java index 3c262feb4f..33abfefdbc 100755 --- a/hibernate-core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,24 +20,33 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.id; + import java.io.Serializable; +import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionImplementor; /** - * Basic implementation of the {@link PostInsertIdentifierGenerator} - * contract. + * Basic implementation of the {@link PostInsertIdentifierGenerator} contract. * * @author Gavin King */ -public abstract class AbstractPostInsertGenerator implements PostInsertIdentifierGenerator { - /** - * {@inheritDoc} - */ +public abstract class AbstractPostInsertGenerator + implements PostInsertIdentifierGenerator, BulkInsertionCapableIdentifierGenerator { + @Override public Serializable generate(SessionImplementor s, Object obj) { return IdentifierGeneratorHelper.POST_INSERT_INDICATOR; } + + @Override + public boolean supportsBulkInsertionIdentifierGeneration() { + return true; + } + + @Override + public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect) { + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/BulkInsertionCapableIdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/BulkInsertionCapableIdentifierGenerator.java new file mode 100644 index 0000000000..74f62e8216 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/id/BulkInsertionCapableIdentifierGenerator.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.id; + +import org.hibernate.dialect.Dialect; + +/** + * Specialized contract for {@link IdentifierGenerator} implementations capable of being used in conjunction + * with HQL insert statements. + * + * @author Steve Ebersole + */ +public interface BulkInsertionCapableIdentifierGenerator extends IdentifierGenerator { + /** + * Given the configuration of this generator, is identifier generation as part of bulk insertion supported? + *

+ * IMPL NOTE : Mainly here to allow stuff like SequenceStyleGenerator which *can* support this based on + * configuration + * + * @return {@code true} if bulk insertions are supported; {@code false} otherwise. + */ + public boolean supportsBulkInsertionIdentifierGeneration(); + + /** + * Return the select expression fragment, if any, that generates the identifier values. + * + * @param dialect The dialect against which the insert will be performed. + * + * @return The identifier value generation fragment (SQL). {@code null} indicates that no fragment is needed. + */ + public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect); +} diff --git a/hibernate-core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java index 57b9812a2d..e763ef0572 100755 --- a/hibernate-core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,9 +20,9 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.id; + import org.hibernate.HibernateException; import org.hibernate.dialect.Dialect; import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate; diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java index 7a5c486441..52d508daa9 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java @@ -22,6 +22,7 @@ * Boston, MA 02110-1301 USA */ package org.hibernate.id; + import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -35,7 +36,6 @@ import org.hibernate.MappingException; import org.hibernate.cfg.ObjectNameNormalizer; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.mapping.Table; import org.hibernate.type.Type; @@ -52,9 +52,10 @@ import org.hibernate.type.Type; * @see TableHiLoGenerator * @author Gavin King */ -public class SequenceGenerator implements PersistentIdentifierGenerator, Configurable { +public class SequenceGenerator + implements PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator, Configurable { - private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, SequenceGenerator.class.getName()); + private static final Logger LOG = Logger.getLogger( SequenceGenerator.class.getName() ); /** * The sequence parameter @@ -76,6 +77,15 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu return identifierType; } + public Object generatorKey() { + return getSequenceName(); + } + + public String getSequenceName() { + return sequenceName; + } + + @Override public void configure(Type type, Properties params, Dialect dialect) throws MappingException { ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER ); sequenceName = normalizer.normalizeIdentifierQuoting( @@ -101,6 +111,7 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu sql = dialect.getSequenceNextValString( sequenceName ); } + @Override public Serializable generate(SessionImplementor session, Object obj) { return generateHolder( session ).makeValue(); } @@ -139,23 +150,28 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu return IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() ); } + @Override + @SuppressWarnings( {"deprecation"}) public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { - String[] ddl = dialect.getCreateSequenceStrings(sequenceName); + String[] ddl = dialect.getCreateSequenceStrings( sequenceName ); if ( parameters != null ) { ddl[ddl.length - 1] += ' ' + parameters; } return ddl; } + @Override public String[] sqlDropStrings(Dialect dialect) throws HibernateException { return dialect.getDropSequenceStrings(sequenceName); } - public Object generatorKey() { - return sequenceName; + @Override + public boolean supportsBulkInsertionIdentifierGeneration() { + return true; } - public String getSequenceName() { - return sequenceName; + @Override + public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect) { + return dialect.getSelectSequenceNextValString( getSequenceName() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java index 7927d319b7..06f8e97cc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Middleware LLC. + * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU @@ -20,7 +20,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.id; @@ -55,11 +54,14 @@ import org.hibernate.type.Type; * * @author Steve Ebersole */ -public class SequenceIdentityGenerator extends SequenceGenerator +public class SequenceIdentityGenerator + extends SequenceGenerator implements PostInsertIdentifierGenerator { - private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, - SequenceIdentityGenerator.class.getName()); + private static final CoreMessageLogger LOG = Logger.getMessageLogger( + CoreMessageLogger.class, + SequenceIdentityGenerator.class.getName() + ); @Override public Serializable generate(SessionImplementor s, Object obj) { diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java index 40b2b88efa..f6f327c37a 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java @@ -87,4 +87,11 @@ public interface DatabaseStructure { * @return The drop commands. */ public String[] sqlDropStrings(Dialect dialect); + + /** + * Is the structure physically a sequence? + * + * @return {@code true} if the actual database structure is a sequence; {@code false} otherwise. + */ + public boolean isPhysicalSequence(); } \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java index 1a06293d23..2186761939 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java @@ -66,39 +66,30 @@ public class SequenceStructure implements DatabaseStructure { sql = dialect.getSequenceNextValString( sequenceName ); } - /** - * {@inheritDoc} - */ + @Override public String getName() { return sequenceName; } - /** - * {@inheritDoc} - */ + @Override public int getIncrementSize() { return incrementSize; } - /** - * {@inheritDoc} - */ + @Override public int getTimesAccessed() { return accessCounter; } - /** - * {@inheritDoc} - */ + @Override public int getInitialValue() { return initialValue; } - /** - * {@inheritDoc} - */ + @Override public AccessCallback buildCallback(final SessionImplementor session) { return new AccessCallback() { + @Override public IntegralDataTypeHolder getNextValue() { accessCounter++; try { @@ -139,25 +130,24 @@ public class SequenceStructure implements DatabaseStructure { }; } - /** - * {@inheritDoc} - */ + @Override public void prepare(Optimizer optimizer) { applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues(); } - /** - * {@inheritDoc} - */ + @Override public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { int sourceIncrementSize = applyIncrementSizeToSourceValues ? incrementSize : 1; return dialect.getCreateSequenceStrings( sequenceName, initialValue, sourceIncrementSize ); } - /** - * {@inheritDoc} - */ + @Override public String[] sqlDropStrings(Dialect dialect) throws HibernateException { return dialect.getDropSequenceStrings( sequenceName ); } + + @Override + public boolean isPhysicalSequence() { + return true; + } } 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 b35516c924..82945bafae 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 @@ -22,6 +22,7 @@ * Boston, MA 02110-1301 USA */ package org.hibernate.id.enhanced; + import java.io.Serializable; import java.util.Properties; @@ -33,6 +34,7 @@ import org.hibernate.cfg.Environment; import org.hibernate.cfg.ObjectNameNormalizer; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.id.BulkInsertionCapableIdentifierGenerator; import org.hibernate.id.Configurable; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.internal.CoreMessageLogger; @@ -95,10 +97,13 @@ import org.hibernate.type.Type; * * @author Steve Ebersole */ -public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Configurable { +public class SequenceStyleGenerator + implements PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator, Configurable { - private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, - SequenceStyleGenerator.class.getName()); + private static final CoreMessageLogger LOG = Logger.getMessageLogger( + CoreMessageLogger.class, + SequenceStyleGenerator.class.getName() + ); // general purpose parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public static final String SEQUENCE_PARAM = "sequence_name"; @@ -155,9 +160,7 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co // Configurable implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - /** - * {@inheritDoc} - */ + @Override public void configure(Type type, Properties params, Dialect dialect) throws MappingException { this.identifierType = type; boolean forceTableUse = ConfigurationHelper.getBoolean( FORCE_TBL_PARAM, params, false ); @@ -338,9 +341,7 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co // IdentifierGenerator implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - /** - * {@inheritDoc} - */ + @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { return optimizer.generate( databaseStructure.buildCallback( session ) ); } @@ -348,24 +349,35 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co // PersistentIdentifierGenerator implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - /** - * {@inheritDoc} - */ + @Override public Object generatorKey() { return databaseStructure.getName(); } - /** - * {@inheritDoc} - */ + @Override public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { return databaseStructure.sqlCreateStrings( dialect ); } - /** - * {@inheritDoc} - */ + @Override public String[] sqlDropStrings(Dialect dialect) throws HibernateException { return databaseStructure.sqlDropStrings( dialect ); } + + + // BulkInsertionCapableIdentifierGenerator implementation ~~~~~~~~~~~~~~~~~ + + @Override + public boolean supportsBulkInsertionIdentifierGeneration() { + // it does, as long as + // 1) there is no (non-noop) optimizer in use + // 2) the underlying structure is a sequence + return OptimizerFactory.NoopOptimizer.class.isInstance( getOptimizer() ) + && getDatabaseStructure().isPhysicalSequence(); + } + + @Override + public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect) { + return dialect.getSelectSequenceNextValString( getDatabaseStructure().getName() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java index fdb8c4861e..fbbbfd2666 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java @@ -197,4 +197,9 @@ public class TableStructure implements DatabaseStructure { } return new String[] { sqlDropString.toString() }; } + + @Override + public boolean isPhysicalSequence() { + return false; + } } diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/hql/BulkManipulationTest.java b/hibernate-core/src/matrix/java/org/hibernate/test/hql/BulkManipulationTest.java index a94c17061b..a7555cb777 100644 --- a/hibernate-core/src/matrix/java/org/hibernate/test/hql/BulkManipulationTest.java +++ b/hibernate-core/src/matrix/java/org/hibernate/test/hql/BulkManipulationTest.java @@ -36,6 +36,7 @@ import org.hibernate.Transaction; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.MySQLDialect; import org.hibernate.hql.internal.ast.HqlSqlWalker; +import org.hibernate.id.BulkInsertionCapableIdentifierGenerator; import org.hibernate.id.IdentifierGenerator; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.testing.DialectChecks; @@ -345,7 +346,8 @@ public class BulkManipulationTest extends BaseCoreFunctionalTestCase { protected boolean supportsBulkInsertIdGeneration(Class entityClass) { EntityPersister persister = sessionFactory().getEntityPersister( entityClass.getName() ); IdentifierGenerator generator = persister.getIdentifierGenerator(); - return HqlSqlWalker.supportsIdGenWithBulkInsertion( generator ); + return BulkInsertionCapableIdentifierGenerator.class.isInstance( generator ) + && BulkInsertionCapableIdentifierGenerator.class.cast( generator ).supportsBulkInsertionIdentifierGeneration(); } @Test