Allow Hibernate's Transaction act like JPA's EntityTransaction
This commit is contained in:
parent
3a1eb3382b
commit
ad0aa213bc
|
@ -71,8 +71,13 @@ public class TransactionImpl implements TransactionImplementor {
|
|||
|
||||
@Override
|
||||
public void commit() {
|
||||
if ( !isActive() ) {
|
||||
if ( !isActive( true ) ) {
|
||||
// allow MARKED_ROLLBACK to propagate through to transactionDriverControl
|
||||
// the boolean passed to isActive indicates whether MARKED_ROLLBACK should be
|
||||
// considered active
|
||||
//
|
||||
// essentially here we have a transaction that is not active and
|
||||
// has not been marked for rollback only
|
||||
throw new IllegalStateException( "Transaction not successfully started" );
|
||||
}
|
||||
|
||||
|
@ -124,6 +129,7 @@ public class TransactionImpl implements TransactionImplementor {
|
|||
@Override
|
||||
public boolean isActive() {
|
||||
// old behavior considered TransactionStatus#MARKED_ROLLBACK as active
|
||||
// return isActive( jpaCompliance.isJpaTransactionComplianceEnabled() ? false : true );
|
||||
return isActive( true );
|
||||
}
|
||||
|
||||
|
|
|
@ -287,6 +287,7 @@ public class SequenceStyleGenerator
|
|||
fallbackSequenceName = generatorName;
|
||||
}
|
||||
}
|
||||
|
||||
// JPA_ENTITY_NAME value honors <class ... entity-name="..."> (HBM) and @Entity#name (JPA) overrides.
|
||||
final String defaultSequenceName = ConfigurationHelper.getBoolean( CONFIG_PREFER_SEQUENCE_PER_ENTITY, params, false )
|
||||
? params.getProperty( JPA_ENTITY_NAME ) + sequencePerEntitySuffix
|
||||
|
|
|
@ -361,7 +361,11 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
|
||||
@Override
|
||||
public void markForRollbackOnly() {
|
||||
accessTransaction().markRollbackOnly();
|
||||
try {
|
||||
accessTransaction().markRollbackOnly();
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -670,6 +674,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
return query;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
markForRollbackOnly();
|
||||
throw exceptionConverter.convert( e );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,6 +183,41 @@ public class SQLQueryReturnProcessor {
|
|||
return new ResultAliasContext();
|
||||
}
|
||||
|
||||
private interface QueryReturnVisitor {
|
||||
void visitScalarReturn(NativeSQLQueryScalarReturn rtn);
|
||||
void visitRootReturn(NativeSQLQueryRootReturn rtn);
|
||||
void visitCollectionReturn(NativeSQLQueryCollectionReturn rtn);
|
||||
|
||||
void visitFetch(NativeSQLQueryJoinReturn rtn);
|
||||
|
||||
void visitDynamicInstantiation(NativeSQLQueryConstructorReturn rtn);
|
||||
}
|
||||
|
||||
public void visitReturns(QueryReturnVisitor visitor) {
|
||||
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
|
||||
if ( NativeSQLQueryScalarReturn.class.isInstance( queryReturn ) ) {
|
||||
visitor.visitScalarReturn( (NativeSQLQueryScalarReturn) queryReturn );
|
||||
}
|
||||
else if ( NativeSQLQueryRootReturn.class.isInstance( queryReturn ) ) {
|
||||
visitor.visitRootReturn( (NativeSQLQueryRootReturn) queryReturn );
|
||||
}
|
||||
else if ( NativeSQLQueryCollectionReturn.class.isInstance( queryReturn ) ) {
|
||||
visitor.visitCollectionReturn( (NativeSQLQueryCollectionReturn) queryReturn );
|
||||
}
|
||||
else if ( NativeSQLQueryJoinReturn.class.isInstance( queryReturn ) ) {
|
||||
visitor.visitFetch( (NativeSQLQueryJoinReturn) queryReturn );
|
||||
}
|
||||
else if ( NativeSQLQueryConstructorReturn.class.isInstance( queryReturn ) ) {
|
||||
visitor.visitDynamicInstantiation( (NativeSQLQueryConstructorReturn) queryReturn );
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Unrecognized NativeSQLQueryReturn concrete type : " + queryReturn
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Return> generateCustomReturns(boolean queryHadAliases) {
|
||||
List<Return> customReturns = new ArrayList<Return>();
|
||||
Map<String,Return> customReturnsByAlias = new HashMap<String,Return>();
|
||||
|
@ -354,6 +389,58 @@ public class SQLQueryReturnProcessor {
|
|||
return customReturns;
|
||||
}
|
||||
|
||||
public List<Return> generateCallableReturns() {
|
||||
final List<Return> customReturns = new ArrayList<>();
|
||||
|
||||
visitReturns(
|
||||
new QueryReturnVisitor() {
|
||||
@Override
|
||||
public void visitScalarReturn(NativeSQLQueryScalarReturn rtn) {
|
||||
customReturns.add( new ScalarReturn( rtn.getType(), rtn.getColumnAlias() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRootReturn(NativeSQLQueryRootReturn rtn) {
|
||||
customReturns.add(
|
||||
new RootReturn(
|
||||
rtn.getAlias(),
|
||||
rtn.getReturnEntityName(),
|
||||
new ColumnEntityAliases(
|
||||
(Map) entityPropertyResultMaps.get( rtn.getAlias() ),
|
||||
(SQLLoadable) alias2Persister.get( rtn.getAlias() ),
|
||||
(String) alias2Suffix.get( rtn.getAlias() )
|
||||
),
|
||||
rtn.getLockMode()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCollectionReturn(NativeSQLQueryCollectionReturn rtn) {
|
||||
throw new UnsupportedOperationException( "Collection returns not supported for stored procedure mapping" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFetch(NativeSQLQueryJoinReturn rtn) {
|
||||
throw new UnsupportedOperationException( "Collection returns not supported for stored procedure mapping" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDynamicInstantiation(NativeSQLQueryConstructorReturn rtn) {
|
||||
final ScalarReturn[] scalars = new ScalarReturn[ rtn.getColumnReturns().length ];
|
||||
int i = 0;
|
||||
for ( NativeSQLQueryScalarReturn scalarReturn : rtn.getColumnReturns() ) {
|
||||
scalars[i++] = new ScalarReturn( scalarReturn.getType(), scalarReturn.getColumnAlias() );
|
||||
}
|
||||
|
||||
customReturns.add( new ConstructorReturn( rtn.getTargetClass(), scalars ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return customReturns;
|
||||
}
|
||||
|
||||
private SQLLoadable getSQLLoadable(String entityName) throws MappingException {
|
||||
EntityPersister persister = factory.getEntityPersister( entityName );
|
||||
if ( !(persister instanceof SQLLoadable) ) {
|
||||
|
|
|
@ -31,7 +31,11 @@ public class JdbcResourceLocalTransactionCoordinatorBuilderImpl implements Trans
|
|||
@Override
|
||||
public TransactionCoordinator buildTransactionCoordinator(TransactionCoordinatorOwner owner, Options options) {
|
||||
if ( owner instanceof JdbcResourceTransactionAccess ) {
|
||||
return new JdbcResourceLocalTransactionCoordinatorImpl( this, owner, (JdbcResourceTransactionAccess) owner );
|
||||
return new JdbcResourceLocalTransactionCoordinatorImpl(
|
||||
this,
|
||||
owner,
|
||||
(JdbcResourceTransactionAccess) owner
|
||||
);
|
||||
}
|
||||
|
||||
throw new HibernateException(
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.resource.transaction.backend.jdbc.internal;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.RollbackException;
|
||||
import javax.transaction.Status;
|
||||
|
||||
import org.hibernate.TransactionException;
|
||||
|
@ -15,6 +16,7 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|||
import org.hibernate.engine.transaction.spi.IsolationDelegate;
|
||||
import org.hibernate.engine.transaction.spi.TransactionObserver;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
|
||||
import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransaction;
|
||||
import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransactionAccess;
|
||||
|
@ -43,6 +45,8 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
|||
private final TransactionCoordinatorOwner transactionCoordinatorOwner;
|
||||
private final SynchronizationRegistryStandardImpl synchronizationRegistry = new SynchronizationRegistryStandardImpl();
|
||||
|
||||
private final JpaCompliance jpaCompliance;
|
||||
|
||||
private TransactionDriverControlImpl physicalTransactionDelegate;
|
||||
|
||||
private int timeOut = -1;
|
||||
|
@ -63,6 +67,12 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
|||
this.transactionCoordinatorBuilder = transactionCoordinatorBuilder;
|
||||
this.jdbcResourceTransactionAccess = jdbcResourceTransactionAccess;
|
||||
this.transactionCoordinatorOwner = owner;
|
||||
|
||||
this.jpaCompliance = owner.getJdbcSessionOwner()
|
||||
.getJdbcSessionContext()
|
||||
.getSessionFactory()
|
||||
.getSessionFactoryOptions()
|
||||
.getJpaCompliance();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,6 +117,11 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
|||
return synchronizationRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return jpaCompliance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return transactionCoordinatorOwner.isActive();
|
||||
|
@ -225,13 +240,32 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
|||
public void commit() {
|
||||
try {
|
||||
if ( rollbackOnly ) {
|
||||
throw new TransactionException( "Transaction was marked for rollback only; cannot commit" );
|
||||
log.debugf( "On commit, transaction was marked for roll-back only, rolling back" );
|
||||
|
||||
try {
|
||||
rollback();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
log.debug( "Encountered failure rolling back failed commit", e );
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
if ( jpaCompliance.isJpaTransactionComplianceEnabled() ) {
|
||||
throw new RollbackException( "Transaction was marked for rollback-only" );
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JdbcResourceLocalTransactionCoordinatorImpl.this.beforeCompletionCallback();
|
||||
jdbcResourceTransaction.commit();
|
||||
JdbcResourceLocalTransactionCoordinatorImpl.this.afterCompletionCallback( true );
|
||||
}
|
||||
catch (RollbackException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
try {
|
||||
rollback();
|
||||
|
@ -261,7 +295,7 @@ public class JdbcResourceLocalTransactionCoordinatorImpl implements TransactionC
|
|||
|
||||
@Override
|
||||
public void markRollbackOnly() {
|
||||
if ( getStatus() != TransactionStatus.ROLLED_BACK && getStatus() != TransactionStatus.NOT_ACTIVE ) {
|
||||
if ( getStatus() != TransactionStatus.ROLLED_BACK ) {
|
||||
if ( log.isDebugEnabled() ) {
|
||||
log.debug(
|
||||
"JDBC transaction marked for rollback-only (exception provided for stack trace)",
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|||
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
||||
import org.hibernate.engine.transaction.spi.IsolationDelegate;
|
||||
import org.hibernate.engine.transaction.spi.TransactionObserver;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
|
||||
import org.hibernate.resource.transaction.TransactionRequiredForJoinException;
|
||||
|
@ -74,11 +75,12 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
|||
TransactionCoordinatorBuilder transactionCoordinatorBuilder,
|
||||
TransactionCoordinatorOwner owner,
|
||||
boolean autoJoinTransactions) {
|
||||
this.observers = new ArrayList<TransactionObserver>();
|
||||
this.transactionCoordinatorBuilder = transactionCoordinatorBuilder;
|
||||
this.transactionCoordinatorOwner = owner;
|
||||
this.autoJoinTransactions = autoJoinTransactions;
|
||||
|
||||
this.observers = new ArrayList<>();
|
||||
|
||||
final JdbcSessionContext jdbcSessionContext = owner.getJdbcSessionOwner().getJdbcSessionContext();
|
||||
|
||||
this.jtaPlatform = jdbcSessionContext.getServiceRegistry().getService( JtaPlatform.class );
|
||||
|
@ -100,7 +102,6 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
|||
boolean preferUserTransactions,
|
||||
boolean performJtaThreadTracking,
|
||||
TransactionObserver... observers) {
|
||||
this.observers = new ArrayList<TransactionObserver>();
|
||||
this.transactionCoordinatorBuilder = transactionCoordinatorBuilder;
|
||||
this.transactionCoordinatorOwner = owner;
|
||||
this.autoJoinTransactions = autoJoinTransactions;
|
||||
|
@ -108,6 +109,8 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
|||
this.preferUserTransactions = preferUserTransactions;
|
||||
this.performJtaThreadTracking = performJtaThreadTracking;
|
||||
|
||||
this.observers = new ArrayList<>();
|
||||
|
||||
if ( observers != null ) {
|
||||
Collections.addAll( this.observers, observers );
|
||||
}
|
||||
|
@ -207,6 +210,15 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy
|
|||
return this.transactionCoordinatorOwner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return transactionCoordinatorOwner.getJdbcSessionOwner()
|
||||
.getJdbcSessionContext()
|
||||
.getSessionFactory()
|
||||
.getSessionFactoryOptions()
|
||||
.getJpaCompliance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionDriver getTransactionDriverControl() {
|
||||
if ( physicalTransactionDelegate == null ) {
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.resource.transaction.spi;
|
|||
|
||||
import org.hibernate.engine.transaction.spi.IsolationDelegate;
|
||||
import org.hibernate.engine.transaction.spi.TransactionObserver;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
|
||||
/**
|
||||
* Models the coordination of all transaction related flows.
|
||||
|
@ -15,6 +16,28 @@ import org.hibernate.engine.transaction.spi.TransactionObserver;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface TransactionCoordinator {
|
||||
/**
|
||||
* Access to the builder that generated this coordinator
|
||||
*/
|
||||
TransactionCoordinatorBuilder getTransactionCoordinatorBuilder();
|
||||
|
||||
/**
|
||||
* Get the delegate used by the local transaction driver to control the underlying transaction
|
||||
*
|
||||
* @return The control delegate.
|
||||
*/
|
||||
TransactionDriver getTransactionDriverControl();
|
||||
|
||||
/**
|
||||
* Get access to the local registry of Synchronization instances
|
||||
*
|
||||
* @return The local Synchronization registry
|
||||
*/
|
||||
SynchronizationRegistry getLocalSynchronizations();
|
||||
|
||||
|
||||
JpaCompliance getJpaCompliance();
|
||||
|
||||
/**
|
||||
* Indicates an explicit request to join a transaction. This is mainly intended to handle the JPA requirement
|
||||
* around {@link javax.persistence.EntityManager#joinTransaction()}, and generally speaking only has an impact in
|
||||
|
@ -35,20 +58,6 @@ public interface TransactionCoordinator {
|
|||
*/
|
||||
void pulse();
|
||||
|
||||
/**
|
||||
* Get the delegate used by the local transaction driver to control the underlying transaction
|
||||
*
|
||||
* @return The control delegate.
|
||||
*/
|
||||
TransactionDriver getTransactionDriverControl();
|
||||
|
||||
/**
|
||||
* Get access to the local registry of Synchronization instances
|
||||
*
|
||||
* @return The local Synchronization registry
|
||||
*/
|
||||
SynchronizationRegistry getLocalSynchronizations();
|
||||
|
||||
/**
|
||||
* Is this transaction still active?
|
||||
* <p/>
|
||||
|
@ -85,12 +94,6 @@ public interface TransactionCoordinator {
|
|||
*/
|
||||
void removeObserver(TransactionObserver observer);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TransactionCoordinatorBuilder getTransactionCoordinatorBuilder();
|
||||
|
||||
void setTimeOut(int seconds);
|
||||
|
||||
int getTimeOut();
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.result.internal;
|
|||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -18,8 +19,11 @@ import org.hibernate.JDBCException;
|
|||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.custom.CustomLoader;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.loader.custom.Return;
|
||||
import org.hibernate.loader.custom.RootReturn;
|
||||
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.result.NoMoreReturnsException;
|
||||
|
@ -231,7 +235,7 @@ public class OutputsImpl implements Outputs {
|
|||
context.getSession().getFactory()
|
||||
);
|
||||
processor.process();
|
||||
final List<org.hibernate.loader.custom.Return> customReturns = processor.generateCustomReturns( false );
|
||||
final List<org.hibernate.loader.custom.Return> customReturns = processor.generateCallableReturns();
|
||||
|
||||
CustomQuery customQuery = new CustomQuery() {
|
||||
@Override
|
||||
|
@ -264,8 +268,11 @@ public class OutputsImpl implements Outputs {
|
|||
}
|
||||
|
||||
private static class CustomLoaderExtension extends CustomLoader {
|
||||
private QueryParameters queryParameters;
|
||||
private SharedSessionContractImplementor session;
|
||||
private static final EntityAliases[] NO_ALIASES = new EntityAliases[0];
|
||||
|
||||
private final QueryParameters queryParameters;
|
||||
private final SharedSessionContractImplementor session;
|
||||
private final EntityAliases[] entityAliases;
|
||||
|
||||
private boolean needsDiscovery = true;
|
||||
|
||||
|
@ -276,8 +283,33 @@ public class OutputsImpl implements Outputs {
|
|||
super( customQuery, session.getFactory() );
|
||||
this.queryParameters = queryParameters;
|
||||
this.session = session;
|
||||
|
||||
entityAliases = interpretEntityAliases( customQuery.getCustomQueryReturns() );
|
||||
}
|
||||
|
||||
private EntityAliases[] interpretEntityAliases(List<Return> customQueryReturns) {
|
||||
final List<EntityAliases> entityAliases = new ArrayList<>();
|
||||
for ( Return queryReturn : customQueryReturns ) {
|
||||
if ( !RootReturn.class.isInstance( queryReturn ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entityAliases.add( ( (RootReturn) queryReturn ).getEntityAliases() );
|
||||
}
|
||||
|
||||
if ( entityAliases.isEmpty() ) {
|
||||
return NO_ALIASES;
|
||||
}
|
||||
|
||||
return entityAliases.toArray( new EntityAliases[ entityAliases.size() ] );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityAliases[] getEntityAliases() {
|
||||
return entityAliases;
|
||||
}
|
||||
|
||||
|
||||
// todo : this would be a great way to add locking to stored procedure support (at least where returning entities).
|
||||
|
||||
public List processResultSet(ResultSet resultSet) throws SQLException {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.jpa.test.transaction;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
|
@ -16,6 +17,7 @@ import javax.persistence.RollbackException;
|
|||
import javax.persistence.TransactionRequiredException;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.stat.Statistics;
|
||||
|
@ -226,6 +228,7 @@ public class FlushAndTransactionTest extends BaseEntityManagerFunctionalTestCase
|
|||
catch ( PersistenceException e ) {
|
||||
//success
|
||||
}
|
||||
|
||||
try {
|
||||
em.getTransaction().commit();
|
||||
fail( "Commit should be rollbacked" );
|
||||
|
@ -288,13 +291,6 @@ public class FlushAndTransactionTest extends BaseEntityManagerFunctionalTestCase
|
|||
em.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Book.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRollbackOnlyAndFlush() throws Exception {
|
||||
Book book = new Book();
|
||||
|
@ -313,4 +309,17 @@ public class FlushAndTransactionTest extends BaseEntityManagerFunctionalTestCase
|
|||
em.close();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Book.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
super.addConfigOptions( options );
|
||||
options.put( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,20 +8,19 @@
|
|||
//$Id$
|
||||
package org.hibernate.test.annotations;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.hql.internal.ast.QuerySyntaxException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -54,25 +53,37 @@ public class ConfigurationTest {
|
|||
cfg.configure( "org/hibernate/test/annotations/hibernate.cfg.xml" );
|
||||
cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
|
||||
cfg.setProperty( Configuration.ARTEFACT_PROCESSING_ORDER, "class" );
|
||||
SessionFactory sf = cfg.buildSessionFactory();
|
||||
assertNotNull( sf );
|
||||
Session s = sf.openSession();
|
||||
Transaction tx = s.beginTransaction();
|
||||
Query q;
|
||||
try {
|
||||
s.createQuery( "from Boat" ).list();
|
||||
fail( "Boat should not be mapped" );
|
||||
|
||||
try ( SessionFactoryImplementor sf = (SessionFactoryImplementor) cfg.buildSessionFactory() ) {
|
||||
assertNotNull( sf );
|
||||
|
||||
inTransaction(
|
||||
sf,
|
||||
session -> {
|
||||
try {
|
||||
session.createQuery( "from Boat" ).list();
|
||||
fail( "Boat should not be mapped" );
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTyping( QuerySyntaxException.class, expected.getCause() );
|
||||
// expected outcome
|
||||
|
||||
// see org.hibernate.test.jpa.compliance.tck2_2.QueryApiTest#testInvalidQueryMarksTxnForRollback
|
||||
// for testing of how this invalid query String case is handled in terms of transactions
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
inTransaction(
|
||||
sf,
|
||||
session -> {
|
||||
assertEquals( 0, session.createQuery( "from Plane" ).list().size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QuerySyntaxException.class, e.getCause());
|
||||
//all good
|
||||
}
|
||||
q = s.createQuery( "from Plane" );
|
||||
assertEquals( 0, q.list().size() );
|
||||
tx.commit();
|
||||
s.close();
|
||||
sf.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrecedenceHbm() throws Exception {
|
||||
Configuration cfg = new Configuration();
|
||||
|
|
|
@ -46,6 +46,7 @@ import org.hibernate.dialect.SybaseASE15Dialect;
|
|||
import org.hibernate.dialect.SybaseAnywhereDialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.dialect.TeradataDialect;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory;
|
||||
import org.hibernate.hql.internal.ast.QuerySyntaxException;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
@ -82,6 +83,7 @@ import static org.hamcrest.CoreMatchers.instanceOf;
|
|||
import static org.hibernate.testing.junit4.ExtraAssertions.assertClassAssignability;
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
@ -851,61 +853,84 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
public void testInvalidCollectionDereferencesFail() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
// control group...
|
||||
s.createQuery( "from Animal a join a.offspring o where o.description = 'xyz'" ).list();
|
||||
s.createQuery( "from Animal a join a.offspring o where o.father.description = 'xyz'" ).list();
|
||||
s.createQuery( "from Animal a join a.offspring o order by o.description" ).list();
|
||||
s.createQuery( "from Animal a join a.offspring o order by o.father.description" ).list();
|
||||
|
||||
try {
|
||||
s.createQuery( "from Animal a where a.offspring.description = 'xyz'" ).list();
|
||||
fail( "illegal collection dereference semantic did not cause failure" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch( QueryException qe ) {
|
||||
log.trace("expected failure...", qe);
|
||||
}
|
||||
try ( final SessionImplementor s = (SessionImplementor) openSession() ) {
|
||||
// control group...
|
||||
inTransaction(
|
||||
s,
|
||||
session -> {
|
||||
s.createQuery( "from Animal a join a.offspring o where o.description = 'xyz'" ).list();
|
||||
s.createQuery( "from Animal a join a.offspring o where o.father.description = 'xyz'" ).list();
|
||||
s.createQuery( "from Animal a join a.offspring o order by o.description" ).list();
|
||||
s.createQuery( "from Animal a join a.offspring o order by o.father.description" ).list();
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
s.createQuery( "from Animal a where a.offspring.father.description = 'xyz'" ).list();
|
||||
fail( "illegal collection dereference semantic did not cause failure" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch( QueryException qe ) {
|
||||
log.trace("expected failure...", qe);
|
||||
}
|
||||
inTransaction(
|
||||
s,
|
||||
session -> {
|
||||
try {
|
||||
s.createQuery( "from Animal a where a.offspring.description = 'xyz'" ).list();
|
||||
fail( "illegal collection dereference semantic did not cause failure" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch (QueryException qe) {
|
||||
log.trace( "expected failure...", qe );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
s.createQuery( "from Animal a order by a.offspring.description" ).list();
|
||||
fail( "illegal collection dereference semantic did not cause failure" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch( QueryException qe ) {
|
||||
log.trace("expected failure...", qe);
|
||||
}
|
||||
inTransaction(
|
||||
s,
|
||||
session -> {
|
||||
try {
|
||||
s.createQuery( "from Animal a where a.offspring.father.description = 'xyz'" ).list();
|
||||
fail( "illegal collection dereference semantic did not cause failure" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch (QueryException qe) {
|
||||
log.trace( "expected failure...", qe );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
s.createQuery( "from Animal a order by a.offspring.father.description" ).list();
|
||||
fail( "illegal collection dereference semantic did not cause failure" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch( QueryException qe ) {
|
||||
log.trace("expected failure...", qe);
|
||||
}
|
||||
inTransaction(
|
||||
s,
|
||||
session -> {
|
||||
try {
|
||||
s.createQuery( "from Animal a order by a.offspring.description" ).list();
|
||||
fail( "illegal collection dereference semantic did not cause failure" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch (QueryException qe) {
|
||||
log.trace( "expected failure...", qe );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
inTransaction(
|
||||
s,
|
||||
session -> {
|
||||
try {
|
||||
s.createQuery( "from Animal a order by a.offspring.father.description" ).list();
|
||||
fail( "illegal collection dereference semantic did not cause failure" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch (QueryException qe) {
|
||||
log.trace( "expected failure...", qe );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1571,42 +1596,46 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
@Test
|
||||
@FailureExpected( jiraKey = "unknown" )
|
||||
public void testParameterTypeMismatch() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Query query = s.createQuery( "from Animal a where a.description = :nonstring" )
|
||||
.setParameter( "nonstring", Integer.valueOf( 1 ) );
|
||||
try {
|
||||
query.list();
|
||||
fail( "query execution should have failed" );
|
||||
try ( final SessionImplementor s = (SessionImplementor) openSession() ) {
|
||||
inTransaction(
|
||||
s,
|
||||
session -> {
|
||||
try {
|
||||
s.createQuery( "from Animal a where a.description = :nonstring" )
|
||||
.setParameter( "nonstring", Integer.valueOf( 1 ) )
|
||||
.list();
|
||||
fail( "query execution should have failed" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( TypeMismatchException.class, e.getCause() );
|
||||
}
|
||||
catch (TypeMismatchException tme) {
|
||||
// expected behavior
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( TypeMismatchException.class, e.getCause() );
|
||||
}
|
||||
catch( TypeMismatchException tme ) {
|
||||
// expected behavior
|
||||
}
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleBagFetchesFail() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
try {
|
||||
s.createQuery( "from Human h join fetch h.friends f join fetch f.friends fof" ).list();
|
||||
fail( "failure expected" );
|
||||
try ( final SessionImplementor s = (SessionImplementor) openSession() ) {
|
||||
inTransaction(
|
||||
s,
|
||||
session-> {
|
||||
try {
|
||||
s.createQuery( "from Human h join fetch h.friends f join fetch f.friends fof" ).list();
|
||||
fail( "failure expected" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( MultipleBagFetchException.class, e.getCause() );
|
||||
}
|
||||
catch( HibernateException e ) {
|
||||
assertTrue( "unexpected failure reason : " + e, e.getMessage().indexOf( "multiple bags" ) > 0 );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( MultipleBagFetchException.class, e.getCause() );
|
||||
}
|
||||
catch( HibernateException e ) {
|
||||
assertTrue( "unexpected failure reason : " + e, e.getMessage().indexOf( "multiple bags" ) > 0 );
|
||||
}
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1880,31 +1909,39 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
public void testInvalidFetchSemantics() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
try ( final SessionImplementor s = (SessionImplementor) openSession()) {
|
||||
|
||||
try {
|
||||
s.createQuery( "select mother from Human a left join fetch a.mother mother" ).list();
|
||||
fail( "invalid fetch semantic allowed!" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch( QueryException e ) {
|
||||
}
|
||||
inTransaction(
|
||||
s,
|
||||
session -> {
|
||||
try {
|
||||
s.createQuery( "select mother from Human a left join fetch a.mother mother" ).list();
|
||||
fail( "invalid fetch semantic allowed!" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch( QueryException e ) {
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
s.createQuery( "select mother from Human a left join fetch a.mother mother" ).list();
|
||||
fail( "invalid fetch semantic allowed!" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch( QueryException e ) {
|
||||
}
|
||||
inTransaction(
|
||||
s,
|
||||
session-> {
|
||||
try {
|
||||
s.createQuery( "select mother from Human a left join fetch a.mother mother" ).list();
|
||||
fail( "invalid fetch semantic allowed!" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch( QueryException e ) {
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -12,11 +12,13 @@ import javax.persistence.Id;
|
|||
import org.hibernate.QueryException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
|
@ -63,30 +65,36 @@ public class CaseStatementTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
public void testSimpleCaseStatementWithParamAllResults() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
try ( final SessionImplementor s = (SessionImplementor) openSession() ) {
|
||||
inTransaction(
|
||||
s,
|
||||
session-> {
|
||||
try {
|
||||
s.createQuery( "select case p.name when 'Steve' then :opt1 else :opt2 end from Person p" )
|
||||
.setString( "opt1", "x" )
|
||||
.setString( "opt2", "y" )
|
||||
.list();
|
||||
fail( "was expecting an exception" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch (QueryException expected) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
s.createQuery( "select case p.name when 'Steve' then :opt1 else :opt2 end from Person p" )
|
||||
.setString( "opt1", "x" )
|
||||
.setString( "opt2", "y" )
|
||||
.list();
|
||||
fail( "was expecting an exception" );
|
||||
inTransaction(
|
||||
s,
|
||||
session-> {
|
||||
s.createQuery( "select case p.name when 'Steve' then cast( :opt1 as string ) else cast( :opt2 as string) end from Person p" )
|
||||
.setString( "opt1", "x" )
|
||||
.setString( "opt2", "y" )
|
||||
.list();
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch (QueryException expected) {
|
||||
// expected
|
||||
}
|
||||
|
||||
s.createQuery( "select case p.name when 'Steve' then cast( :opt1 as string ) else cast( :opt2 as string) end from Person p" )
|
||||
.setString( "opt1", "x" )
|
||||
.setString( "opt2", "y" )
|
||||
.list();
|
||||
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -116,29 +124,36 @@ public class CaseStatementTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
public void testSearchedCaseStatementWithAllParamResults() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
try ( final SessionImplementor s = (SessionImplementor) openSession() ) {
|
||||
inTransaction(
|
||||
s,
|
||||
session-> {
|
||||
try {
|
||||
s.createQuery( "select case when p.name = 'Steve' then :opt1 else :opt2 end from Person p" )
|
||||
.setString( "opt1", "x" )
|
||||
.setString( "opt2", "y" )
|
||||
.list();
|
||||
fail( "was expecting an exception" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch (QueryException expected) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
s.createQuery( "select case when p.name = 'Steve' then :opt1 else :opt2 end from Person p" )
|
||||
.setString( "opt1", "x" )
|
||||
.setString( "opt2", "y" )
|
||||
.list();
|
||||
fail( "was expecting an exception" );
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
}
|
||||
catch (QueryException expected) {
|
||||
// expected
|
||||
}
|
||||
inTransaction(
|
||||
s,
|
||||
session-> {
|
||||
s.createQuery( "select case when p.name = 'Steve' then cast( :opt1 as string) else :opt2 end from Person p" )
|
||||
.setString( "opt1", "x" )
|
||||
.setString( "opt2", "y" )
|
||||
.list();
|
||||
|
||||
s.createQuery( "select case when p.name = 'Steve' then cast( :opt1 as string) else :opt2 end from Person p" )
|
||||
.setString( "opt1", "x" )
|
||||
.setString( "opt2", "y" )
|
||||
.list();
|
||||
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,18 +6,25 @@
|
|||
*/
|
||||
package org.hibernate.test.jpa.compliance.tck2_2;
|
||||
|
||||
import javax.persistence.RollbackException;
|
||||
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.inSession;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
|
@ -60,6 +67,78 @@ public class EntityTransactionTests extends BaseUnitTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRollbackOnlyOutcomeExpectations() {
|
||||
final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
|
||||
.applySetting( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" )
|
||||
.build();
|
||||
|
||||
try {
|
||||
final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( ssr )
|
||||
.buildMetadata()
|
||||
.buildSessionFactory();
|
||||
|
||||
try {
|
||||
inSession(
|
||||
sessionFactory,
|
||||
session -> {
|
||||
final Transaction transaction = session.getTransaction();
|
||||
transaction.begin();
|
||||
|
||||
try {
|
||||
assertTrue( transaction.isActive() );
|
||||
|
||||
transaction.setRollbackOnly();
|
||||
assertTrue( transaction.isActive() );
|
||||
assertTrue( transaction.getRollbackOnly() );
|
||||
}
|
||||
finally {
|
||||
if ( transaction.isActive() ) {
|
||||
transaction.rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
inSession(
|
||||
sessionFactory,
|
||||
session -> {
|
||||
final Transaction transaction = session.getTransaction();
|
||||
transaction.begin();
|
||||
|
||||
try {
|
||||
assertTrue( transaction.isActive() );
|
||||
|
||||
transaction.setRollbackOnly();
|
||||
assertTrue( transaction.isActive() );
|
||||
assertTrue( transaction.getRollbackOnly() );
|
||||
|
||||
// now try to commit, this should force a rollback
|
||||
try {
|
||||
transaction.commit();
|
||||
}
|
||||
catch (RollbackException e) {
|
||||
assertFalse( transaction.isActive() );
|
||||
assertThat( transaction.getStatus(), CoreMatchers.is( TransactionStatus.ROLLED_BACK ) );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ( transaction.isActive() ) {
|
||||
transaction.rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
sessionFactory.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
StandardServiceRegistryBuilder.destroy( ssr );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRollbackOnlyExpectations() {
|
||||
final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.test.jpa.compliance.tck2_2;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Parameter;
|
||||
|
@ -16,12 +17,14 @@ import javax.persistence.TemporalType;
|
|||
import javax.persistence.TransactionRequiredException;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
|
@ -38,6 +41,12 @@ public class QueryApiTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
Date dob;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
super.addSettings( settings );
|
||||
settings.put( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
|
@ -181,7 +190,7 @@ public class QueryApiTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
session -> {
|
||||
try {
|
||||
// Query
|
||||
session.createQuery( "select p from Person p where name = ?" ).setMaxResults( -3 );
|
||||
session.createQuery( "select p from Person p where name = ?1" ).setMaxResults( -3 );
|
||||
fail( "expecting failure" );
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
@ -207,4 +216,22 @@ public class QueryApiTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidQueryMarksTxnForRollback() {
|
||||
inSession(
|
||||
session -> {
|
||||
try {
|
||||
assertFalse( session.getTransaction().isActive() );
|
||||
// Query
|
||||
session.createQuery( "invalid" ).list();
|
||||
fail( "expecting failure" );
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue( session.getTransaction().isActive() );
|
||||
assertTrue( session.getTransaction().getRollbackOnly() );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,104 +7,144 @@
|
|||
package org.hibernate.test.resource.transaction.jdbc;
|
||||
|
||||
import org.hibernate.TransactionException;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
|
||||
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.hibernate.test.resource.common.SynchronizationCollectorImpl;
|
||||
import org.hibernate.test.resource.common.SynchronizationErrorImpl;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.anyOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.inSession;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BasicJdbcTransactionTests {
|
||||
public class BasicJdbcTransactionTests extends BaseUnitTestCase {
|
||||
|
||||
private SessionFactoryImplementor generateSessionFactory() {
|
||||
final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
|
||||
// should be the default, but lets be specific about which we want to test
|
||||
.applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jdbc" )
|
||||
.build();
|
||||
try {
|
||||
return (SessionFactoryImplementor) new MetadataSources( ssr ).buildMetadata().buildSessionFactory();
|
||||
}
|
||||
catch (Exception e) {
|
||||
StandardServiceRegistryBuilder.destroy( ssr );
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicUsageTest() throws Exception {
|
||||
final TransactionCoordinatorOwnerTestingImpl owner = new TransactionCoordinatorOwnerTestingImpl();
|
||||
final JdbcResourceLocalTransactionCoordinatorBuilderImpl transactionCoordinatorBuilder =
|
||||
new JdbcResourceLocalTransactionCoordinatorBuilderImpl();
|
||||
public void basicUsageTest() {
|
||||
try ( final SessionFactoryImplementor sf = generateSessionFactory() ) {
|
||||
inSession(
|
||||
sf,
|
||||
session-> {
|
||||
final TransactionCoordinator coordinator = session.getTransactionCoordinator();
|
||||
|
||||
final TransactionCoordinator transactionCoordinator = transactionCoordinatorBuilder.buildTransactionCoordinator(
|
||||
owner,
|
||||
() -> false
|
||||
);
|
||||
final SynchronizationCollectorImpl sync = new SynchronizationCollectorImpl();
|
||||
coordinator.getLocalSynchronizations()
|
||||
.registerSynchronization( sync );
|
||||
|
||||
SynchronizationCollectorImpl sync = new SynchronizationCollectorImpl();
|
||||
transactionCoordinator.getLocalSynchronizations().registerSynchronization( sync );
|
||||
coordinator.getTransactionDriverControl().begin();
|
||||
assertEquals( 0, sync.getBeforeCompletionCount() );
|
||||
assertEquals( 0, sync.getSuccessfulCompletionCount() );
|
||||
assertEquals( 0, sync.getFailedCompletionCount() );
|
||||
|
||||
transactionCoordinator.getTransactionDriverControl().begin();
|
||||
assertEquals( 0, sync.getBeforeCompletionCount() );
|
||||
assertEquals( 0, sync.getSuccessfulCompletionCount() );
|
||||
assertEquals( 0, sync.getFailedCompletionCount() );
|
||||
|
||||
transactionCoordinator.getTransactionDriverControl().commit();
|
||||
assertEquals( 1, sync.getBeforeCompletionCount() );
|
||||
assertEquals( 1, sync.getSuccessfulCompletionCount() );
|
||||
assertEquals( 0, sync.getFailedCompletionCount() );
|
||||
coordinator.getTransactionDriverControl().commit();
|
||||
assertEquals( 1, sync.getBeforeCompletionCount() );
|
||||
assertEquals( 1, sync.getSuccessfulCompletionCount() );
|
||||
assertEquals( 0, sync.getFailedCompletionCount() );
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("EmptyCatchBlock")
|
||||
public void testMarkRollbackOnly() {
|
||||
final TransactionCoordinatorOwnerTestingImpl owner = new TransactionCoordinatorOwnerTestingImpl();
|
||||
final JdbcResourceLocalTransactionCoordinatorBuilderImpl transactionCoordinatorBuilder =
|
||||
new JdbcResourceLocalTransactionCoordinatorBuilderImpl();
|
||||
try ( final SessionFactoryImplementor sf = generateSessionFactory() ) {
|
||||
inSession(
|
||||
sf,
|
||||
session-> {
|
||||
final TransactionCoordinator coordinator = session.getTransactionCoordinator();
|
||||
|
||||
final TransactionCoordinator transactionCoordinator = transactionCoordinatorBuilder.buildTransactionCoordinator(
|
||||
owner,
|
||||
() -> false
|
||||
);
|
||||
|
||||
assertEquals( TransactionStatus.NOT_ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
|
||||
assertEquals( TransactionStatus.NOT_ACTIVE, coordinator.getTransactionDriverControl().getStatus() );
|
||||
|
||||
transactionCoordinator.getTransactionDriverControl().begin();
|
||||
assertEquals( TransactionStatus.ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
|
||||
session.getTransaction().begin();
|
||||
assertEquals( TransactionStatus.ACTIVE, coordinator.getTransactionDriverControl().getStatus() );
|
||||
|
||||
transactionCoordinator.getTransactionDriverControl().markRollbackOnly();
|
||||
assertEquals( TransactionStatus.MARKED_ROLLBACK, transactionCoordinator.getTransactionDriverControl().getStatus() );
|
||||
session.getTransaction().markRollbackOnly();
|
||||
assertEquals( TransactionStatus.MARKED_ROLLBACK, coordinator.getTransactionDriverControl().getStatus() );
|
||||
|
||||
try {
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
catch (TransactionException expected) {
|
||||
}
|
||||
finally {
|
||||
assertThat(
|
||||
coordinator.getTransactionDriverControl().getStatus(),
|
||||
anyOf(
|
||||
is( TransactionStatus.NOT_ACTIVE ),
|
||||
is( TransactionStatus.ROLLED_BACK )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
transactionCoordinator.getTransactionDriverControl().commit();
|
||||
}
|
||||
catch (TransactionException expected) {
|
||||
}
|
||||
finally {
|
||||
assertEquals( TransactionStatus.NOT_ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("EmptyCatchBlock")
|
||||
public void testSynchronizationFailure() {
|
||||
final TransactionCoordinatorOwnerTestingImpl owner = new TransactionCoordinatorOwnerTestingImpl();
|
||||
final JdbcResourceLocalTransactionCoordinatorBuilderImpl transactionCoordinatorBuilder =
|
||||
new JdbcResourceLocalTransactionCoordinatorBuilderImpl();
|
||||
try ( final SessionFactoryImplementor sf = generateSessionFactory() ) {
|
||||
inSession(
|
||||
sf,
|
||||
session -> {
|
||||
final TransactionCoordinator coordinator = session.getTransactionCoordinator();
|
||||
|
||||
final TransactionCoordinator transactionCoordinator = transactionCoordinatorBuilder.buildTransactionCoordinator(
|
||||
owner,
|
||||
() -> false
|
||||
);
|
||||
assertEquals( TransactionStatus.NOT_ACTIVE, coordinator.getTransactionDriverControl().getStatus() );
|
||||
coordinator.getLocalSynchronizations().registerSynchronization( SynchronizationErrorImpl.forBefore() );
|
||||
|
||||
assertEquals( TransactionStatus.NOT_ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
|
||||
transactionCoordinator.getLocalSynchronizations().registerSynchronization( SynchronizationErrorImpl.forBefore() );
|
||||
coordinator.getTransactionDriverControl().begin();
|
||||
assertEquals( TransactionStatus.ACTIVE, coordinator.getTransactionDriverControl().getStatus() );
|
||||
|
||||
transactionCoordinator.getTransactionDriverControl().begin();
|
||||
assertEquals( TransactionStatus.ACTIVE, transactionCoordinator.getTransactionDriverControl().getStatus() );
|
||||
|
||||
try {
|
||||
transactionCoordinator.getTransactionDriverControl().commit();
|
||||
}
|
||||
catch (Exception expected) {
|
||||
}
|
||||
finally {
|
||||
assertEquals(
|
||||
TransactionStatus.NOT_ACTIVE,
|
||||
transactionCoordinator.getTransactionDriverControl().getStatus()
|
||||
try {
|
||||
coordinator.getTransactionDriverControl().commit();
|
||||
}
|
||||
catch (Exception expected) {
|
||||
}
|
||||
finally {
|
||||
assertThat(
|
||||
coordinator.getTransactionDriverControl().getStatus(),
|
||||
anyOf(
|
||||
is( TransactionStatus.NOT_ACTIVE ),
|
||||
is( TransactionStatus.ROLLED_BACK )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.test.sql.storedproc;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityResult;
|
||||
import javax.persistence.FieldResult;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedStoredProcedureQueries;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.QueryHint;
|
||||
import javax.persistence.SqlResultSetMapping;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
|
||||
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class H2ProcTesting {
|
||||
public static void applyProcDefinitions(Configuration configuration) {
|
||||
configuration.addAuxiliaryDatabaseObject(
|
||||
new AuxiliaryDatabaseObject() {
|
||||
@Override
|
||||
public String getExportIdentifier() {
|
||||
return "function:findOneUser";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesToDialect(Dialect dialect) {
|
||||
return H2Dialect.class.isInstance( dialect );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeTablesOnCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlCreateStrings(Dialect dialect) {
|
||||
return new String[] {
|
||||
"CREATE ALIAS findOneUser AS $$\n" +
|
||||
"import org.h2.tools.SimpleResultSet;\n" +
|
||||
"import java.sql.*;\n" +
|
||||
"@CODE\n" +
|
||||
"ResultSet findOneUser() {\n" +
|
||||
" SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||
" rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||
" rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||
" rs.addRow(1, \"Steve\");\n" +
|
||||
" return rs;\n" +
|
||||
"}\n" +
|
||||
"$$"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) {
|
||||
return new String[] {
|
||||
"DROP ALIAS findUser IF EXISTS"
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
configuration.addAuxiliaryDatabaseObject(
|
||||
new AuxiliaryDatabaseObject() {
|
||||
@Override
|
||||
public String getExportIdentifier() {
|
||||
return "function:findUsers";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesToDialect(Dialect dialect) {
|
||||
return H2Dialect.class.isInstance( dialect );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeTablesOnCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlCreateStrings(Dialect dialect) {
|
||||
return new String[] {
|
||||
"CREATE ALIAS findUsers AS $$\n" +
|
||||
"import org.h2.tools.SimpleResultSet;\n" +
|
||||
"import java.sql.*;\n" +
|
||||
"@CODE\n" +
|
||||
"ResultSet findUsers() {\n" +
|
||||
" SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||
" rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||
" rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||
" rs.addRow(1, \"Steve\");\n" +
|
||||
" rs.addRow(2, \"John\");\n" +
|
||||
" rs.addRow(3, \"Jane\");\n" +
|
||||
" return rs;\n" +
|
||||
"}\n" +
|
||||
"$$"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) {
|
||||
return new String[] {"DROP ALIAS findUser IF EXISTS"};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
configuration.addAuxiliaryDatabaseObject(
|
||||
new AuxiliaryDatabaseObject() {
|
||||
@Override
|
||||
public String getExportIdentifier() {
|
||||
return "function:findUserRange";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesToDialect(Dialect dialect) {
|
||||
return H2Dialect.class.isInstance( dialect );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeTablesOnCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlCreateStrings(Dialect dialect) {
|
||||
return new String[] {
|
||||
"CREATE ALIAS findUserRange AS $$\n" +
|
||||
"import org.h2.tools.SimpleResultSet;\n" +
|
||||
"import java.sql.*;\n" +
|
||||
"@CODE\n" +
|
||||
"ResultSet findUserRange(int start, int end) {\n" +
|
||||
" SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||
" rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||
" rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||
" for ( int i = start; i < end; i++ ) {\n" +
|
||||
" rs.addRow(1, \"User \" + i );\n" +
|
||||
" }\n" +
|
||||
" return rs;\n" +
|
||||
"}\n" +
|
||||
"$$"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) {
|
||||
return new String[] {"DROP ALIAS findUserRange IF EXISTS"};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Entity
|
||||
@NamedStoredProcedureQueries( {
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "findUserRangeNoNullPassing",
|
||||
procedureName = "findUserRange",
|
||||
parameters = {
|
||||
@StoredProcedureParameter( type = Integer.class ),
|
||||
@StoredProcedureParameter( type = Integer.class ),
|
||||
}
|
||||
),
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "findUserRangeNamedNullPassing",
|
||||
procedureName = "findUserRange",
|
||||
hints = @QueryHint( name = "hibernate.proc.param_null_passing.firstArg", value = "true" ),
|
||||
parameters = {
|
||||
@StoredProcedureParameter( name = "firstArg", type = Integer.class ),
|
||||
@StoredProcedureParameter( name = "secondArg", type = Integer.class ),
|
||||
}
|
||||
),
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "findUserRangeOrdinalNullPassing",
|
||||
procedureName = "findUserRange",
|
||||
hints = @QueryHint( name = "hibernate.proc.param_null_passing.1", value = "true" ),
|
||||
parameters = {
|
||||
@StoredProcedureParameter( type = Integer.class ),
|
||||
@StoredProcedureParameter( type = Integer.class ),
|
||||
}
|
||||
)
|
||||
} )
|
||||
@SqlResultSetMapping(
|
||||
name = "all-fields",
|
||||
entities = @EntityResult(
|
||||
entityClass = MyEntity.class,
|
||||
fields = {
|
||||
@FieldResult( name = "id", column = "id" ),
|
||||
@FieldResult( name = "name", column = "name" )
|
||||
}
|
||||
)
|
||||
)
|
||||
@SqlResultSetMapping(
|
||||
name = "some-fields",
|
||||
entities = @EntityResult(
|
||||
entityClass = MyEntity.class,
|
||||
fields = {
|
||||
@FieldResult( name = "id", column = "id" )
|
||||
}
|
||||
)
|
||||
)
|
||||
@SqlResultSetMapping(
|
||||
name = "no-fields",
|
||||
entities = @EntityResult(
|
||||
entityClass = MyEntity.class
|
||||
)
|
||||
)
|
||||
public static class MyEntity {
|
||||
@Id
|
||||
public Integer id;
|
||||
String name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.test.sql.storedproc;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.procedure.ProcedureOutputs;
|
||||
import org.hibernate.result.Output;
|
||||
import org.hibernate.result.ResultSetOutput;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RequiresDialect( H2Dialect.class )
|
||||
public class ResultMappingTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { H2ProcTesting.MyEntity.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.configure( configuration );
|
||||
H2ProcTesting.applyProcDefinitions( configuration );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultClass() {
|
||||
inTransaction(
|
||||
sessionFactory(),
|
||||
session -> {
|
||||
final ProcedureCall call = session.createStoredProcedureCall(
|
||||
"findOneUser",
|
||||
H2ProcTesting.MyEntity.class
|
||||
);
|
||||
final ProcedureOutputs procedureResult = call.getOutputs();
|
||||
final Output currentOutput = procedureResult.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
final ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
final Object result = resultSetReturn.getSingleResult();
|
||||
assertTyping( H2ProcTesting.MyEntity.class, result );
|
||||
assertEquals( "Steve", ( (H2ProcTesting.MyEntity) result ).name );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMappingAllFields() {
|
||||
inTransaction(
|
||||
sessionFactory(),
|
||||
session -> {
|
||||
final ProcedureCall call = session.createStoredProcedureCall( "findOneUser", "all-fields" );
|
||||
final ProcedureOutputs procedureResult = call.getOutputs();
|
||||
final Output currentOutput = procedureResult.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
final ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
final Object result = resultSetReturn.getSingleResult();
|
||||
assertTyping( H2ProcTesting.MyEntity.class, result );
|
||||
assertEquals( "Steve", ( (H2ProcTesting.MyEntity) result ).name );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMappingSomeFields() {
|
||||
inTransaction(
|
||||
sessionFactory(),
|
||||
session -> {
|
||||
final ProcedureCall call = session.createStoredProcedureCall( "findOneUser", "some-fields" );
|
||||
final ProcedureOutputs procedureResult = call.getOutputs();
|
||||
final Output currentOutput = procedureResult.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
final ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
final Object result = resultSetReturn.getSingleResult();
|
||||
assertTyping( H2ProcTesting.MyEntity.class, result );
|
||||
assertEquals( "Steve", ( (H2ProcTesting.MyEntity) result ).name );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMappingNoFields() {
|
||||
inTransaction(
|
||||
sessionFactory(),
|
||||
session -> {
|
||||
final ProcedureCall call = session.createStoredProcedureCall( "findOneUser", "no-fields" );
|
||||
final ProcedureOutputs procedureResult = call.getOutputs();
|
||||
final Output currentOutput = procedureResult.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
final ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
final Object result = resultSetReturn.getSingleResult();
|
||||
assertTyping( H2ProcTesting.MyEntity.class, result );
|
||||
assertEquals( "Steve", ( (H2ProcTesting.MyEntity) result ).name );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,19 +7,11 @@
|
|||
package org.hibernate.test.sql.storedproc;
|
||||
|
||||
import java.util.List;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedStoredProcedureQueries;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.QueryHint;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.procedure.ProcedureOutputs;
|
||||
|
@ -31,6 +23,7 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
@ -42,143 +35,13 @@ import static org.junit.Assert.fail;
|
|||
public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { MyEntity.class };
|
||||
return new Class[] { H2ProcTesting.MyEntity.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.configure( configuration );
|
||||
configuration.addAuxiliaryDatabaseObject(
|
||||
new AuxiliaryDatabaseObject() {
|
||||
@Override
|
||||
public String getExportIdentifier() {
|
||||
return "function:findOneUser";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesToDialect(Dialect dialect) {
|
||||
return H2Dialect.class.isInstance( dialect );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeTablesOnCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlCreateStrings(Dialect dialect) {
|
||||
return new String[] {
|
||||
"CREATE ALIAS findOneUser AS $$\n" +
|
||||
"import org.h2.tools.SimpleResultSet;\n" +
|
||||
"import java.sql.*;\n" +
|
||||
"@CODE\n" +
|
||||
"ResultSet findOneUser() {\n" +
|
||||
" SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||
" rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||
" rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||
" rs.addRow(1, \"Steve\");\n" +
|
||||
" return rs;\n" +
|
||||
"}\n" +
|
||||
"$$"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) {
|
||||
return new String[] {
|
||||
"DROP ALIAS findUser IF EXISTS"
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
configuration.addAuxiliaryDatabaseObject(
|
||||
new AuxiliaryDatabaseObject() {
|
||||
@Override
|
||||
public String getExportIdentifier() {
|
||||
return "function:findUsers";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesToDialect(Dialect dialect) {
|
||||
return H2Dialect.class.isInstance( dialect );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeTablesOnCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlCreateStrings(Dialect dialect) {
|
||||
return new String[] {
|
||||
"CREATE ALIAS findUsers AS $$\n" +
|
||||
"import org.h2.tools.SimpleResultSet;\n" +
|
||||
"import java.sql.*;\n" +
|
||||
"@CODE\n" +
|
||||
"ResultSet findUsers() {\n" +
|
||||
" SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||
" rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||
" rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||
" rs.addRow(1, \"Steve\");\n" +
|
||||
" rs.addRow(2, \"John\");\n" +
|
||||
" rs.addRow(3, \"Jane\");\n" +
|
||||
" return rs;\n" +
|
||||
"}\n" +
|
||||
"$$"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) {
|
||||
return new String[] {"DROP ALIAS findUser IF EXISTS"};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
configuration.addAuxiliaryDatabaseObject(
|
||||
new AuxiliaryDatabaseObject() {
|
||||
@Override
|
||||
public String getExportIdentifier() {
|
||||
return "function:findUserRange";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesToDialect(Dialect dialect) {
|
||||
return H2Dialect.class.isInstance( dialect );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeTablesOnCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlCreateStrings(Dialect dialect) {
|
||||
return new String[] {
|
||||
"CREATE ALIAS findUserRange AS $$\n" +
|
||||
"import org.h2.tools.SimpleResultSet;\n" +
|
||||
"import java.sql.*;\n" +
|
||||
"@CODE\n" +
|
||||
"ResultSet findUserRange(int start, int end) {\n" +
|
||||
" SimpleResultSet rs = new SimpleResultSet();\n" +
|
||||
" rs.addColumn(\"ID\", Types.INTEGER, 10, 0);\n" +
|
||||
" rs.addColumn(\"NAME\", Types.VARCHAR, 255, 0);\n" +
|
||||
" for ( int i = start; i < end; i++ ) {\n" +
|
||||
" rs.addRow(1, \"User \" + i );\n" +
|
||||
" }\n" +
|
||||
" return rs;\n" +
|
||||
"}\n" +
|
||||
"$$"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) {
|
||||
return new String[] {"DROP ALIAS findUserRange IF EXISTS"};
|
||||
}
|
||||
}
|
||||
);
|
||||
H2ProcTesting.applyProcDefinitions( configuration );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -413,37 +276,4 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
|||
session.close();
|
||||
}
|
||||
|
||||
@Entity
|
||||
@NamedStoredProcedureQueries( {
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "findUserRangeNoNullPassing",
|
||||
procedureName = "findUserRange",
|
||||
parameters = {
|
||||
@StoredProcedureParameter( type = Integer.class ),
|
||||
@StoredProcedureParameter( type = Integer.class ),
|
||||
}
|
||||
),
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "findUserRangeNamedNullPassing",
|
||||
procedureName = "findUserRange",
|
||||
hints = @QueryHint( name = "hibernate.proc.param_null_passing.firstArg", value = "true" ),
|
||||
parameters = {
|
||||
@StoredProcedureParameter( name = "firstArg", type = Integer.class ),
|
||||
@StoredProcedureParameter( name = "secondArg", type = Integer.class ),
|
||||
}
|
||||
),
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "findUserRangeOrdinalNullPassing",
|
||||
procedureName = "findUserRange",
|
||||
hints = @QueryHint( name = "hibernate.proc.param_null_passing.1", value = "true" ),
|
||||
parameters = {
|
||||
@StoredProcedureParameter( type = Integer.class ),
|
||||
@StoredProcedureParameter( type = Integer.class ),
|
||||
}
|
||||
)
|
||||
} )
|
||||
public static class MyEntity {
|
||||
@Id
|
||||
public Integer id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.hibernate.test.cache.infinispan.util;
|
|||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.Synchronization;
|
||||
|
@ -13,6 +14,8 @@ import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
|||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.engine.transaction.spi.IsolationDelegate;
|
||||
import org.hibernate.engine.transaction.spi.TransactionObserver;
|
||||
import org.hibernate.jpa.JpaCompliance;
|
||||
import org.hibernate.jpa.spi.JpaComplianceImpl;
|
||||
import org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate;
|
||||
import org.hibernate.resource.transaction.backend.jta.internal.StatusTranslator;
|
||||
import org.hibernate.resource.transaction.spi.SynchronizationRegistry;
|
||||
|
@ -112,6 +115,11 @@ public class BatchModeTransactionCoordinator implements TransactionCoordinator {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompliance getJpaCompliance() {
|
||||
return new JpaComplianceImpl( Collections.emptyMap(), false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
try {
|
||||
|
|
|
@ -58,24 +58,43 @@ public class TransactionUtil2 {
|
|||
action.accept( session );
|
||||
log.trace( "Called action - in txn" );
|
||||
|
||||
log.trace( "Committing transaction" );
|
||||
txn.commit();
|
||||
log.trace( "Committed transaction" );
|
||||
if ( txn.isActive() ) {
|
||||
if ( txn.getRollbackOnly() ) {
|
||||
log.trace( "Rolling back transaction due to being marked for rollback only" );
|
||||
txn.rollback();
|
||||
log.trace( "Rolled back transaction due to being marked for rollback only" );
|
||||
}
|
||||
else {
|
||||
log.trace( "Committing transaction" );
|
||||
txn.commit();
|
||||
log.trace( "Committed transaction" );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.tracef(
|
||||
"Error calling action: %s (%s) - rolling back",
|
||||
e.getClass().getName(),
|
||||
e.getMessage()
|
||||
);
|
||||
try {
|
||||
txn.rollback();
|
||||
if ( txn.isActive() ) {
|
||||
log.tracef(
|
||||
"Error calling action: %s (%s) - rolling back",
|
||||
e.getClass().getName(),
|
||||
e.getMessage()
|
||||
);
|
||||
|
||||
try {
|
||||
txn.rollback();
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
log.trace( "Was unable to roll back transaction" );
|
||||
// really nothing else we can do here - the attempt to
|
||||
// rollback already failed and there is nothing else
|
||||
// to clean up.
|
||||
}
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
log.trace( "Was unable to roll back transaction" );
|
||||
// really nothing else we can do here - the attempt to
|
||||
// rollback already failed and there is nothing else
|
||||
// to clean up.
|
||||
else {
|
||||
log.tracef(
|
||||
"Error calling action: %s (%s) - transaction was already rolled back",
|
||||
e.getClass().getName(),
|
||||
e.getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
throw e;
|
||||
|
|
Loading…
Reference in New Issue