merge master
This commit is contained in:
commit
0e62ff4856
|
@ -326,6 +326,19 @@
|
|||
Name of column used for storing ordinal of the change in sets of embeddable elements.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<property>org.hibernate.envers.allow_identifier_reuse</property>
|
||||
</entry>
|
||||
<entry>
|
||||
false
|
||||
</entry>
|
||||
<entry>
|
||||
Guarantees proper validity audit strategy behavior when application reuses identifiers
|
||||
of deleted entities. Exactly one row with <literal>null</literal> end date exists
|
||||
for each identifier.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<bundle start-level="30">mvn:org.apache.aries.transaction/org.apache.aries.transaction.manager/1.0.1</bundle>
|
||||
|
||||
<!-- JPA -->
|
||||
<bundle start-level="30">mvn:org.hibernate.javax.persistence/hibernate-jpa-2.1-api/1.0.0-SNAPSHOT</bundle>
|
||||
<bundle start-level="30">mvn:org.hibernate.javax.persistence/hibernate-jpa-2.1-api/1.0.0.Final</bundle>
|
||||
<!-- No container currently supports JPA 2.1. Clone and build Aries JPA from the following fork (upgrades to
|
||||
JPA 2.1). Aries should be upgrading as soon as the spec is out.
|
||||
https://github.com/brmeyer/aries/tree/jpa21 -->
|
||||
|
@ -46,7 +46,6 @@
|
|||
|
||||
<!-- These do not natively support OSGi, so using 3rd party bundles. -->
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.antlr/2.7.7_5</bundle>
|
||||
<bundle>wrap:mvn:org.javassist/javassist/3.18.0-GA</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.specs/org.apache.servicemix.specs.jsr303-api-1.0.0/2.2.0</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.ant/1.8.2_2</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.dom4j/1.6.1_5</bundle>
|
||||
|
@ -55,8 +54,9 @@
|
|||
<bundle>wrap:mvn:org.jboss/jandex/1.1.0.Alpha1</bundle>
|
||||
|
||||
<bundle>wrap:mvn:org.hibernate.common/hibernate-commons-annotations/4.0.2.Final</bundle>
|
||||
<bundle>mvn:com.fasterxml/classmate/0.8.0</bundle>
|
||||
<bundle>mvn:org.jboss.logging/jboss-logging/3.1.1.GA</bundle>
|
||||
<bundle>mvn:com.fasterxml/classmate/0.5.4</bundle>
|
||||
<bundle>mvn:org.jboss.logging/jboss-logging/3.1.0.GA</bundle>
|
||||
<bundle>mvn:org.javassist/javassist/3.18.0-GA</bundle>
|
||||
|
||||
<bundle>mvn:org.hibernate/hibernate-core/5.0.0-SNAPSHOT</bundle>
|
||||
<bundle>mvn:org.hibernate/hibernate-entitymanager/5.0.0-SNAPSHOT</bundle>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.0.0.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<bundle start-level="30">mvn:org.apache.geronimo.specs/geronimo-jta_1.1_spec/1.1.1</bundle>
|
||||
|
||||
<!-- JPA -->
|
||||
<bundle start-level="30">mvn:org.hibernate.javax.persistence/hibernate-jpa-2.1-api/1.0.0-SNAPSHOT</bundle>
|
||||
<bundle start-level="30">mvn:org.hibernate.javax.persistence/hibernate-jpa-2.1-api/1.0.0.Final</bundle>
|
||||
|
||||
<!-- Taken from Karaf-Tutorial -->
|
||||
<bundle>mvn:commons-collections/commons-collections/3.2.1</bundle>
|
||||
|
@ -21,7 +21,6 @@
|
|||
|
||||
<!-- These do not natively support OSGi, so using 3rd party bundles. -->
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.antlr/2.7.7_5</bundle>
|
||||
<bundle>wrap:mvn:org.javassist/javassist/3.18.0-GA</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.specs/org.apache.servicemix.specs.jsr303-api-1.0.0/2.2.0</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.ant/1.8.2_2</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.dom4j/1.6.1_5</bundle>
|
||||
|
@ -30,8 +29,9 @@
|
|||
<bundle>wrap:mvn:org.hibernate.common/hibernate-commons-annotations/4.0.2.Final</bundle>
|
||||
<bundle>wrap:mvn:org.jboss/jandex/1.1.0.Alpha1</bundle>
|
||||
|
||||
<bundle>mvn:com.fasterxml/classmate/0.8.0</bundle>
|
||||
<bundle>mvn:org.jboss.logging/jboss-logging/3.1.1.GA</bundle>
|
||||
<bundle>mvn:com.fasterxml/classmate/0.5.4</bundle>
|
||||
<bundle>mvn:org.jboss.logging/jboss-logging/3.1.0.GA</bundle>
|
||||
<bundle>mvn:org.javassist/javassist/3.18.0-GA</bundle>
|
||||
|
||||
<bundle>mvn:org.hibernate/hibernate-core/5.0.0-SNAPSHOT</bundle>
|
||||
<bundle>mvn:org.hibernate/hibernate-entitymanager/5.0.0-SNAPSHOT</bundle>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.0.0.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<bundle start-level="30">mvn:org.apache.geronimo.specs/geronimo-jta_1.1_spec/1.1.1</bundle>
|
||||
|
||||
<!-- JPA -->
|
||||
<bundle start-level="30">mvn:org.hibernate.javax.persistence/hibernate-jpa-2.1-api/1.0.0-SNAPSHOT</bundle>
|
||||
<bundle start-level="30">mvn:org.hibernate.javax.persistence/hibernate-jpa-2.1-api/1.0.0.Final</bundle>
|
||||
|
||||
<!-- Taken from Karaf-Tutorial -->
|
||||
<bundle>mvn:commons-collections/commons-collections/3.2.1</bundle>
|
||||
|
@ -21,7 +21,6 @@
|
|||
|
||||
<!-- These do not natively support OSGi, so using 3rd party bundles. -->
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.antlr/2.7.7_5</bundle>
|
||||
<bundle>wrap:mvn:org.javassist/javassist/3.18.0-GA</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.specs/org.apache.servicemix.specs.jsr303-api-1.0.0/2.2.0</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.ant/1.8.2_2</bundle>
|
||||
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.dom4j/1.6.1_5</bundle>
|
||||
|
@ -36,8 +35,9 @@
|
|||
<!-- Optional. Needed to test ehcache 2lc. -->
|
||||
<!-- <bundle>wrap:mvn:net.sf.ehcache/ehcache-core/2.4.3</bundle> -->
|
||||
|
||||
<bundle>mvn:com.fasterxml/classmate/0.8.0</bundle>
|
||||
<bundle>mvn:org.jboss.logging/jboss-logging/3.1.1.GA</bundle>
|
||||
<bundle>mvn:com.fasterxml/classmate/0.5.4</bundle>
|
||||
<bundle>mvn:org.jboss.logging/jboss-logging/3.1.0.GA</bundle>
|
||||
<bundle>mvn:org.javassist/javassist/3.18.0-GA</bundle>
|
||||
|
||||
<!-- JACC is optional. -->
|
||||
<!--<bundle>mvn:javax.servlet/javax.servlet-api/3.0.1</bundle>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.0.0.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
|
|
|
@ -29,6 +29,9 @@ dependencies {
|
|||
// for test runtime
|
||||
transitive = true
|
||||
}
|
||||
// for testing stored procedure support
|
||||
testCompile( libraries.derby )
|
||||
|
||||
|
||||
testRuntime( 'jaxen:jaxen:1.1' )
|
||||
testRuntime( libraries.javassist )
|
||||
|
|
|
@ -1092,9 +1092,17 @@ public class Configuration implements Serializable {
|
|||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Foreign keys must be created *after* unique keys for numerous DBs. See HH-8390.
|
||||
iter = getTableMappings();
|
||||
while ( iter.hasNext() ) {
|
||||
Table table = (Table) iter.next();
|
||||
if ( table.isPhysicalTable() ) {
|
||||
|
||||
if ( dialect.hasAlterTable() ) {
|
||||
subIter = table.getForeignKeyIterator();
|
||||
Iterator subIter = table.getForeignKeyIterator();
|
||||
while ( subIter.hasNext() ) {
|
||||
ForeignKey fk = (ForeignKey) subIter.next();
|
||||
if ( fk.isPhysicalConstraint() ) {
|
||||
|
@ -1232,6 +1240,33 @@ public class Configuration implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
Iterator subIter = table.getIndexIterator();
|
||||
while ( subIter.hasNext() ) {
|
||||
final Index index = (Index) subIter.next();
|
||||
// Skip if index already exists
|
||||
if ( tableInfo != null && StringHelper.isNotEmpty( index.getName() ) ) {
|
||||
final IndexMetadata meta = tableInfo.getIndexMetadata( index.getName() );
|
||||
if ( meta != null ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
scripts.add( new SchemaUpdateScript( index.sqlCreateString( dialect, mapping, tableCatalog,
|
||||
tableSchema ), false ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Foreign keys must be created *after* unique keys for numerous DBs. See HH-8390.
|
||||
iter = getTableMappings();
|
||||
while ( iter.hasNext() ) {
|
||||
Table table = (Table) iter.next();
|
||||
String tableSchema = ( table.getSchema() == null ) ? defaultSchema : table.getSchema();
|
||||
String tableCatalog = ( table.getCatalog() == null ) ? defaultCatalog : table.getCatalog();
|
||||
if ( table.isPhysicalTable() ) {
|
||||
|
||||
TableMetadata tableInfo = databaseMetadata.getTableMetadata( table.getName(), tableSchema,
|
||||
tableCatalog, table.isQuoted() );
|
||||
|
||||
if ( dialect.hasAlterTable() ) {
|
||||
Iterator subIter = table.getForeignKeyIterator();
|
||||
while ( subIter.hasNext() ) {
|
||||
|
@ -1247,20 +1282,6 @@ public class Configuration implements Serializable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Iterator subIter = table.getIndexIterator();
|
||||
while ( subIter.hasNext() ) {
|
||||
final Index index = (Index) subIter.next();
|
||||
// Skip if index already exists
|
||||
if ( tableInfo != null && StringHelper.isNotEmpty( index.getName() ) ) {
|
||||
final IndexMetadata meta = tableInfo.getIndexMetadata( index.getName() );
|
||||
if ( meta != null ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
scripts.add( new SchemaUpdateScript( index.sqlCreateString( dialect, mapping, tableCatalog,
|
||||
tableSchema ), false ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -173,7 +173,8 @@ public class NamedProcedureCallDefinition {
|
|||
: ParameterStrategy.POSITIONAL;
|
||||
parameterDefinitions = new ParameterDefinition[ parameters.length ];
|
||||
for ( int i = 0; i < parameters.length; i++ ) {
|
||||
parameterDefinitions[i] = new ParameterDefinition( i, parameters[i] );
|
||||
// i+1 for the position because the apis say the numbers are 1-based, not zero
|
||||
parameterDefinitions[i] = new ParameterDefinition( i+1, parameters[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ import java.sql.Types;
|
|||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.dialect.function.VarArgsSQLFunction;
|
||||
import org.hibernate.dialect.unique.InformixUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
|
||||
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
|
@ -43,6 +45,8 @@ import org.hibernate.type.StandardBasicTypes;
|
|||
*/
|
||||
public class InformixDialect extends Dialect {
|
||||
|
||||
private final UniqueDelegate uniqueDelegate;
|
||||
|
||||
/**
|
||||
* Creates new <code>InformixDialect</code> instance. Sets up the JDBC /
|
||||
* Informix type mappings.
|
||||
|
@ -77,6 +81,8 @@ public class InformixDialect extends Dialect {
|
|||
registerColumnType( Types.VARCHAR, 32739, "lvarchar($l)" );
|
||||
|
||||
registerFunction( "concat", new VarArgsSQLFunction( StandardBasicTypes.STRING, "(", "||", ")" ) );
|
||||
|
||||
uniqueDelegate = new InformixUniqueDelegate( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -286,4 +292,9 @@ public class InformixDialect extends Dialect {
|
|||
public String getCreateTemporaryTablePostfix() {
|
||||
return "with no log";
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* JBoss, Home of Professional Open Source
|
||||
* Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @authors tag. All rights reserved.
|
||||
* See the copyright.txt in the distribution for a
|
||||
* full listing of individual contributors.
|
||||
*
|
||||
* 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, v. 2.1.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT A
|
||||
* 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,
|
||||
* v.2.1 along with this distribution; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
package org.hibernate.dialect.unique;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.metamodel.relational.UniqueKey;
|
||||
|
||||
/**
|
||||
* Informix requires the constraint name to come last on the alter table.
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public class InformixUniqueDelegate extends DefaultUniqueDelegate {
|
||||
|
||||
public InformixUniqueDelegate( Dialect dialect ) {
|
||||
super( dialect );
|
||||
}
|
||||
|
||||
// legacy model ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public String getAlterTableToAddUniqueKeyCommand(
|
||||
org.hibernate.mapping.UniqueKey uniqueKey,
|
||||
String defaultCatalog,
|
||||
String defaultSchema) {
|
||||
// Do this here, rather than allowing UniqueKey/Constraint to do it.
|
||||
// We need full, simplified control over whether or not it happens.
|
||||
final String tableName = uniqueKey.getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema );
|
||||
final String constraintName = dialect.quote( uniqueKey.getName() );
|
||||
return "alter table " + tableName + " add constraint " + uniqueConstraintSql( uniqueKey ) + " constraint " + constraintName;
|
||||
}
|
||||
|
||||
// new model ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey) {
|
||||
// Do this here, rather than allowing UniqueKey/Constraint to do it.
|
||||
// We need full, simplified control over whether or not it happens.
|
||||
final String tableName = uniqueKey.getTable().getQualifiedName( dialect );
|
||||
final String constraintName = dialect.quote( uniqueKey.getName() );
|
||||
|
||||
return "alter table " + tableName + " add constraint " + uniqueConstraintSql( uniqueKey ) + " constraint " + constraintName;
|
||||
}
|
||||
}
|
|
@ -55,7 +55,7 @@ public class NaturalIdXrefDelegate {
|
|||
private static final Logger LOG = Logger.getLogger( NaturalIdXrefDelegate.class );
|
||||
|
||||
private final StatefulPersistenceContext persistenceContext;
|
||||
private final Map<EntityPersister, NaturalIdResolutionCache> naturalIdResolutionCacheMap = new ConcurrentHashMap<EntityPersister, NaturalIdResolutionCache>();
|
||||
private final ConcurrentHashMap<EntityPersister, NaturalIdResolutionCache> naturalIdResolutionCacheMap = new ConcurrentHashMap<EntityPersister, NaturalIdResolutionCache>();
|
||||
|
||||
/**
|
||||
* Constructs a NaturalIdXrefDelegate
|
||||
|
@ -92,7 +92,10 @@ public class NaturalIdXrefDelegate {
|
|||
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
||||
if ( entityNaturalIdResolutionCache == null ) {
|
||||
entityNaturalIdResolutionCache = new NaturalIdResolutionCache( persister );
|
||||
naturalIdResolutionCacheMap.put( persister, entityNaturalIdResolutionCache );
|
||||
NaturalIdResolutionCache previousInstance = naturalIdResolutionCacheMap.putIfAbsent( persister, entityNaturalIdResolutionCache );
|
||||
if ( previousInstance != null ) {
|
||||
entityNaturalIdResolutionCache = previousInstance;
|
||||
}
|
||||
}
|
||||
return entityNaturalIdResolutionCache.cache( pk, naturalIdValues );
|
||||
}
|
||||
|
@ -279,7 +282,10 @@ public class NaturalIdXrefDelegate {
|
|||
|
||||
if ( entityNaturalIdResolutionCache == null ) {
|
||||
entityNaturalIdResolutionCache = new NaturalIdResolutionCache( persister );
|
||||
naturalIdResolutionCacheMap.put( persister, entityNaturalIdResolutionCache );
|
||||
NaturalIdResolutionCache existingCache = naturalIdResolutionCacheMap.putIfAbsent( persister, entityNaturalIdResolutionCache );
|
||||
if ( existingCache != null ) {
|
||||
entityNaturalIdResolutionCache = existingCache;
|
||||
}
|
||||
}
|
||||
|
||||
entityNaturalIdResolutionCache.pkToNaturalIdMap.put( pk, cachedNaturalId );
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -109,7 +110,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
// private Map<Object,EntityEntry> entityEntries;
|
||||
|
||||
// Entity proxies, by EntityKey
|
||||
private Map<EntityKey, Object> proxiesByKey;
|
||||
private ConcurrentMap<EntityKey, Object> proxiesByKey;
|
||||
|
||||
// Snapshots of current database state for entities
|
||||
// that have *not* been loaded
|
||||
|
@ -563,9 +564,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
final EntityPersister persister = session.getFactory().getEntityPersister( li.getEntityName() );
|
||||
final EntityKey key = session.generateEntityKey( li.getIdentifier(), persister );
|
||||
// any earlier proxy takes precedence
|
||||
if ( !proxiesByKey.containsKey( key ) ) {
|
||||
proxiesByKey.put( key, proxy );
|
||||
}
|
||||
proxiesByKey.putIfAbsent( key, proxy );
|
||||
proxy.getHibernateLazyInitializer().setSession( session );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ public class DriverManagerConnectionProviderImpl
|
|||
private int poolSize;
|
||||
private boolean autocommit;
|
||||
|
||||
//Access guarded by synchronization on the pool instance
|
||||
private final ArrayList<Connection> pool = new ArrayList<Connection>();
|
||||
private final AtomicInteger checkedOut = new AtomicInteger();
|
||||
|
||||
|
@ -170,6 +171,7 @@ public class DriverManagerConnectionProviderImpl
|
|||
public void stop() {
|
||||
LOG.cleaningUpConnectionPool( url );
|
||||
|
||||
synchronized ( pool ) {
|
||||
for ( Connection connection : pool ) {
|
||||
try {
|
||||
connection.close();
|
||||
|
@ -179,6 +181,7 @@ public class DriverManagerConnectionProviderImpl
|
|||
}
|
||||
}
|
||||
pool.clear();
|
||||
}
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ public class HiLoOptimizer extends AbstractOptimizer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IntegralDataTypeHolder getLastSourceValue() {
|
||||
public synchronized IntegralDataTypeHolder getLastSourceValue() {
|
||||
return noTenantGenerationState().lastSourceValue;
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ public class HiLoOptimizer extends AbstractOptimizer {
|
|||
*
|
||||
* @return Value for property 'lastValue'.
|
||||
*/
|
||||
public IntegralDataTypeHolder getLastValue() {
|
||||
public synchronized IntegralDataTypeHolder getLastValue() {
|
||||
return noTenantGenerationState().value.copy().decrement();
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ public class HiLoOptimizer extends AbstractOptimizer {
|
|||
*
|
||||
* @return Value for property 'upperLimit'.
|
||||
*/
|
||||
public IntegralDataTypeHolder getHiValue() {
|
||||
public synchronized IntegralDataTypeHolder getHiValue() {
|
||||
return noTenantGenerationState().upperLimit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IntegralDataTypeHolder getLastSourceValue() {
|
||||
public synchronized IntegralDataTypeHolder getLastSourceValue() {
|
||||
return noTenantGenerationState().lastSourceValue.copy();
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
|
|||
* @return Value for property 'lastValue'.
|
||||
*/
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public IntegralDataTypeHolder getLastValue() {
|
||||
public synchronized IntegralDataTypeHolder getLastValue() {
|
||||
return noTenantGenerationState().value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,8 @@ public final class StringHelper {
|
|||
public static int lastIndexOfLetter(String string) {
|
||||
for ( int i=0; i<string.length(); i++ ) {
|
||||
char character = string.charAt(i);
|
||||
if ( !Character.isLetter(character) /*&& !('_'==character)*/ ) return i-1;
|
||||
// Include "_". See HHH-8073
|
||||
if ( !Character.isLetter(character) && !('_'==character) ) return i-1;
|
||||
}
|
||||
return string.length()-1;
|
||||
}
|
||||
|
|
|
@ -594,6 +594,17 @@ public class CustomLoader extends Loader {
|
|||
rowProcessor.columnProcessors[i].performDiscovery( metadata, types, aliases );
|
||||
}
|
||||
|
||||
validateAliases( aliases );
|
||||
|
||||
resultTypes = ArrayHelper.toTypeArray( types );
|
||||
transformerAliases = ArrayHelper.toStringArray( aliases );
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new HibernateException( "Exception while trying to autodiscover types.", e );
|
||||
}
|
||||
}
|
||||
|
||||
private void validateAliases(List<String> aliases) {
|
||||
// lets make sure we did not end up with duplicate aliases. this can occur when the user supplied query
|
||||
// did not rename same-named columns. e.g.:
|
||||
// select u.username, u2.username from t_user u, t_user u2 ...
|
||||
|
@ -603,6 +614,7 @@ public class CustomLoader extends Loader {
|
|||
// troublesome condition, so lets throw an error. See HHH-5992
|
||||
final HashSet<String> aliasesSet = new HashSet<String>();
|
||||
for ( String alias : aliases ) {
|
||||
validateAlias( alias );
|
||||
boolean alreadyExisted = !aliasesSet.add( alias );
|
||||
if ( alreadyExisted ) {
|
||||
throw new NonUniqueDiscoveredSqlAliasException(
|
||||
|
@ -611,13 +623,9 @@ public class CustomLoader extends Loader {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resultTypes = ArrayHelper.toTypeArray( types );
|
||||
transformerAliases = ArrayHelper.toStringArray( aliases );
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new HibernateException( "Exception while trying to autodiscover types.", e );
|
||||
}
|
||||
protected void validateAlias(String alias) {
|
||||
}
|
||||
|
||||
private static class Metadata {
|
||||
|
|
|
@ -111,7 +111,7 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
@Override
|
||||
public String getAlias(Dialect dialect) {
|
||||
final int lastLetter = StringHelper.lastIndexOfLetter( name );
|
||||
String suffix = Integer.toString(uniqueInteger) + '_';
|
||||
final String suffix = Integer.toString(uniqueInteger) + '_';
|
||||
|
||||
String alias = name;
|
||||
if ( lastLetter == -1 ) {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.procedure;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NoSuchParameterException extends HibernateException {
|
||||
public NoSuchParameterException(String message) {
|
||||
super( message );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.procedure;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ParameterStrategyException extends HibernateException {
|
||||
public ParameterStrategyException(String message) {
|
||||
super( message );
|
||||
}
|
||||
}
|
|
@ -82,6 +82,9 @@ public interface ProcedureCall extends BasicQueryContract, SynchronizeableQuery
|
|||
* @param position The parameter position
|
||||
*
|
||||
* @return The parameter registration memento
|
||||
*
|
||||
* @throws ParameterStrategyException If the ProcedureCall is defined using named parameters
|
||||
* @throws NoSuchParameterException If no parameter with that position exists
|
||||
*/
|
||||
public ParameterRegistration getParameterRegistration(int position);
|
||||
|
||||
|
@ -122,6 +125,9 @@ public interface ProcedureCall extends BasicQueryContract, SynchronizeableQuery
|
|||
* @param name The parameter name
|
||||
*
|
||||
* @return The parameter registration memento
|
||||
*
|
||||
* @throws ParameterStrategyException If the ProcedureCall is defined using positional parameters
|
||||
* @throws NoSuchParameterException If no parameter with that name exists
|
||||
*/
|
||||
public ParameterRegistration getParameterRegistration(String name);
|
||||
|
||||
|
@ -134,13 +140,14 @@ public interface ProcedureCall extends BasicQueryContract, SynchronizeableQuery
|
|||
|
||||
/**
|
||||
* Retrieves access to outputs of this procedure call. Can be called multiple times, returning the same
|
||||
* Output instance each time.
|
||||
* ProcedureResult instance each time.
|
||||
* <p/>
|
||||
* Note that the procedure will not actually be executed until the outputs are actually accessed.
|
||||
* If the procedure call has not actually be executed yet, it will be executed and then the ProcedureResult
|
||||
* will be returned.
|
||||
*
|
||||
* @return The outputs representation
|
||||
* @return The ProcedureResult representation
|
||||
*/
|
||||
public ProcedureResult getResult();
|
||||
public ProcedureOutputs getResult();
|
||||
|
||||
/**
|
||||
* Extract the disconnected representation of this call. Used in HEM to allow redefining a named query
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.hibernate.Session;
|
|||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* Represents a "memento" of a ProcedureCall
|
||||
* Represents a "memento" (disconnected, externalizable form) of a ProcedureCall
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -23,20 +23,20 @@
|
|||
*/
|
||||
package org.hibernate.procedure;
|
||||
|
||||
import org.hibernate.result.Result;
|
||||
import org.hibernate.result.Outputs;
|
||||
|
||||
/**
|
||||
* Specialization of the {@link Result} contract providing access to the stored procedure's registered
|
||||
* Specialization of the {@link org.hibernate.result.Outputs} contract providing access to the stored procedure's registered
|
||||
* output parameters.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ProcedureResult extends Result {
|
||||
public interface ProcedureOutputs extends Outputs {
|
||||
/**
|
||||
* Retrieve the value of an OUTPUT parameter by the parameter's registration memento.
|
||||
* <p/>
|
||||
* Should NOT be called for parameters registered as REF_CURSOR. REF_CURSOR parameters should be
|
||||
* accessed via the returns (see {@link #getNextReturn}
|
||||
* accessed via the returns (see {@link #getNextOutput}
|
||||
*
|
||||
* @param parameterRegistration The parameter's registration memento.
|
||||
*
|
||||
|
@ -53,6 +53,9 @@ public interface ProcedureResult extends Result {
|
|||
*
|
||||
* @return The output value.
|
||||
*
|
||||
* @throws ParameterStrategyException If the ProcedureCall is defined using positional parameters
|
||||
* @throws NoSuchParameterException If no parameter with that name exists
|
||||
*
|
||||
* @see ProcedureCall#registerParameter(String, Class, javax.persistence.ParameterMode)
|
||||
*/
|
||||
public Object getOutputParameterValue(String name);
|
||||
|
@ -64,6 +67,9 @@ public interface ProcedureResult extends Result {
|
|||
*
|
||||
* @return The output value.
|
||||
*
|
||||
* @throws ParameterStrategyException If the ProcedureCall is defined using named parameters
|
||||
* @throws NoSuchParameterException If no parameter with that position exists
|
||||
*
|
||||
* @see ProcedureCall#registerParameter(int, Class, javax.persistence.ParameterMode)
|
||||
*/
|
||||
public Object getOutputParameterValue(int position);
|
|
@ -50,10 +50,12 @@ import org.hibernate.internal.util.StringHelper;
|
|||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.procedure.NamedParametersNotSupportedException;
|
||||
import org.hibernate.procedure.NoSuchParameterException;
|
||||
import org.hibernate.procedure.ParameterRegistration;
|
||||
import org.hibernate.procedure.ParameterStrategyException;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.procedure.ProcedureCallMemento;
|
||||
import org.hibernate.procedure.ProcedureResult;
|
||||
import org.hibernate.procedure.ProcedureOutputs;
|
||||
import org.hibernate.result.spi.ResultContext;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
|
@ -75,7 +77,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
|||
|
||||
private Set<String> synchronizedQuerySpaces;
|
||||
|
||||
private ProcedureResultImpl outputs;
|
||||
private ProcedureOutputsImpl outputs;
|
||||
|
||||
/**
|
||||
* The no-returns form.
|
||||
|
@ -321,21 +323,22 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
|||
@Override
|
||||
public ParameterRegistrationImplementor getParameterRegistration(int position) {
|
||||
if ( parameterStrategy != ParameterStrategy.POSITIONAL ) {
|
||||
throw new IllegalArgumentException( "Positions were not used to register parameters with this stored procedure call" );
|
||||
throw new ParameterStrategyException(
|
||||
"Attempt to access positional parameter [" + position + "] but ProcedureCall using named parameters"
|
||||
);
|
||||
}
|
||||
try {
|
||||
return registeredParameters.get( position );
|
||||
for ( ParameterRegistrationImplementor parameter : registeredParameters ) {
|
||||
if ( position == parameter.getPosition() ) {
|
||||
return parameter;
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new QueryException( "Could not locate parameter registered using that position [" + position + "]" );
|
||||
}
|
||||
throw new NoSuchParameterException( "Could not locate parameter registered using that position [" + position + "]" );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> ParameterRegistration<T> registerParameter(String name, Class<T> type, ParameterMode mode) {
|
||||
final NamedParameterRegistration parameterRegistration
|
||||
= new NamedParameterRegistration( this, name, mode, type );
|
||||
final NamedParameterRegistration parameterRegistration = new NamedParameterRegistration( this, name, mode, type );
|
||||
registerParameter( parameterRegistration );
|
||||
return parameterRegistration;
|
||||
}
|
||||
|
@ -350,14 +353,14 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
|||
@Override
|
||||
public ParameterRegistrationImplementor getParameterRegistration(String name) {
|
||||
if ( parameterStrategy != ParameterStrategy.NAMED ) {
|
||||
throw new IllegalArgumentException( "Names were not used to register parameters with this stored procedure call" );
|
||||
throw new ParameterStrategyException( "Names were not used to register parameters with this stored procedure call" );
|
||||
}
|
||||
for ( ParameterRegistrationImplementor parameter : registeredParameters ) {
|
||||
if ( name.equals( parameter.getName() ) ) {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException( "Could not locate parameter registered under that name [" + name + "]" );
|
||||
throw new NoSuchParameterException( "Could not locate parameter registered under that name [" + name + "]" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -367,7 +370,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public ProcedureResult getResult() {
|
||||
public ProcedureOutputs getResult() {
|
||||
if ( outputs == null ) {
|
||||
outputs = buildOutputs();
|
||||
}
|
||||
|
@ -375,7 +378,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
|||
return outputs;
|
||||
}
|
||||
|
||||
private ProcedureResultImpl buildOutputs() {
|
||||
private ProcedureOutputsImpl buildOutputs() {
|
||||
// todo : going to need a very specialized Loader for this.
|
||||
// or, might be a good time to look at splitting Loader up into:
|
||||
// 1) building statement objects
|
||||
|
@ -385,6 +388,11 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
|||
// for now assume there are no resultClasses nor mappings defined..
|
||||
// TOTAL PROOF-OF-CONCEPT!!!!!!
|
||||
|
||||
// todo : how to identify calls which should be in the form `{? = call procName...}` ??? (note leading param marker)
|
||||
// more than likely this will need to be a method on the native API. I can see this as a trigger to
|
||||
// both: (1) add the `? = ` part and also (2) register a REFCURSOR parameter for DBs (Oracle, PGSQL) that
|
||||
// need it.
|
||||
|
||||
final StringBuilder buffer = new StringBuilder().append( "{call " )
|
||||
.append( procedureName )
|
||||
.append( "(" );
|
||||
|
@ -414,7 +422,7 @@ public class ProcedureCallImpl extends AbstractBasicQueryContractImpl implements
|
|||
i += parameter.getSqlTypes().length;
|
||||
}
|
||||
|
||||
return new ProcedureResultImpl( this, statement );
|
||||
return new ProcedureOutputsImpl( this, statement );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw getSession().getFactory().getSQLExceptionHelper().convert(
|
||||
|
|
|
@ -25,28 +25,26 @@ package org.hibernate.procedure.internal;
|
|||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.engine.jdbc.cursor.spi.RefCursorSupport;
|
||||
import org.hibernate.procedure.ParameterRegistration;
|
||||
import org.hibernate.procedure.ProcedureResult;
|
||||
import org.hibernate.result.Return;
|
||||
import org.hibernate.result.internal.ResultImpl;
|
||||
import org.hibernate.procedure.ProcedureOutputs;
|
||||
import org.hibernate.result.Output;
|
||||
import org.hibernate.result.internal.OutputsImpl;
|
||||
|
||||
/**
|
||||
* Implementation of ProcedureResult. Defines centralized access to all of the results of a procedure call.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ProcedureResultImpl extends ResultImpl implements ProcedureResult {
|
||||
public class ProcedureOutputsImpl extends OutputsImpl implements ProcedureOutputs {
|
||||
private final ProcedureCallImpl procedureCall;
|
||||
private final CallableStatement callableStatement;
|
||||
|
||||
private final ParameterRegistrationImplementor[] refCursorParameters;
|
||||
private int refCursorParamIndex;
|
||||
|
||||
ProcedureResultImpl(ProcedureCallImpl procedureCall, CallableStatement callableStatement) {
|
||||
ProcedureOutputsImpl(ProcedureCallImpl procedureCall, CallableStatement callableStatement) {
|
||||
super( procedureCall, callableStatement );
|
||||
this.procedureCall = procedureCall;
|
||||
this.callableStatement = callableStatement;
|
||||
|
@ -70,48 +68,45 @@ public class ProcedureResultImpl extends ResultImpl implements ProcedureResult {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected CurrentReturnDescriptor buildCurrentReturnDescriptor(boolean isResultSet, int updateCount) {
|
||||
return new ProcedureCurrentReturnDescriptor( isResultSet, updateCount, refCursorParamIndex );
|
||||
protected CurrentReturnState buildCurrentReturnState(boolean isResultSet, int updateCount) {
|
||||
return new ProcedureCurrentReturnState( isResultSet, updateCount, refCursorParamIndex );
|
||||
}
|
||||
|
||||
protected boolean hasMoreReturns(CurrentReturnDescriptor descriptor) {
|
||||
return super.hasMoreReturns( descriptor )
|
||||
|| ( (ProcedureCurrentReturnDescriptor) descriptor ).refCursorParamIndex < refCursorParameters.length;
|
||||
protected class ProcedureCurrentReturnState extends CurrentReturnState {
|
||||
private final int refCursorParamIndex;
|
||||
|
||||
private ProcedureCurrentReturnState(boolean isResultSet, int updateCount, int refCursorParamIndex) {
|
||||
super( isResultSet, updateCount );
|
||||
this.refCursorParamIndex = refCursorParamIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Return buildExtendedReturn(CurrentReturnDescriptor returnDescriptor) {
|
||||
this.refCursorParamIndex++;
|
||||
final int refCursorParamIndex = ( (ProcedureCurrentReturnDescriptor) returnDescriptor ).refCursorParamIndex;
|
||||
final ParameterRegistrationImplementor refCursorParam = refCursorParameters[refCursorParamIndex];
|
||||
public boolean indicatesMoreOutputs() {
|
||||
return super.indicatesMoreOutputs()
|
||||
|| ProcedureOutputsImpl.this.refCursorParamIndex < ProcedureOutputsImpl.this.refCursorParameters.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasExtendedReturns() {
|
||||
return refCursorParamIndex < refCursorParameters.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Output buildExtendedReturn() {
|
||||
ProcedureOutputsImpl.this.refCursorParamIndex++;
|
||||
final ParameterRegistrationImplementor refCursorParam = ProcedureOutputsImpl.this.refCursorParameters[refCursorParamIndex];
|
||||
ResultSet resultSet;
|
||||
if ( refCursorParam.getName() != null ) {
|
||||
resultSet = procedureCall.getSession().getFactory().getServiceRegistry()
|
||||
resultSet = ProcedureOutputsImpl.this.procedureCall.getSession().getFactory().getServiceRegistry()
|
||||
.getService( RefCursorSupport.class )
|
||||
.getResultSet( callableStatement, refCursorParam.getName() );
|
||||
.getResultSet( ProcedureOutputsImpl.this.callableStatement, refCursorParam.getName() );
|
||||
}
|
||||
else {
|
||||
resultSet = procedureCall.getSession().getFactory().getServiceRegistry()
|
||||
resultSet = ProcedureOutputsImpl.this.procedureCall.getSession().getFactory().getServiceRegistry()
|
||||
.getService( RefCursorSupport.class )
|
||||
.getResultSet( callableStatement, refCursorParam.getPosition() );
|
||||
.getResultSet( ProcedureOutputsImpl.this.callableStatement, refCursorParam.getPosition() );
|
||||
}
|
||||
return new ResultSetReturn( this, resultSet );
|
||||
}
|
||||
|
||||
protected JDBCException convert(SQLException e, String message) {
|
||||
return procedureCall.getSession().getFactory().getSQLExceptionHelper().convert(
|
||||
e,
|
||||
message,
|
||||
procedureCall.getProcedureName()
|
||||
);
|
||||
}
|
||||
|
||||
protected static class ProcedureCurrentReturnDescriptor extends CurrentReturnDescriptor {
|
||||
private final int refCursorParamIndex;
|
||||
|
||||
private ProcedureCurrentReturnDescriptor(boolean isResultSet, int updateCount, int refCursorParamIndex) {
|
||||
super( isResultSet, updateCount );
|
||||
this.refCursorParamIndex = refCursorParamIndex;
|
||||
return buildResultSetOutput( extractResults( resultSet ) );
|
||||
}
|
||||
}
|
||||
|
|
@ -32,4 +32,8 @@ public class NoMoreReturnsException extends HibernateException {
|
|||
public NoMoreReturnsException(String message) {
|
||||
super( message );
|
||||
}
|
||||
|
||||
public NoMoreReturnsException() {
|
||||
super( "Results have been exhausted" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,18 +24,18 @@
|
|||
package org.hibernate.result;
|
||||
|
||||
/**
|
||||
* Common contract for individual return objects which can be either results ({@link ResultSetReturn}) or update
|
||||
* counts ({@link UpdateCountReturn}).
|
||||
* Common contract for individual return objects which can be either results ({@link ResultSetOutput}) or update
|
||||
* counts ({@link UpdateCountOutput}).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Return {
|
||||
public interface Output {
|
||||
/**
|
||||
* Determine if this return is a result (castable to {@link ResultSetReturn}). The alternative is that it is
|
||||
* an update count (castable to {@link UpdateCountReturn}).
|
||||
* Determine if this return is a result (castable to {@link ResultSetOutput}). The alternative is that it is
|
||||
* an update count (castable to {@link UpdateCountOutput}).
|
||||
*
|
||||
* @return {@code true} indicates that {@code this} can be safely cast to {@link ResultSetReturn}), other wise
|
||||
* it can be cast to {@link UpdateCountReturn}.
|
||||
* @return {@code true} indicates that {@code this} can be safely cast to {@link ResultSetOutput}), other wise
|
||||
* it can be cast to {@link UpdateCountOutput}.
|
||||
*/
|
||||
public boolean isResultSet();
|
||||
}
|
|
@ -24,27 +24,32 @@
|
|||
package org.hibernate.result;
|
||||
|
||||
/**
|
||||
* Represents the result of executing a JDBC statement accounting for mixing of result sets and update counts hiding the
|
||||
* complexity (IMO) of how this is exposed in the JDBC API.
|
||||
*
|
||||
* A result is made up of group of {@link Return} objects, each representing a single result set or update count.
|
||||
* Represents the outputs of executing a JDBC statement accounting for mixing of result sets and update counts
|
||||
* hiding the complexity (IMO) of how this is exposed in the JDBC API.
|
||||
* <p/>
|
||||
* The outputs are exposed as a group of {@link Output} objects, each representing a single result set or update count.
|
||||
* Conceptually, Result presents those Returns as an iterator.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Result {
|
||||
public interface Outputs {
|
||||
/**
|
||||
* Are there any more returns associated with this result?
|
||||
* Retrieve the current Output object.
|
||||
*
|
||||
* @return {@code true} means there are more returns available via {@link #getNextReturn()}; {@code false}
|
||||
* indicates that calling {@link #getNextReturn()} will certainly result in an exception.
|
||||
* @return The current Output object. Can be {@code null}
|
||||
*/
|
||||
public boolean hasMoreReturns();
|
||||
public Output getCurrent();
|
||||
|
||||
/**
|
||||
* Retrieve the next return.
|
||||
* Go to the next Output object (if any), returning an indication of whether there was another (aka, will
|
||||
* the next call to {@link #getCurrent()} return {@code null}?
|
||||
*
|
||||
* @return The next return.
|
||||
* @return {@code true} if the next call to {@link #getCurrent()} will return a non-{@code null} value.
|
||||
*/
|
||||
public Return getNextReturn() throws NoMoreReturnsException;
|
||||
public boolean goToNext();
|
||||
|
||||
/**
|
||||
* Eagerly release any resources held by this Outputs.
|
||||
*/
|
||||
public void release();
|
||||
}
|
|
@ -30,7 +30,7 @@ import java.util.List;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ResultSetReturn extends Return {
|
||||
public interface ResultSetOutput extends Output {
|
||||
/**
|
||||
* Consume the underlying {@link java.sql.ResultSet} and return the resulting List.
|
||||
*
|
|
@ -28,7 +28,7 @@ package org.hibernate.result;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface UpdateCountReturn extends Return {
|
||||
public interface UpdateCountOutput extends Output {
|
||||
/**
|
||||
* Retrieve the associated update count
|
||||
*
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.result.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.loader.custom.CustomLoader;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.result.NoMoreReturnsException;
|
||||
import org.hibernate.result.Outputs;
|
||||
import org.hibernate.result.Output;
|
||||
import org.hibernate.result.spi.ResultContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class OutputsImpl implements Outputs {
|
||||
private static final Logger log = CoreLogging.logger( OutputsImpl.class );
|
||||
|
||||
private final ResultContext context;
|
||||
private final PreparedStatement jdbcStatement;
|
||||
private final CustomLoaderExtension loader;
|
||||
|
||||
private CurrentReturnState currentReturnState;
|
||||
|
||||
public OutputsImpl(ResultContext context, PreparedStatement jdbcStatement) {
|
||||
this.context = context;
|
||||
this.jdbcStatement = jdbcStatement;
|
||||
|
||||
// For now... but see the LoadPlan work; eventually this should just be a ResultSetProcessor.
|
||||
this.loader = buildSpecializedCustomLoader( context );
|
||||
|
||||
try {
|
||||
final boolean isResultSet = jdbcStatement.execute();
|
||||
currentReturnState = buildCurrentReturnState( isResultSet );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getMoreResults" );
|
||||
}
|
||||
}
|
||||
|
||||
private CurrentReturnState buildCurrentReturnState(boolean isResultSet) {
|
||||
int updateCount = -1;
|
||||
if ( ! isResultSet ) {
|
||||
try {
|
||||
updateCount = jdbcStatement.getUpdateCount();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getUpdateCount" );
|
||||
}
|
||||
}
|
||||
|
||||
return buildCurrentReturnState( isResultSet, updateCount );
|
||||
}
|
||||
|
||||
protected CurrentReturnState buildCurrentReturnState(boolean isResultSet, int updateCount) {
|
||||
return new CurrentReturnState( isResultSet, updateCount );
|
||||
}
|
||||
|
||||
protected JDBCException convert(SQLException e, String message) {
|
||||
return context.getSession().getFactory().getSQLExceptionHelper().convert(
|
||||
e,
|
||||
message,
|
||||
context.getSql()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Output getCurrent() {
|
||||
if ( currentReturnState == null ) {
|
||||
return null;
|
||||
}
|
||||
return currentReturnState.getOutput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean goToNext() {
|
||||
if ( currentReturnState == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( currentReturnState.indicatesMoreOutputs() )
|
||||
// prepare the next return state
|
||||
try {
|
||||
final boolean isResultSet = jdbcStatement.getMoreResults();
|
||||
currentReturnState = buildCurrentReturnState( isResultSet );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getMoreResults" );
|
||||
}
|
||||
|
||||
// and return
|
||||
return currentReturnState != null && currentReturnState.indicatesMoreOutputs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
try {
|
||||
jdbcStatement.close();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.debug( "Unable to close PreparedStatement", e );
|
||||
}
|
||||
}
|
||||
|
||||
private List extractCurrentResults() {
|
||||
try {
|
||||
return extractResults( jdbcStatement.getResultSet() );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getResultSet" );
|
||||
}
|
||||
}
|
||||
|
||||
protected List extractResults(ResultSet resultSet) {
|
||||
try {
|
||||
return loader.processResultSet( resultSet );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error extracting results from CallableStatement" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the information needed to interpret the current return within a result
|
||||
*/
|
||||
protected class CurrentReturnState {
|
||||
private final boolean isResultSet;
|
||||
private final int updateCount;
|
||||
|
||||
private Output rtn;
|
||||
|
||||
protected CurrentReturnState(boolean isResultSet, int updateCount) {
|
||||
this.isResultSet = isResultSet;
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
public boolean indicatesMoreOutputs() {
|
||||
return isResultSet() || getUpdateCount() >= 0;
|
||||
}
|
||||
|
||||
public boolean isResultSet() {
|
||||
return isResultSet;
|
||||
}
|
||||
|
||||
public int getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
public Output getOutput() {
|
||||
if ( rtn == null ) {
|
||||
rtn = buildOutput();
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
protected Output buildOutput() {
|
||||
if ( log.isDebugEnabled() ) {
|
||||
log.debugf(
|
||||
"Building Return [isResultSet=%s, updateCount=%s, extendedReturn=%s",
|
||||
isResultSet(),
|
||||
getUpdateCount(),
|
||||
hasExtendedReturns()
|
||||
);
|
||||
}
|
||||
// todo : temporary for tck testing...
|
||||
System.out.println(
|
||||
String.format(
|
||||
"Building Return [isResultSet=%s, updateCount=%s, extendedReturn=%s",
|
||||
isResultSet(),
|
||||
getUpdateCount(),
|
||||
hasExtendedReturns()
|
||||
)
|
||||
);
|
||||
|
||||
if ( isResultSet() ) {
|
||||
return buildResultSetOutput( extractCurrentResults() );
|
||||
}
|
||||
else if ( getUpdateCount() >= 0 ) {
|
||||
return buildUpdateCountOutput( updateCount );
|
||||
}
|
||||
else if ( hasExtendedReturns() ) {
|
||||
return buildExtendedReturn();
|
||||
}
|
||||
|
||||
throw new NoMoreReturnsException();
|
||||
}
|
||||
|
||||
// hooks for stored procedure (out param) processing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
protected Output buildResultSetOutput(List list) {
|
||||
return new ResultSetOutputImpl( list );
|
||||
}
|
||||
|
||||
protected Output buildUpdateCountOutput(int updateCount) {
|
||||
return new UpdateCountOutputImpl( updateCount );
|
||||
}
|
||||
|
||||
protected boolean hasExtendedReturns() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Output buildExtendedReturn() {
|
||||
throw new IllegalStateException( "State does not define extended returns" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Hooks into Hibernate's Loader hierarchy for ResultSet -> Object mapping
|
||||
|
||||
private static CustomLoaderExtension buildSpecializedCustomLoader(final ResultContext context) {
|
||||
// might be better to just manually construct the Return(s).. SQLQueryReturnProcessor does a lot of
|
||||
// work that is really unnecessary here.
|
||||
final SQLQueryReturnProcessor processor = new SQLQueryReturnProcessor(
|
||||
context.getQueryReturns(),
|
||||
context.getSession().getFactory()
|
||||
);
|
||||
processor.process();
|
||||
final List<org.hibernate.loader.custom.Return> customReturns = processor.generateCustomReturns( false );
|
||||
|
||||
CustomQuery customQuery = new CustomQuery() {
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return context.getSql();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getQuerySpaces() {
|
||||
return context.getSynchronizedQuerySpaces();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map getNamedParameterBindPoints() {
|
||||
// no named parameters in terms of embedded in the SQL string
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<org.hibernate.loader.custom.Return> getCustomQueryReturns() {
|
||||
return customReturns;
|
||||
}
|
||||
};
|
||||
|
||||
return new CustomLoaderExtension(
|
||||
customQuery,
|
||||
context.getQueryParameters(),
|
||||
context.getSession()
|
||||
);
|
||||
}
|
||||
|
||||
private static class CustomLoaderExtension extends CustomLoader {
|
||||
private QueryParameters queryParameters;
|
||||
private SessionImplementor session;
|
||||
|
||||
private boolean needsDiscovery = true;
|
||||
|
||||
public CustomLoaderExtension(
|
||||
CustomQuery customQuery,
|
||||
QueryParameters queryParameters,
|
||||
SessionImplementor session) {
|
||||
super( customQuery, session.getFactory() );
|
||||
this.queryParameters = queryParameters;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if ( needsDiscovery ) {
|
||||
super.autoDiscoverTypes( resultSet );
|
||||
// todo : EntityAliases discovery
|
||||
needsDiscovery = false;
|
||||
}
|
||||
return super.processResultSet(
|
||||
resultSet,
|
||||
queryParameters,
|
||||
session,
|
||||
true,
|
||||
null,
|
||||
Integer.MAX_VALUE,
|
||||
Collections.<AfterLoadAction>emptyList()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,293 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.result.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.loader.custom.CustomLoader;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.result.NoMoreReturnsException;
|
||||
import org.hibernate.result.Result;
|
||||
import org.hibernate.result.Return;
|
||||
import org.hibernate.result.spi.ResultContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ResultImpl implements Result {
|
||||
private final ResultContext context;
|
||||
private final PreparedStatement jdbcStatement;
|
||||
private final CustomLoaderExtension loader;
|
||||
|
||||
private CurrentReturnDescriptor currentReturnDescriptor;
|
||||
|
||||
private boolean executed = false;
|
||||
|
||||
public ResultImpl(ResultContext context, PreparedStatement jdbcStatement) {
|
||||
this.context = context;
|
||||
this.jdbcStatement = jdbcStatement;
|
||||
|
||||
// For now...
|
||||
this.loader = buildSpecializedCustomLoader( context );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreReturns() {
|
||||
if ( currentReturnDescriptor == null ) {
|
||||
final boolean isResultSet;
|
||||
|
||||
if ( executed ) {
|
||||
try {
|
||||
isResultSet = jdbcStatement.getMoreResults();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getMoreResults" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
isResultSet = jdbcStatement.execute();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.execute" );
|
||||
}
|
||||
executed = true;
|
||||
}
|
||||
|
||||
int updateCount = -1;
|
||||
if ( ! isResultSet ) {
|
||||
try {
|
||||
updateCount = jdbcStatement.getUpdateCount();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getUpdateCount" );
|
||||
}
|
||||
}
|
||||
|
||||
currentReturnDescriptor = buildCurrentReturnDescriptor( isResultSet, updateCount );
|
||||
}
|
||||
|
||||
return hasMoreReturns( currentReturnDescriptor );
|
||||
}
|
||||
|
||||
protected CurrentReturnDescriptor buildCurrentReturnDescriptor(boolean isResultSet, int updateCount) {
|
||||
return new CurrentReturnDescriptor( isResultSet, updateCount );
|
||||
}
|
||||
|
||||
protected boolean hasMoreReturns(CurrentReturnDescriptor descriptor) {
|
||||
return descriptor.isResultSet
|
||||
|| descriptor.updateCount >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Return getNextReturn() {
|
||||
if ( currentReturnDescriptor == null ) {
|
||||
if ( executed ) {
|
||||
throw new IllegalStateException( "Unexpected condition" );
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException( "hasMoreReturns() not called before getNextReturn()" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! hasMoreReturns( currentReturnDescriptor ) ) {
|
||||
throw new NoMoreReturnsException( "Results have been exhausted" );
|
||||
}
|
||||
|
||||
CurrentReturnDescriptor copyReturnDescriptor = currentReturnDescriptor;
|
||||
currentReturnDescriptor = null;
|
||||
|
||||
if ( copyReturnDescriptor.isResultSet ) {
|
||||
try {
|
||||
return new ResultSetReturn( this, jdbcStatement.getResultSet() );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw convert( e, "Error calling CallableStatement.getResultSet" );
|
||||
}
|
||||
}
|
||||
else if ( copyReturnDescriptor.updateCount >= 0 ) {
|
||||
return new UpdateCountReturn( this, copyReturnDescriptor.updateCount );
|
||||
}
|
||||
else {
|
||||
return buildExtendedReturn( copyReturnDescriptor );
|
||||
}
|
||||
}
|
||||
|
||||
protected Return buildExtendedReturn(CurrentReturnDescriptor copyReturnDescriptor) {
|
||||
throw new NoMoreReturnsException( "Results have been exhausted" );
|
||||
}
|
||||
|
||||
protected JDBCException convert(SQLException e, String message) {
|
||||
return context.getSession().getFactory().getSQLExceptionHelper().convert(
|
||||
e,
|
||||
message,
|
||||
context.getSql()
|
||||
);
|
||||
}
|
||||
|
||||
protected static class CurrentReturnDescriptor {
|
||||
private final boolean isResultSet;
|
||||
private final int updateCount;
|
||||
|
||||
protected CurrentReturnDescriptor(boolean isResultSet, int updateCount) {
|
||||
this.isResultSet = isResultSet;
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ResultSetReturn implements org.hibernate.result.ResultSetReturn {
|
||||
private final ResultImpl storedProcedureOutputs;
|
||||
private final ResultSet resultSet;
|
||||
|
||||
public ResultSetReturn(ResultImpl storedProcedureOutputs, ResultSet resultSet) {
|
||||
this.storedProcedureOutputs = storedProcedureOutputs;
|
||||
this.resultSet = resultSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResultSet() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List getResultList() {
|
||||
try {
|
||||
return storedProcedureOutputs.loader.processResultSet( resultSet );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw storedProcedureOutputs.convert( e, "Error calling ResultSet.next" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSingleResult() {
|
||||
List results = getResultList();
|
||||
if ( results == null || results.isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return results.get( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static class UpdateCountReturn implements org.hibernate.result.UpdateCountReturn {
|
||||
private final ResultImpl result;
|
||||
private final int updateCount;
|
||||
|
||||
public UpdateCountReturn(ResultImpl result, int updateCount) {
|
||||
this.result = result;
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResultSet() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static CustomLoaderExtension buildSpecializedCustomLoader(final ResultContext context) {
|
||||
final SQLQueryReturnProcessor processor = new SQLQueryReturnProcessor(
|
||||
context.getQueryReturns(),
|
||||
context.getSession().getFactory()
|
||||
);
|
||||
processor.process();
|
||||
final List<org.hibernate.loader.custom.Return> customReturns = processor.generateCustomReturns( false );
|
||||
|
||||
CustomQuery customQuery = new CustomQuery() {
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return context.getSql();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getQuerySpaces() {
|
||||
return context.getSynchronizedQuerySpaces();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map getNamedParameterBindPoints() {
|
||||
// no named parameters in terms of embedded in the SQL string
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<org.hibernate.loader.custom.Return> getCustomQueryReturns() {
|
||||
return customReturns;
|
||||
}
|
||||
};
|
||||
|
||||
return new CustomLoaderExtension(
|
||||
customQuery,
|
||||
context.getQueryParameters(),
|
||||
context.getSession()
|
||||
);
|
||||
}
|
||||
|
||||
private static class CustomLoaderExtension extends CustomLoader {
|
||||
private QueryParameters queryParameters;
|
||||
private SessionImplementor session;
|
||||
|
||||
public CustomLoaderExtension(
|
||||
CustomQuery customQuery,
|
||||
QueryParameters queryParameters,
|
||||
SessionImplementor session) {
|
||||
super( customQuery, session.getFactory() );
|
||||
this.queryParameters = queryParameters;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
super.autoDiscoverTypes( resultSet );
|
||||
return super.processResultSet(
|
||||
resultSet,
|
||||
queryParameters,
|
||||
session,
|
||||
true,
|
||||
null,
|
||||
Integer.MAX_VALUE,
|
||||
Collections.<AfterLoadAction>emptyList()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.result.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.result.ResultSetOutput;
|
||||
|
||||
/**
|
||||
* Implementation of ResultSetOutput
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class ResultSetOutputImpl implements ResultSetOutput {
|
||||
private final List results;
|
||||
|
||||
public ResultSetOutputImpl(List results) {
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResultSet() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List getResultList() {
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSingleResult() {
|
||||
final List results = getResultList();
|
||||
if ( results == null || results.isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return results.get( 0 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.result.internal;
|
||||
|
||||
import org.hibernate.result.UpdateCountOutput;
|
||||
|
||||
/**
|
||||
* Implementation of UpdateCountOutput
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class UpdateCountOutputImpl implements UpdateCountOutput {
|
||||
private final int updateCount;
|
||||
|
||||
public UpdateCountOutputImpl(int updateCount) {
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResultSet() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestMethod;
|
|||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.hibernate.type.SerializationException;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
@ -66,7 +67,11 @@ public class SessionFactorySerializationTest extends BaseCoreFunctionalTestMetho
|
|||
|
||||
SessionFactory factory2 = (SessionFactory) SerializationHelper.clone( factory );
|
||||
assertSame( factory, factory2 );
|
||||
|
||||
SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", NAME, false, null );
|
||||
factory.close();
|
||||
|
||||
assertFalse( SessionFactoryRegistry.INSTANCE.hasRegistrations() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -82,17 +87,20 @@ public class SessionFactorySerializationTest extends BaseCoreFunctionalTestMetho
|
|||
StringRefAddr refAddr = (StringRefAddr) reference.get( "uuid" );
|
||||
String uuid = (String) refAddr.getContent();
|
||||
// deregister under this uuid...
|
||||
SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, NAME, false, null );
|
||||
SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, null, false, null );
|
||||
// and then register under a different uuid...
|
||||
SessionFactoryRegistry.INSTANCE.addSessionFactory( "some-other-uuid", NAME, false, factory, null );
|
||||
SessionFactoryRegistry.INSTANCE.addSessionFactory( "some-other-uuid", null, false, factory, null );
|
||||
|
||||
try {
|
||||
SerializationHelper.clone( factory );
|
||||
fail( "Expecting an error" );
|
||||
}
|
||||
catch ( SerializationException expected ) {
|
||||
|
||||
}
|
||||
|
||||
SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", null, false, null );
|
||||
factory.close();
|
||||
|
||||
assertFalse( SessionFactoryRegistry.INSTANCE.hasRegistrations() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,12 +56,11 @@ public class EmbeddableIntegratorTest extends BaseUnitTestCase {
|
|||
*/
|
||||
@Test(expected = GenericJDBCException.class)
|
||||
public void testWithoutIntegrator() {
|
||||
|
||||
ServiceRegistry reg = new StandardServiceRegistryBuilder( new BootstrapServiceRegistryImpl() ).build();
|
||||
|
||||
SessionFactory sf = new Configuration().addAnnotatedClass( Investor.class )
|
||||
.setProperty( "hibernate.hbm2ddl.auto", "create-drop" ).buildSessionFactory( reg );
|
||||
|
||||
try {
|
||||
Session sess = sf.openSession();
|
||||
Investor myInv = getInvestor();
|
||||
myInv.setId( 1L );
|
||||
|
@ -74,18 +73,22 @@ public class EmbeddableIntegratorTest extends BaseUnitTestCase {
|
|||
assertEquals( new BigDecimal( "100" ), inv.getInvestments().get( 0 ).getAmount().getAmount() );
|
||||
|
||||
sess.close();
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
StandardServiceRegistryBuilder.destroy( reg );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithIntegrator() {
|
||||
StandardServiceRegistry reg = new StandardServiceRegistryBuilder( new BootstrapServiceRegistryBuilder().with(
|
||||
new InvestorIntegrator() ).build() ).build();
|
||||
|
||||
StandardServiceRegistry reg = new StandardServiceRegistryBuilder(
|
||||
new BootstrapServiceRegistryBuilder().with( new InvestorIntegrator() ).build()
|
||||
).build();
|
||||
SessionFactory sf = new Configuration().addAnnotatedClass( Investor.class )
|
||||
.setProperty( "hibernate.hbm2ddl.auto", "create-drop" ).buildSessionFactory( reg );
|
||||
|
||||
try {
|
||||
Session sess = sf.openSession();
|
||||
Investor myInv = getInvestor();
|
||||
myInv.setId( 2L );
|
||||
|
@ -98,9 +101,12 @@ public class EmbeddableIntegratorTest extends BaseUnitTestCase {
|
|||
assertEquals( new BigDecimal( "100" ), inv.getInvestments().get( 0 ).getAmount().getAmount() );
|
||||
|
||||
sess.close();
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
StandardServiceRegistryBuilder.destroy( reg );
|
||||
}
|
||||
}
|
||||
|
||||
private Investor getInvestor() {
|
||||
Investor i = new Investor();
|
||||
|
|
|
@ -70,6 +70,9 @@ public class OrmVersion1SupportedTest extends BaseCoreFunctionalTestCase {
|
|||
s.close();
|
||||
|
||||
assertEquals( "HHH00196 should not be called", 0, BytemanHelper.getAndResetInvocationCount() );
|
||||
|
||||
// which means we also need to close it manually
|
||||
releaseSessionFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,7 +25,6 @@ package org.hibernate.test.cfg.cache;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
@ -44,7 +43,8 @@ public class CacheConfigurationTest extends BaseUnitTestCase {
|
|||
if(isMetadataUsed()){
|
||||
throw new IllegalStateException( "what should we do here " );
|
||||
}
|
||||
// we only care if the SF builds successfully.
|
||||
Configuration cfg = new Configuration().configure(CFG_XML);
|
||||
SessionFactory sessionFactory = cfg.buildSessionFactory();
|
||||
cfg.buildSessionFactory().close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,14 +37,15 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.CriteriaImpl;
|
||||
import org.hibernate.loader.criteria.CriteriaQueryTranslator;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CriterionTest extends BaseCoreFunctionalTestCase {
|
||||
public class CriterionTest extends BaseUnitTestCase {
|
||||
@Test
|
||||
public void testIlikeRendering() {
|
||||
SessionFactory sf = new Configuration()
|
||||
|
@ -52,6 +53,7 @@ public class CriterionTest extends BaseCoreFunctionalTestCase {
|
|||
.setProperty( AvailableSettings.DIALECT, IlikeSupportingDialect.class.getName() )
|
||||
.setProperty( Environment.HBM2DDL_AUTO, "create-drop" )
|
||||
.buildSessionFactory();
|
||||
try {
|
||||
final Criteria criteria = sf.openSession().createCriteria( IrrelevantEntity.class );
|
||||
final CriteriaQueryTranslator translator = new CriteriaQueryTranslator(
|
||||
(SessionFactoryImplementor) sf,
|
||||
|
@ -63,6 +65,10 @@ public class CriterionTest extends BaseCoreFunctionalTestCase {
|
|||
final String ilikeExpressionSqlFragment = ilikeExpression.toSqlString( criteria, translator );
|
||||
assertEquals( "a.name insensitiveLike ?", ilikeExpressionSqlFragment );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIlikeMimicing() {
|
||||
|
@ -71,6 +77,7 @@ public class CriterionTest extends BaseCoreFunctionalTestCase {
|
|||
.setProperty( AvailableSettings.DIALECT, NonIlikeSupportingDialect.class.getName() )
|
||||
.setProperty( Environment.HBM2DDL_AUTO, "create-drop" )
|
||||
.buildSessionFactory();
|
||||
try {
|
||||
final Criteria criteria = sf.openSession().createCriteria( IrrelevantEntity.class );
|
||||
final CriteriaQueryTranslator translator = new CriteriaQueryTranslator(
|
||||
(SessionFactoryImplementor) sf,
|
||||
|
@ -82,6 +89,10 @@ public class CriterionTest extends BaseCoreFunctionalTestCase {
|
|||
final String ilikeExpressionSqlFragment = ilikeExpression.toSqlString( criteria, translator );
|
||||
assertEquals( "lowLowLow(a.name) like ?", ilikeExpressionSqlFragment );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static class IlikeSupportingDialect extends Dialect {
|
||||
@Override
|
||||
|
|
|
@ -21,15 +21,19 @@
|
|||
package org.hibernate.test.mapping;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.metamodel.spi.relational.TableSpecification;
|
||||
import org.hibernate.test.util.SchemaUtil;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Column aliases utilize {@link Table#getUniqueInteger()} for naming. The
|
||||
* unique integer used to be statically generated by the Table class, meaning
|
||||
|
@ -41,18 +45,64 @@ import static org.junit.Assert.assertTrue;
|
|||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-2448" )
|
||||
public class AliasTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
/**
|
||||
* Column aliases utilize {@link Table#getUniqueInteger()} for naming. The unique integer used to be statically
|
||||
* generated by the Table class, meaning it was dependent on mapping order. HHH-2448 made the alias names
|
||||
* deterministic by having Configuration determine the unique integers on its second pass over the Tables tree map.
|
||||
* AliasTest and {@link MappingReorderedAliasTest} ensure that the unique integers are the same, regardless of
|
||||
* mapping ordering.
|
||||
*/
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-2448" )
|
||||
public void testAliasOrdering() {
|
||||
TableSpecification table1 = SchemaUtil.getTable( "Table1", metadata() );
|
||||
TableSpecification table2 = SchemaUtil.getTable( "Table2", metadata() );
|
||||
assertTrue( table1.getTableNumber() < table2.getTableNumber() );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-8371" )
|
||||
public final void testUnderscoreInColumnName() throws Throwable {
|
||||
final Session s = openSession();
|
||||
s.getTransaction().begin();
|
||||
|
||||
UserEntity user = new UserEntity();
|
||||
user.setName( "foo" );
|
||||
s.persist(user);
|
||||
final ConfEntity conf = new ConfEntity();
|
||||
conf.setConfKey("counter");
|
||||
conf.setConfValue("3");
|
||||
final UserConfEntity uc = new UserConfEntity();
|
||||
uc.setUser(user);
|
||||
uc.setConf(conf);
|
||||
conf.getUserConf().add(uc);
|
||||
s.persist(conf);
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
s.getTransaction().begin();
|
||||
user = (UserEntity) s.get(UserEntity.class, user.getId());
|
||||
|
||||
try {
|
||||
s.flush();
|
||||
}
|
||||
catch ( HibernateException e ) {
|
||||
// original issue from HHH-8371
|
||||
fail( "The explicit column name's underscore(s) were not considered during alias creation." );
|
||||
}
|
||||
|
||||
assertNotNull( user );
|
||||
assertEquals( user.getName(), "foo" );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Table1.class, Table2.class };
|
||||
return new Class<?>[] { Table1.class, Table2.class, ConfEntity.class, UserConfEntity.class, UserEntity.class };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package org.hibernate.test.mapping;
|
||||
|
||||
import static javax.persistence.CascadeType.ALL;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "CONF")
|
||||
@IdClass(ConfId.class)
|
||||
public class ConfEntity implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -5089484717715507169L;
|
||||
|
||||
@Id
|
||||
@Column(name = "confKey")
|
||||
private String confKey;
|
||||
|
||||
@Id
|
||||
@Column(name = "confValue")
|
||||
private String confValue;
|
||||
|
||||
@OneToMany(mappedBy="conf", cascade = ALL, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
private Set<UserConfEntity> userConf = new HashSet<UserConfEntity>();
|
||||
|
||||
public String getConfKey() {
|
||||
return confKey;
|
||||
}
|
||||
|
||||
public void setConfKey(String confKey) {
|
||||
this.confKey = confKey;
|
||||
}
|
||||
|
||||
public String getConfValue() {
|
||||
return confValue;
|
||||
}
|
||||
|
||||
public void setConfValue(String confValue) {
|
||||
this.confValue = confValue;
|
||||
}
|
||||
|
||||
public Set<UserConfEntity> getUserConf() {
|
||||
return userConf;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package org.hibernate.test.mapping;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ConfId implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -6722022851594514199L;
|
||||
|
||||
private String confKey;
|
||||
|
||||
private String confValue;
|
||||
|
||||
public ConfId(){
|
||||
}
|
||||
|
||||
public ConfId(String confKey, String confValue) {
|
||||
this.confKey = confKey;
|
||||
this.confValue = confValue;
|
||||
}
|
||||
|
||||
public String getConfKey() {
|
||||
return confKey;
|
||||
}
|
||||
|
||||
public void setConfKey(String confKey) {
|
||||
this.confKey = confKey;
|
||||
}
|
||||
|
||||
public String getConfValue() {
|
||||
return confValue;
|
||||
}
|
||||
|
||||
public void setConfValue(String confValue) {
|
||||
this.confValue = confValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((confKey == null) ? 0 : confKey.hashCode());
|
||||
result = prime * result + ((confValue == null) ? 0 : confValue.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ConfId other = (ConfId) obj;
|
||||
if (confKey == null) {
|
||||
if (other.confKey != null)
|
||||
return false;
|
||||
} else if (!confKey.equals(other.confKey))
|
||||
return false;
|
||||
else if (confValue == null) {
|
||||
if (other.confValue != null)
|
||||
return false;
|
||||
} else if (!confValue.equals(other.confValue))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,6 @@ public class MappingReorderedAliasTest extends AliasTest {
|
|||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Table2.class, Table1.class };
|
||||
return new Class<?>[] { Table2.class, Table1.class, ConfEntity.class, UserConfEntity.class, UserEntity.class };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.hibernate.test.mapping;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "USER_CONFS")
|
||||
@IdClass(UserConfId.class)
|
||||
public class UserConfEntity implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = 9153314908821604322L;
|
||||
|
||||
@Id
|
||||
@ManyToOne
|
||||
@JoinColumn(name="user_id")
|
||||
private UserEntity user;
|
||||
|
||||
@Id
|
||||
@ManyToOne
|
||||
@JoinColumns({
|
||||
@JoinColumn(name="cnf_key", referencedColumnName="confKey"),
|
||||
@JoinColumn(name="cnf_value", referencedColumnName="confValue")})
|
||||
private ConfEntity conf;
|
||||
|
||||
public ConfEntity getConf() {
|
||||
return conf;
|
||||
}
|
||||
|
||||
public void setConf(ConfEntity conf) {
|
||||
this.conf = conf;
|
||||
}
|
||||
|
||||
|
||||
public UserEntity getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(UserEntity user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package org.hibernate.test.mapping;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
|
||||
public class UserConfId implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -161134972658451944L;
|
||||
|
||||
private Long user;
|
||||
|
||||
private ConfId conf;
|
||||
|
||||
public UserConfId(){
|
||||
}
|
||||
|
||||
public UserConfId(Long user, ConfId conf) {
|
||||
this.user = user;
|
||||
this.conf = conf;
|
||||
}
|
||||
|
||||
public Long getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(Long user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
|
||||
public ConfId getConf() {
|
||||
return conf;
|
||||
}
|
||||
|
||||
public void setConf(ConfId conf) {
|
||||
this.conf = conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((conf == null) ? 0 : conf.hashCode());
|
||||
result = prime * result + ((user == null) ? 0 : user.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
UserConfId other = (UserConfId) obj;
|
||||
if (conf == null) {
|
||||
if (other.conf != null)
|
||||
return false;
|
||||
} else if (!conf.equals(other.conf))
|
||||
return false;
|
||||
if (user == null) {
|
||||
if (other.user != null)
|
||||
return false;
|
||||
} else if (!user.equals(other.user))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package org.hibernate.test.mapping;
|
||||
|
||||
import static javax.persistence.CascadeType.ALL;
|
||||
import static javax.persistence.FetchType.EAGER;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderColumn;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "USER")
|
||||
public class UserEntity implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Column(name = "user_id")
|
||||
private Long id;
|
||||
|
||||
@OrderColumn(name = "cnf_order")
|
||||
@OneToMany(mappedBy="user", fetch = EAGER, cascade = ALL, orphanRemoval = true)
|
||||
private Set<UserConfEntity> confs = new HashSet<UserConfEntity>();
|
||||
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Set<UserConfEntity> getConfs() {
|
||||
return confs;
|
||||
}
|
||||
|
||||
public void setConfs(Set<UserConfEntity> confs) {
|
||||
this.confs = confs;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -30,24 +30,20 @@ import org.junit.Test;
|
|||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
import org.hibernate.mapping.AuxiliaryDatabaseObject;
|
||||
import org.hibernate.metamodel.spi.MetadataImplementor;
|
||||
import org.hibernate.metamodel.spi.relational.Database;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.procedure.ProcedureResult;
|
||||
import org.hibernate.result.ResultSetReturn;
|
||||
import org.hibernate.result.Return;
|
||||
import org.hibernate.procedure.ProcedureOutputs;
|
||||
import org.hibernate.result.ResultSetOutput;
|
||||
import org.hibernate.result.Output;
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.junit4.ExtraAssertions;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
|
@ -305,13 +301,11 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
|||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
|
||||
ProcedureCall query = session.createStoredProcedureCall( "user");
|
||||
ProcedureResult procedureResult = query.getResult();
|
||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
||||
Return nextReturn = procedureResult.getNextReturn();
|
||||
assertNotNull( nextReturn );
|
||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||
ProcedureCall procedureCall = session.createStoredProcedureCall( "user");
|
||||
ProcedureOutputs procedureOutputs = procedureCall.getResult();
|
||||
Output currentOutput = procedureOutputs.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
String name = (String) resultSetReturn.getSingleResult();
|
||||
assertEquals( "SA", name );
|
||||
|
||||
|
@ -325,14 +319,12 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
|||
session.beginTransaction();
|
||||
|
||||
ProcedureCall query = session.createStoredProcedureCall( "findOneUser" );
|
||||
ProcedureResult procedureResult = query.getResult();
|
||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
||||
Return nextReturn = procedureResult.getNextReturn();
|
||||
assertNotNull( nextReturn );
|
||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||
ProcedureOutputs procedureResult = query.getResult();
|
||||
Output currentOutput = procedureResult.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
Object result = resultSetReturn.getSingleResult();
|
||||
ExtraAssertions.assertTyping( Object[].class, result );
|
||||
assertTyping( Object[].class, result );
|
||||
String name = (String) ( (Object[]) result )[1];
|
||||
assertEquals( "Steve", name );
|
||||
|
||||
|
@ -346,17 +338,15 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
|||
session.beginTransaction();
|
||||
|
||||
ProcedureCall query = session.createStoredProcedureCall( "findUsers" );
|
||||
ProcedureResult procedureResult = query.getResult();
|
||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
||||
Return nextReturn = procedureResult.getNextReturn();
|
||||
assertNotNull( nextReturn );
|
||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||
ProcedureOutputs procedureResult = query.getResult();
|
||||
Output currentOutput = procedureResult.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
List results = resultSetReturn.getResultList();
|
||||
assertEquals( 3, results.size() );
|
||||
|
||||
for ( Object result : results ) {
|
||||
ExtraAssertions.assertTyping( Object[].class, result );
|
||||
assertTyping( Object[].class, result );
|
||||
Integer id = (Integer) ( (Object[]) result )[0];
|
||||
String name = (String) ( (Object[]) result )[1];
|
||||
if ( id.equals( 1 ) ) {
|
||||
|
@ -385,16 +375,14 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
|||
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||
query.registerParameter( "start", Integer.class, ParameterMode.IN ).bindValue( 1 );
|
||||
query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||
ProcedureResult procedureResult = query.getResult();
|
||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
||||
Return nextReturn = procedureResult.getNextReturn();
|
||||
assertNotNull( nextReturn );
|
||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||
ProcedureOutputs procedureResult = query.getResult();
|
||||
Output currentOutput = procedureResult.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
List results = resultSetReturn.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
Object result = results.get( 0 );
|
||||
ExtraAssertions.assertTyping( Object[].class, result );
|
||||
assertTyping( Object[].class, result );
|
||||
Integer id = (Integer) ( (Object[]) result )[0];
|
||||
String name = (String) ( (Object[]) result )[1];
|
||||
assertEquals( 1, (int) id );
|
||||
|
@ -412,16 +400,14 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
|||
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||
query.registerParameter( 1, Integer.class, ParameterMode.IN ).bindValue( 1 );
|
||||
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||
ProcedureResult procedureResult = query.getResult();
|
||||
assertTrue( "Checking ProcedureResult has more returns", procedureResult.hasMoreReturns() );
|
||||
Return nextReturn = procedureResult.getNextReturn();
|
||||
assertNotNull( nextReturn );
|
||||
ExtraAssertions.assertClassAssignability( ResultSetReturn.class, nextReturn.getClass() );
|
||||
ResultSetReturn resultSetReturn = (ResultSetReturn) nextReturn;
|
||||
ProcedureOutputs procedureResult = query.getResult();
|
||||
Output currentOutput = procedureResult.getCurrent();
|
||||
assertNotNull( currentOutput );
|
||||
ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
|
||||
List results = resultSetReturn.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
Object result = results.get( 0 );
|
||||
ExtraAssertions.assertTyping( Object[].class, result );
|
||||
assertTyping( Object[].class, result );
|
||||
Integer id = (Integer) ( (Object[]) result )[0];
|
||||
String name = (String) ( (Object[]) result )[1];
|
||||
assertEquals( 1, (int) id );
|
||||
|
@ -443,9 +429,8 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
|||
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||
query.registerParameter( 1, Integer.class, ParameterMode.IN );
|
||||
query.registerParameter( 2, Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||
ProcedureResult procedureResult = query.getResult();
|
||||
try {
|
||||
procedureResult.hasMoreReturns();
|
||||
query.getResult();
|
||||
fail( "Expecting failure due to missing parameter bind" );
|
||||
}
|
||||
catch (JDBCException expected) {
|
||||
|
@ -456,9 +441,8 @@ public class StoredProcedureTest extends BaseCoreFunctionalTestCase {
|
|||
ProcedureCall query = session.createStoredProcedureCall( "findUserRange" );
|
||||
query.registerParameter( "start", Integer.class, ParameterMode.IN );
|
||||
query.registerParameter( "end", Integer.class, ParameterMode.IN ).bindValue( 2 );
|
||||
ProcedureResult procedureResult = query.getResult();
|
||||
try {
|
||||
procedureResult.hasMoreReturns();
|
||||
query.getResult();
|
||||
fail( "Expecting failure due to missing parameter bind" );
|
||||
}
|
||||
catch (JDBCException expected) {
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.hibernate.Session;
|
|||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
|
@ -58,56 +59,59 @@ public class StatsTest extends BaseCoreFunctionalTestCase {
|
|||
public String[] getMappings() {
|
||||
return new String[] { "stats/Continent.hbm.xml" };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
|
||||
protected void initialize(){
|
||||
super.initialize();
|
||||
getTestConfiguration().getProperties().setProperty( Environment.GENERATE_STATISTICS, "true" );
|
||||
getTestConfiguration().getProperties().setProperty( AvailableSettings.HBM2DDL_AUTO, "create");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareStandardServiceRegistryBuilder(StandardServiceRegistryBuilder serviceRegistryBuilder) {
|
||||
serviceRegistryBuilder.applySetting( Environment.GENERATE_STATISTICS, "true" );
|
||||
protected boolean createSchema() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings( {"UnusedAssignment"})
|
||||
public void testCollectionFetchVsLoad() throws Exception {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
stats.clear();
|
||||
SessionFactory sf =sessionFactory();
|
||||
|
||||
Session s = openSession();
|
||||
Session s = sf.openSession();
|
||||
Transaction tx = s.beginTransaction();
|
||||
Continent europe = fillDb(s);
|
||||
tx.commit();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
assertEquals(0, stats.getCollectionLoadCount() );
|
||||
assertEquals(0, stats.getCollectionFetchCount() );
|
||||
assertEquals(0, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals(0, sf.getStatistics().getCollectionFetchCount() );
|
||||
Continent europe2 = (Continent) s.get( Continent.class, europe.getId() );
|
||||
assertEquals("Lazy true: no collection should be loaded", 0, stats.getCollectionLoadCount() );
|
||||
assertEquals( 0, stats.getCollectionFetchCount() );
|
||||
assertEquals("Lazy true: no collection should be loaded", 0, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals( 0, sf.getStatistics().getCollectionFetchCount() );
|
||||
europe2.getCountries().size();
|
||||
assertEquals( 1, stats.getCollectionLoadCount() );
|
||||
assertEquals("Explicit fetch of the collection state", 1, stats.getCollectionFetchCount() );
|
||||
assertEquals( 1, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals("Explicit fetch of the collection state", 1, sf.getStatistics().getCollectionFetchCount() );
|
||||
tx.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
sf.getStatistics().clear();
|
||||
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
stats.clear();
|
||||
europe = fillDb(s);
|
||||
tx.commit();
|
||||
s.clear();
|
||||
tx = s.beginTransaction();
|
||||
assertEquals( 0, stats.getCollectionLoadCount() );
|
||||
assertEquals( 0, stats.getCollectionFetchCount() );
|
||||
assertEquals( 0, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals( 0, sf.getStatistics().getCollectionFetchCount() );
|
||||
europe2 = (Continent) s.createQuery(
|
||||
"from " + Continent.class.getName() + " a join fetch a.countries where a.id = " + europe.getId()
|
||||
).uniqueResult();
|
||||
assertEquals( 1, stats.getCollectionLoadCount() );
|
||||
assertEquals( "collection should be loaded in the same query as its parent", 0, stats.getCollectionFetchCount() );
|
||||
assertEquals( 1, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals( "collection should be loaded in the same query as its parent", 0, sf.getStatistics().getCollectionFetchCount() );
|
||||
tx.commit();
|
||||
s.close();
|
||||
|
||||
|
@ -115,21 +119,23 @@ public class StatsTest extends BaseCoreFunctionalTestCase {
|
|||
PluralAttributeBinding coll = SchemaUtil.getCollection( Continent.class, "countries", metadata() );
|
||||
coll.setFetchStyle( FetchStyle.JOIN );
|
||||
coll.setFetchTiming( FetchTiming.IMMEDIATE );
|
||||
SessionFactory sf = metadata().getSessionFactoryBuilder().build();
|
||||
stats = sf.getStatistics();
|
||||
sf = metadata().getSessionFactoryBuilder().build();
|
||||
Statistics stats = sf.getStatistics();
|
||||
stats.clear();
|
||||
stats.setStatisticsEnabled(true);
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
europe = fillDb(s);
|
||||
tx.commit();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
assertEquals( 0, stats.getCollectionLoadCount() );
|
||||
assertEquals( 0, stats.getCollectionFetchCount() );
|
||||
assertEquals( 0, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals( 0, sf.getStatistics().getCollectionFetchCount() );
|
||||
europe2 = (Continent) s.get( Continent.class, europe.getId() );
|
||||
assertEquals( 1, stats.getCollectionLoadCount() );
|
||||
assertEquals( "Should do direct load, not indirect second load when lazy false and JOIN", 0, stats.getCollectionFetchCount() );
|
||||
assertEquals( 1, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals( "Should do direct load, not indirect second load when lazy false and JOIN", 0, sf.getStatistics().getCollectionFetchCount() );
|
||||
tx.commit();
|
||||
s.close();
|
||||
sf.close();
|
||||
|
@ -146,42 +152,45 @@ public class StatsTest extends BaseCoreFunctionalTestCase {
|
|||
tx = s.beginTransaction();
|
||||
europe = fillDb(s);
|
||||
tx.commit();
|
||||
s.clear();
|
||||
s.close();
|
||||
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
assertEquals( 0, stats.getCollectionLoadCount() );
|
||||
assertEquals( 0, stats.getCollectionFetchCount() );
|
||||
assertEquals( 0, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals( 0, sf.getStatistics().getCollectionFetchCount() );
|
||||
europe2 = (Continent) s.get( Continent.class, europe.getId() );
|
||||
assertEquals( 1, stats.getCollectionLoadCount() );
|
||||
assertEquals( "Should do explicit collection load, not part of the first one", 1, stats.getCollectionFetchCount() );
|
||||
assertEquals( 1, sf.getStatistics().getCollectionLoadCount() );
|
||||
assertEquals( "Should do explicit collection load, not part of the first one", 1, sf.getStatistics().getCollectionFetchCount() );
|
||||
for ( Object o : europe2.getCountries() ) {
|
||||
s.delete( o );
|
||||
}
|
||||
cleanDb( s );
|
||||
tx.commit();
|
||||
s.close();
|
||||
|
||||
sf.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryStatGathering() {
|
||||
Statistics stats = sessionFactory().getStatistics();
|
||||
stats.clear();
|
||||
SessionFactory sf = sessionFactory();
|
||||
|
||||
Session s = openSession();
|
||||
Session s = sf.openSession();
|
||||
Transaction tx = s.beginTransaction();
|
||||
fillDb(s);
|
||||
tx.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
final String continents = "from Continent";
|
||||
int results = s.createQuery( continents ).list().size();
|
||||
QueryStatistics continentStats = stats.getQueryStatistics( continents );
|
||||
QueryStatistics continentStats = sf.getStatistics().getQueryStatistics( continents );
|
||||
assertNotNull( "stats were null", continentStats );
|
||||
assertEquals( "unexpected execution count", 1, continentStats.getExecutionCount() );
|
||||
assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() );
|
||||
long maxTime = continentStats.getExecutionMaxTime();
|
||||
assertEquals( maxTime, stats.getQueryExecutionMaxTime() );
|
||||
assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() );
|
||||
// assertEquals( continents, stats.getQueryExecutionMaxTimeQueryString() );
|
||||
|
||||
Iterator itr = s.createQuery( continents ).iterate();
|
||||
|
@ -206,44 +215,47 @@ public class StatsTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
// explicitly check that statistics for "split queries" get collected
|
||||
// under the original query
|
||||
stats.clear();
|
||||
s = openSession();
|
||||
sf.getStatistics().clear();
|
||||
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
final String localities = "from Locality";
|
||||
results = s.createQuery( localities ).list().size();
|
||||
QueryStatistics localityStats = stats.getQueryStatistics( localities );
|
||||
QueryStatistics localityStats = sf.getStatistics().getQueryStatistics( localities );
|
||||
assertNotNull( "stats were null", localityStats );
|
||||
// ...one for each split query
|
||||
assertEquals( "unexpected execution count", 2, localityStats.getExecutionCount() );
|
||||
assertEquals( "unexpected row count", results, localityStats.getExecutionRowCount() );
|
||||
maxTime = localityStats.getExecutionMaxTime();
|
||||
assertEquals( maxTime, stats.getQueryExecutionMaxTime() );
|
||||
assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() );
|
||||
// assertEquals( localities, stats.getQueryExecutionMaxTimeQueryString() );
|
||||
tx.commit();
|
||||
s.close();
|
||||
assertFalse( s.isOpen() );
|
||||
|
||||
// native sql queries
|
||||
stats.clear();
|
||||
s = openSession();
|
||||
sf.getStatistics().clear();
|
||||
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
final String sql = "select id, name from Country";
|
||||
results = s.createSQLQuery( sql ).addEntity( Country.class ).list().size();
|
||||
QueryStatistics sqlStats = stats.getQueryStatistics( sql );
|
||||
QueryStatistics sqlStats = sf.getStatistics().getQueryStatistics( sql );
|
||||
assertNotNull( "sql stats were null", sqlStats );
|
||||
assertEquals( "unexpected execution count", 1, sqlStats.getExecutionCount() );
|
||||
assertEquals( "unexpected row count", results, sqlStats.getExecutionRowCount() );
|
||||
maxTime = sqlStats.getExecutionMaxTime();
|
||||
assertEquals( maxTime, stats.getQueryExecutionMaxTime() );
|
||||
assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() );
|
||||
// assertEquals( sql, stats.getQueryExecutionMaxTimeQueryString() );
|
||||
tx.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s = sf.openSession();
|
||||
tx = s.beginTransaction();
|
||||
cleanDb( s );
|
||||
tx.commit();
|
||||
s.close();
|
||||
sf.close();
|
||||
}
|
||||
|
||||
private Continent fillDb(Session s) {
|
||||
|
|
|
@ -22,6 +22,9 @@ dependencies {
|
|||
testRuntime( libraries.validator )
|
||||
testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Alpha2" )
|
||||
// testRuntime( "org.glassfish.web:el-impl:2.1.2-b04" )
|
||||
|
||||
// for testing stored procedure support
|
||||
testCompile( libraries.derby )
|
||||
}
|
||||
|
||||
def pomName() {
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
package org.hibernate.jpa.event.internal.jpa;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
||||
|
@ -36,7 +35,8 @@ import org.hibernate.jpa.event.spi.jpa.ListenerFactory;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardListenerFactory implements ListenerFactory {
|
||||
private Map listenerInstances = new ConcurrentHashMap();
|
||||
|
||||
private final ConcurrentHashMap listenerInstances = new ConcurrentHashMap();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -52,7 +52,10 @@ public class StandardListenerFactory implements ListenerFactory {
|
|||
e
|
||||
);
|
||||
}
|
||||
listenerInstances.put( listenerClass, listenerInstance );
|
||||
Object existing = listenerInstances.putIfAbsent( listenerClass, listenerInstance );
|
||||
if ( existing != null ) {
|
||||
listenerInstance = existing;
|
||||
}
|
||||
}
|
||||
return (T) listenerInstance;
|
||||
}
|
||||
|
|
|
@ -269,6 +269,8 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
|
||||
@Override
|
||||
public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map) {
|
||||
validateNotClosed();
|
||||
|
||||
//TODO support discardOnClose, persistencecontexttype?, interceptor,
|
||||
return new EntityManagerImpl(
|
||||
this,
|
||||
|
@ -282,42 +284,49 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
}
|
||||
|
||||
public CriteriaBuilder getCriteriaBuilder() {
|
||||
validateNotClosed();
|
||||
return criteriaBuilder;
|
||||
}
|
||||
|
||||
public Metamodel getMetamodel() {
|
||||
validateNotClosed();
|
||||
return metamodel;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// The spec says so, that's why :(
|
||||
validateNotClosed();
|
||||
|
||||
sessionFactory.close();
|
||||
EntityManagerFactoryRegistry.INSTANCE.removeEntityManagerFactory(entityManagerFactoryName, this);
|
||||
}
|
||||
|
||||
public Map<String, Object> getProperties() {
|
||||
validateNotClosed();
|
||||
return properties;
|
||||
}
|
||||
|
||||
public Cache getCache() {
|
||||
validateNotClosed();
|
||||
|
||||
// TODO : cache the cache reference?
|
||||
if ( ! isOpen() ) {
|
||||
throw new IllegalStateException("EntityManagerFactory is closed");
|
||||
}
|
||||
return new JPACache( sessionFactory );
|
||||
}
|
||||
|
||||
public PersistenceUnitUtil getPersistenceUnitUtil() {
|
||||
protected void validateNotClosed() {
|
||||
if ( ! isOpen() ) {
|
||||
throw new IllegalStateException("EntityManagerFactory is closed");
|
||||
throw new IllegalStateException( "EntityManagerFactory is closed" );
|
||||
}
|
||||
}
|
||||
|
||||
public PersistenceUnitUtil getPersistenceUnitUtil() {
|
||||
validateNotClosed();
|
||||
return util;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNamedQuery(String name, Query query) {
|
||||
if ( ! isOpen() ) {
|
||||
throw new IllegalStateException( "EntityManagerFactory is closed" );
|
||||
}
|
||||
validateNotClosed();
|
||||
|
||||
if ( StoredProcedureQueryImpl.class.isInstance( query ) ) {
|
||||
final ProcedureCall procedureCall = ( (StoredProcedureQueryImpl) query ).getHibernateProcedureCall();
|
||||
|
|
|
@ -197,7 +197,7 @@ public class EntityManagerImpl extends AbstractEntityManagerImpl implements Sess
|
|||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> EntityGraph<T> getEntityGraph(String graphName) {
|
||||
public EntityGraph<?> getEntityGraph(String graphName) {
|
||||
checkOpen();
|
||||
final EntityGraphImpl named = getEntityManagerFactory().findEntityGraphByName( graphName );
|
||||
if ( named == null ) {
|
||||
|
|
|
@ -23,13 +23,10 @@
|
|||
*/
|
||||
package org.hibernate.jpa.internal;
|
||||
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.TypedQuery;
|
||||
import static javax.persistence.TemporalType.DATE;
|
||||
import static javax.persistence.TemporalType.TIME;
|
||||
import static javax.persistence.TemporalType.TIMESTAMP;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -39,7 +36,13 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
|
@ -59,10 +62,8 @@ import org.hibernate.jpa.internal.util.LockModeTypeHelper;
|
|||
import org.hibernate.jpa.spi.AbstractEntityManagerImpl;
|
||||
import org.hibernate.jpa.spi.AbstractQueryImpl;
|
||||
import org.hibernate.type.CompositeCustomType;
|
||||
|
||||
import static javax.persistence.TemporalType.DATE;
|
||||
import static javax.persistence.TemporalType.TIME;
|
||||
import static javax.persistence.TemporalType.TIMESTAMP;
|
||||
import org.hibernate.type.Type;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Hibernate implementation of both the {@link Query} and {@link TypedQuery} contracts.
|
||||
|
@ -103,7 +104,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
for ( String name : (Set<String>) parameterMetadata.getNamedParameterNames() ) {
|
||||
final NamedParameterDescriptor descriptor = parameterMetadata.getNamedParameterDescriptor( name );
|
||||
Class javaType = namedParameterTypeRedefinition.get( name );
|
||||
if ( javaType != null && mightNeedRedefinition( javaType, descriptor.getExpectedType().getClass() ) ) {
|
||||
if ( javaType != null && mightNeedRedefinition( javaType, descriptor.getExpectedType() ) ) {
|
||||
descriptor.resetExpectedType(
|
||||
sfi().getTypeResolver().heuristicType( javaType.getName() )
|
||||
);
|
||||
|
@ -136,10 +137,13 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
return (SessionFactoryImplementor) getEntityManager().getFactory().getSessionFactory();
|
||||
}
|
||||
|
||||
private boolean mightNeedRedefinition(Class javaType, Class expectedType) {
|
||||
private boolean mightNeedRedefinition(Class javaType, Type expectedType) {
|
||||
// only redefine dates/times/timestamps that are not wrapped in a CompositeCustomType
|
||||
if ( expectedType == null )
|
||||
return java.util.Date.class.isAssignableFrom( javaType );
|
||||
else
|
||||
return java.util.Date.class.isAssignableFrom( javaType )
|
||||
&& !CompositeCustomType.class.isAssignableFrom( expectedType );
|
||||
&& !CompositeCustomType.class.isAssignableFrom( expectedType.getClass() );
|
||||
}
|
||||
|
||||
private static class ParameterRegistrationImpl<T> implements ParameterRegistration<T> {
|
||||
|
|
|
@ -25,11 +25,15 @@ package org.hibernate.jpa.internal;
|
|||
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
import javax.persistence.Parameter;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.TransactionRequiredException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -37,11 +41,15 @@ import java.util.List;
|
|||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.procedure.NoSuchParameterException;
|
||||
import org.hibernate.procedure.ParameterStrategyException;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.procedure.ProcedureResult;
|
||||
import org.hibernate.result.ResultSetReturn;
|
||||
import org.hibernate.result.Return;
|
||||
import org.hibernate.result.UpdateCountReturn;
|
||||
import org.hibernate.procedure.ProcedureCallMemento;
|
||||
import org.hibernate.procedure.ProcedureOutputs;
|
||||
import org.hibernate.result.NoMoreReturnsException;
|
||||
import org.hibernate.result.ResultSetOutput;
|
||||
import org.hibernate.result.Output;
|
||||
import org.hibernate.result.UpdateCountOutput;
|
||||
import org.hibernate.jpa.spi.BaseQueryImpl;
|
||||
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
|
||||
|
||||
|
@ -50,13 +58,28 @@ import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
|
|||
*/
|
||||
public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredProcedureQuery {
|
||||
private final ProcedureCall procedureCall;
|
||||
private ProcedureResult procedureResult;
|
||||
private ProcedureOutputs procedureResult;
|
||||
|
||||
public StoredProcedureQueryImpl(ProcedureCall procedureCall, HibernateEntityManagerImplementor entityManager) {
|
||||
super( entityManager );
|
||||
this.procedureCall = procedureCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* This form is used to build a StoredProcedureQueryImpl from a memento (usually from a NamedStoredProcedureQuery).
|
||||
*
|
||||
* @param memento The memento
|
||||
* @param entityManager The EntityManager
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public StoredProcedureQueryImpl(ProcedureCallMemento memento, HibernateEntityManagerImplementor entityManager) {
|
||||
super( entityManager );
|
||||
this.procedureCall = memento.makeProcedureCall( entityManager.getSession() );
|
||||
for ( org.hibernate.procedure.ParameterRegistration nativeParamReg : procedureCall.getRegisteredParameters() ) {
|
||||
registerParameter( new ParameterRegistrationImpl( nativeParamReg ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean applyTimeoutHint(int timeout) {
|
||||
procedureCall.setTimeout( timeout );
|
||||
|
@ -178,81 +201,162 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
|||
|
||||
// outputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private ProcedureResult outputs() {
|
||||
@Override
|
||||
public boolean execute() {
|
||||
try {
|
||||
final Output rtn = outputs().getCurrent();
|
||||
return rtn != null && ResultSetOutput.class.isInstance( rtn );
|
||||
}
|
||||
catch (NoMoreReturnsException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected ProcedureOutputs outputs() {
|
||||
if ( procedureResult == null ) {
|
||||
procedureResult = procedureCall.getResult();
|
||||
}
|
||||
return procedureResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate() {
|
||||
if ( ! entityManager().isTransactionInProgress() ) {
|
||||
throw new TransactionRequiredException( "javax.persistence.Query.executeUpdate requires active transaction" );
|
||||
}
|
||||
|
||||
// the expectation is that there is just one Output, of type UpdateCountOutput
|
||||
try {
|
||||
execute();
|
||||
return getUpdateCount();
|
||||
}
|
||||
finally {
|
||||
outputs().release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOutputParameterValue(int position) {
|
||||
try {
|
||||
return outputs().getOutputParameterValue( position );
|
||||
}
|
||||
catch (ParameterStrategyException e) {
|
||||
throw new IllegalArgumentException( "Invalid mix of named and positional parameters", e );
|
||||
}
|
||||
catch (NoSuchParameterException e) {
|
||||
throw new IllegalArgumentException( e.getMessage(), e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOutputParameterValue(String parameterName) {
|
||||
try {
|
||||
return outputs().getOutputParameterValue( parameterName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute() {
|
||||
return outputs().hasMoreReturns();
|
||||
catch (ParameterStrategyException e) {
|
||||
throw new IllegalArgumentException( "Invalid mix of named and positional parameters", e );
|
||||
}
|
||||
catch (NoSuchParameterException e) {
|
||||
throw new IllegalArgumentException( e.getMessage(), e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate() {
|
||||
return getUpdateCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreResults() {
|
||||
return outputs().hasMoreReturns();
|
||||
return outputs().goToNext() && ResultSetOutput.class.isInstance( outputs().getCurrent() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
final Return nextReturn = outputs().getNextReturn();
|
||||
if ( nextReturn.isResultSet() ) {
|
||||
try {
|
||||
final Output rtn = outputs().getCurrent();
|
||||
if ( rtn == null ) {
|
||||
return -1;
|
||||
}
|
||||
else if ( UpdateCountOutput.class.isInstance( rtn ) ) {
|
||||
return ( (UpdateCountOutput) rtn ).getUpdateCount();
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (NoMoreReturnsException e) {
|
||||
return -1;
|
||||
}
|
||||
return ( (UpdateCountReturn) nextReturn ).getUpdateCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List getResultList() {
|
||||
final Return nextReturn = outputs().getNextReturn();
|
||||
if ( ! nextReturn.isResultSet() ) {
|
||||
return null; // todo : what should be thrown/returned here?
|
||||
try {
|
||||
final Output rtn = outputs().getCurrent();
|
||||
if ( ! ResultSetOutput.class.isInstance( rtn ) ) {
|
||||
throw new IllegalStateException( "Current CallableStatement ou was not a ResultSet, but getResultList was called" );
|
||||
}
|
||||
|
||||
return ( (ResultSetOutput) rtn ).getResultList();
|
||||
}
|
||||
catch (NoMoreReturnsException e) {
|
||||
// todo : the spec is completely silent on these type of edge-case scenarios.
|
||||
// Essentially here we'd have a case where there are no more results (ResultSets nor updateCount) but
|
||||
// getResultList was called.
|
||||
return null;
|
||||
}
|
||||
return ( (ResultSetReturn) nextReturn ).getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSingleResult() {
|
||||
final Return nextReturn = outputs().getNextReturn();
|
||||
if ( ! nextReturn.isResultSet() ) {
|
||||
return null; // todo : what should be thrown/returned here?
|
||||
final List resultList = getResultList();
|
||||
if ( resultList == null || resultList.isEmpty() ) {
|
||||
throw new NoResultException(
|
||||
String.format(
|
||||
"Call to stored procedure [%s] returned no results",
|
||||
procedureCall.getProcedureName()
|
||||
)
|
||||
);
|
||||
}
|
||||
return ( (ResultSetReturn) nextReturn ).getSingleResult();
|
||||
else if ( resultList.size() > 1 ) {
|
||||
throw new NonUniqueResultException(
|
||||
String.format(
|
||||
"Call to stored procedure [%s] returned multiple results",
|
||||
procedureCall.getProcedureName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return resultList.get( 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T unwrap(Class<T> cls) {
|
||||
return null;
|
||||
if ( ProcedureCall.class.isAssignableFrom( cls ) ) {
|
||||
return (T) procedureCall;
|
||||
}
|
||||
else if ( ProcedureOutputs.class.isAssignableFrom( cls ) ) {
|
||||
return (T) outputs();
|
||||
}
|
||||
else if ( BaseQueryImpl.class.isAssignableFrom( cls ) ) {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
|
||||
// ugh ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
throw new PersistenceException(
|
||||
String.format(
|
||||
"Unsure how to unwrap %s impl [%s] as requested type [%s]",
|
||||
StoredProcedureQuery.class.getSimpleName(),
|
||||
this.getClass().getName(),
|
||||
cls.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query setLockMode(LockModeType lockMode) {
|
||||
return null;
|
||||
throw new IllegalStateException( "javax.persistence.Query.setLockMode not valid on javax.persistence.StoredProcedureQuery" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockModeType getLockMode() {
|
||||
return null;
|
||||
throw new IllegalStateException( "javax.persistence.Query.getLockMode not valid on javax.persistence.StoredProcedureQuery" );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.sql.Connection;
|
|||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.engine.jdbc.internal.DDLFormatterImpl;
|
||||
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
|
||||
|
@ -38,6 +39,8 @@ import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
class JdbcConnectionContext {
|
||||
private static final Logger log = Logger.getLogger( JdbcConnectionContext.class );
|
||||
|
||||
private final JdbcConnectionAccess jdbcConnectionAccess;
|
||||
private final SqlStatementLogger sqlStatementLogger;
|
||||
|
||||
|
@ -62,6 +65,15 @@ class JdbcConnectionContext {
|
|||
|
||||
public void release() {
|
||||
if ( jdbcConnection != null ) {
|
||||
try {
|
||||
if ( ! jdbcConnection.getAutoCommit() ) {
|
||||
jdbcConnection.commit();
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.debug( "Unable to commit JDBC transaction used for JPA schema export; may or may not be a problem" );
|
||||
}
|
||||
|
||||
try {
|
||||
jdbcConnectionAccess.releaseConnection( jdbcConnection );
|
||||
}
|
||||
|
|
|
@ -838,8 +838,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
if ( memento == null ) {
|
||||
throw new IllegalArgumentException( "No @NamedStoredProcedureQuery was found with that name : " + name );
|
||||
}
|
||||
final ProcedureCall procedureCall = memento.makeProcedureCall( internalGetSession() );
|
||||
final StoredProcedureQueryImpl jpaImpl = new StoredProcedureQueryImpl( procedureCall, this );
|
||||
final StoredProcedureQueryImpl jpaImpl = new StoredProcedureQueryImpl( memento, this );
|
||||
// apply hints
|
||||
if ( memento.getHintsMap() != null ) {
|
||||
for ( Map.Entry<String,Object> hintEntry : memento.getHintsMap().entrySet() ) {
|
||||
|
|
|
@ -51,6 +51,8 @@ import org.hibernate.jpa.internal.EntityManagerMessageLogger;
|
|||
import org.hibernate.jpa.internal.util.CacheModeHelper;
|
||||
import org.hibernate.jpa.internal.util.ConfigurationHelper;
|
||||
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
|
||||
import org.hibernate.procedure.NoSuchParameterException;
|
||||
import org.hibernate.procedure.ParameterStrategyException;
|
||||
|
||||
import static org.hibernate.jpa.QueryHints.HINT_CACHEABLE;
|
||||
import static org.hibernate.jpa.QueryHints.HINT_CACHE_MODE;
|
||||
|
@ -439,7 +441,8 @@ public abstract class BaseQueryImpl implements Query {
|
|||
protected abstract boolean isJpaPositionalParameter(int position);
|
||||
|
||||
/**
|
||||
* Hibernate specific extension to the JPA {@link javax.persistence.Parameter} contract.
|
||||
* Hibernate specific extension to the JPA {@link javax.persistence.Parameter} contract. Used here to track
|
||||
* information known about the parameter.
|
||||
*/
|
||||
protected static interface ParameterRegistration<T> extends Parameter<T> {
|
||||
/**
|
||||
|
@ -450,6 +453,12 @@ public abstract class BaseQueryImpl implements Query {
|
|||
*/
|
||||
public ParameterMode getMode();
|
||||
|
||||
/**
|
||||
* Can we bind (set) values on this parameter? Generally this is {@code true}, but would not be in the case
|
||||
* of parameters with OUT or REF_CURSOR mode.
|
||||
*
|
||||
* @return Whether the parameter is bindable (can set be called).
|
||||
*/
|
||||
public boolean isBindable();
|
||||
|
||||
public void bindValue(T value);
|
||||
|
@ -459,6 +468,11 @@ public abstract class BaseQueryImpl implements Query {
|
|||
public ParameterBind<T> getBind();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the value currently bound to a particular parameter.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
protected static interface ParameterBind<T> {
|
||||
public T getValue();
|
||||
|
||||
|
@ -648,6 +662,12 @@ public abstract class BaseQueryImpl implements Query {
|
|||
try {
|
||||
findParameterRegistration( position ).bindValue( value, temporalType );
|
||||
}
|
||||
catch (ParameterStrategyException e) {
|
||||
throw new IllegalArgumentException( "Invalid mix of named and positional parameters", e );
|
||||
}
|
||||
catch (NoSuchParameterException e) {
|
||||
throw new IllegalArgumentException( e.getMessage(), e );
|
||||
}
|
||||
catch (QueryParameterException e) {
|
||||
throw new IllegalArgumentException( e );
|
||||
}
|
||||
|
@ -755,18 +775,22 @@ public abstract class BaseQueryImpl implements Query {
|
|||
checkOpen( false );
|
||||
|
||||
final ParameterRegistration<T> registration = findParameterRegistration( param );
|
||||
if ( registration != null ) {
|
||||
if ( registration == null ) {
|
||||
throw new IllegalArgumentException( "Passed parameter [" + param + "] is not a (registered) parameter of this query" );
|
||||
}
|
||||
|
||||
if ( ! registration.isBindable() ) {
|
||||
throw new IllegalArgumentException( "Passed parameter [" + param + "] is not bindable" );
|
||||
throw new IllegalStateException( "Passed parameter [" + param + "] is not bindable" );
|
||||
}
|
||||
|
||||
final ParameterBind<T> bind = registration.getBind();
|
||||
if ( bind != null ) {
|
||||
return bind.getValue();
|
||||
}
|
||||
}
|
||||
if ( bind == null ) {
|
||||
throw new IllegalStateException( "Parameter [" + param + "] has not yet been bound" );
|
||||
}
|
||||
|
||||
return bind.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParameterValue(String name) {
|
||||
checkOpen( false );
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.ParameterExpression;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
|
@ -103,4 +104,26 @@ public class BasicCriteriaUsageTest extends BaseEntityManagerFunctionalTestCase
|
|||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-8373")
|
||||
public void testFunctionCriteria() {
|
||||
Wall wall = new Wall();
|
||||
wall.setColor( "yellow" );
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.persist( wall );
|
||||
|
||||
CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
CriteriaQuery<Wall> query = cb.createQuery( Wall.class );
|
||||
Root<Wall> root = query.from( Wall.class );
|
||||
|
||||
query.select( root ).where( cb.equal( root.get( "color" ), cb.lower( cb.literal( "YELLOW" ) ) ) );
|
||||
|
||||
Wall resultItem = em.createQuery( query ).getSingleResult();
|
||||
assertNotNull( resultItem );
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class BasicEntityGraphTests extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
em.getEntityManagerFactory().addNamedEntityGraph( "immutable", graphRoot );
|
||||
|
||||
graphRoot = em.getEntityGraph( "immutable" );
|
||||
graphRoot = (EntityGraph<Entity1>) em.getEntityGraph( "immutable" );
|
||||
|
||||
assertEquals( "immutable", graphRoot.getName() );
|
||||
assertEquals( 2, graphRoot.getAttributeNodes().size() );
|
||||
|
|
|
@ -52,13 +52,13 @@ public abstract class AbstractStoredProcedureTest extends BaseEntityManagerFunct
|
|||
list = m2.getParameterDeclarations();
|
||||
|
||||
memento = list.get( 0 );
|
||||
assertEquals( Integer.valueOf( 0 ), memento.getPosition() );
|
||||
assertEquals( Integer.valueOf( 1 ), memento.getPosition() );
|
||||
assertEquals( javax.persistence.ParameterMode.INOUT, memento.getMode() );
|
||||
assertEquals( StringType.INSTANCE, memento.getHibernateType() );
|
||||
assertEquals( String.class, memento.getType() );
|
||||
|
||||
memento = list.get( 1 );
|
||||
assertEquals( Integer.valueOf( 1 ), memento.getPosition() );
|
||||
assertEquals( Integer.valueOf( 2 ), memento.getPosition() );
|
||||
assertEquals( javax.persistence.ParameterMode.INOUT, memento.getMode() );
|
||||
assertEquals( LongType.INSTANCE, memento.getHibernateType() );
|
||||
assertEquals( Long.class, memento.getType() );
|
||||
|
|
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.jpa.test.procedure;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.dialect.DerbyTenSevenDialect;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.jpa.AvailableSettings;
|
||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||
import org.hibernate.jpa.boot.spi.Bootstrap;
|
||||
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
|
||||
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Tests various JPA usage scenarios for performing stored procedures. Inspired by the awesomely well-done JPA TCK
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JpaTckUsageTest extends BaseUnitTestCase {
|
||||
|
||||
@Test
|
||||
public void testMultipleGetUpdateCountCalls() {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
try {
|
||||
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser" );
|
||||
// this is what the TCK attempts to do, don't shoot the messenger...
|
||||
query.getUpdateCount();
|
||||
// yep, twice
|
||||
query.getUpdateCount();
|
||||
}
|
||||
finally {
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicScalarResults() {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
try {
|
||||
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser" );
|
||||
boolean isResult = query.execute();
|
||||
assertTrue( isResult );
|
||||
int updateCount = query.getUpdateCount();
|
||||
|
||||
boolean results = false;
|
||||
do {
|
||||
List list = query.getResultList();
|
||||
assertEquals( 1, list.size() );
|
||||
|
||||
results = query.hasMoreResults();
|
||||
// and it only sets the updateCount once lol
|
||||
} while ( results || updateCount != -1);
|
||||
}
|
||||
finally {
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-8416", message = "JPA TCK challenge" )
|
||||
public void testHasMoreResultsHandlingTckChallenge() {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
try {
|
||||
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser", User.class );
|
||||
assertTrue( query.execute() );
|
||||
assertTrue( query.hasMoreResults() );
|
||||
query.getResultList();
|
||||
assertFalse( query.hasMoreResults() );
|
||||
}
|
||||
finally {
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasMoreResultsHandling() {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
try {
|
||||
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser", User.class );
|
||||
assertTrue( query.execute() );
|
||||
query.getResultList();
|
||||
assertFalse( query.hasMoreResults() );
|
||||
}
|
||||
finally {
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultClassHandling() {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
try {
|
||||
StoredProcedureQuery query = em.createStoredProcedureQuery( "findOneUser", User.class );
|
||||
boolean isResult = query.execute();
|
||||
assertTrue( isResult );
|
||||
int updateCount = query.getUpdateCount();
|
||||
|
||||
boolean results = false;
|
||||
do {
|
||||
List list = query.getResultList();
|
||||
assertEquals( 1, list.size() );
|
||||
assertTyping( User.class, list.get( 0 ) );
|
||||
|
||||
results = query.hasMoreResults();
|
||||
// and it only sets the updateCount once lol
|
||||
} while ( results || updateCount != -1);
|
||||
}
|
||||
finally {
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingInParamDefinedOnNamedStoredProcedureQuery() {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
try {
|
||||
StoredProcedureQuery query = em.createNamedStoredProcedureQuery( "positional-param" );
|
||||
query.setParameter( 1, 1 );
|
||||
}
|
||||
finally {
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingNonExistingParams() {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
try {
|
||||
// non-existing positional param
|
||||
try {
|
||||
StoredProcedureQuery query = em.createNamedStoredProcedureQuery( "positional-param" );
|
||||
query.setParameter( 99, 1 );
|
||||
fail( "Expecting an exception" );
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
// this is the expected condition
|
||||
}
|
||||
|
||||
// non-existing named param
|
||||
try {
|
||||
StoredProcedureQuery query = em.createNamedStoredProcedureQuery( "positional-param" );
|
||||
query.setParameter( "does-not-exist", 1 );
|
||||
fail( "Expecting an exception" );
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
// this is the expected condition
|
||||
}
|
||||
}
|
||||
finally {
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-8395", message = "Out of the frying pan into the fire: https://issues.apache.org/jira/browse/DERBY-211" )
|
||||
public void testExecuteUpdate() {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
try {
|
||||
StoredProcedureQuery query = em.createStoredProcedureQuery( "deleteAllUsers" );
|
||||
int count = query.executeUpdate();
|
||||
// this fails because the Derby EmbeddedDriver is returning zero here rather than the actual updateCount :(
|
||||
// https://issues.apache.org/jira/browse/DERBY-211
|
||||
assertEquals( 1, count );
|
||||
}
|
||||
finally {
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testParameterRegistration() {
|
||||
|
||||
}
|
||||
|
||||
// todo : look at ways to allow "Auxiliary DB Objects" to the db via EMF bootstrapping.
|
||||
|
||||
// public static final String findOneUser_CREATE_CMD = "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" +
|
||||
// "$$";
|
||||
// public static final String findOneUser_DROP_CMD = "DROP ALIAS findOneUser IF EXISTS";
|
||||
//
|
||||
// public static final String deleteAllUsers_CREATE_CMD = "CREATE ALIAS deleteAllUsers AS $$\n" +
|
||||
// "@CODE\n" +
|
||||
// "int deleteAllUsers() {\n" +
|
||||
// " return 156;" +
|
||||
// "}\n" +
|
||||
// "$$";
|
||||
// public static final String deleteAllUsers_DROP_CMD = "DROP ALIAS deleteAllUsers IF EXISTS";
|
||||
|
||||
HibernateEntityManagerFactory entityManagerFactory;
|
||||
|
||||
@Before
|
||||
public void startUp() {
|
||||
// create the EMF
|
||||
entityManagerFactory = (EntityManagerFactoryImpl) Bootstrap.getEntityManagerFactoryBuilder(
|
||||
buildPersistenceUnitDescriptor(),
|
||||
buildSettingsMap()
|
||||
).build();
|
||||
|
||||
// create the procedures
|
||||
createTestUser( entityManagerFactory );
|
||||
createProcedures( entityManagerFactory );
|
||||
}
|
||||
|
||||
private PersistenceUnitDescriptor buildPersistenceUnitDescriptor() {
|
||||
return new BaseEntityManagerFunctionalTestCase.TestingPersistenceUnitDescriptorImpl( getClass().getSimpleName() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map buildSettingsMap() {
|
||||
Map settings = new HashMap();
|
||||
|
||||
settings.put( AvailableSettings.LOADED_CLASSES, Collections.singletonList( User.class ) );
|
||||
|
||||
settings.put( org.hibernate.cfg.AvailableSettings.DIALECT, DerbyTenSevenDialect.class );
|
||||
settings.put( org.hibernate.cfg.AvailableSettings.DRIVER, org.apache.derby.jdbc.EmbeddedDriver.class.getName() );
|
||||
// settings.put( org.hibernate.cfg.AvailableSettings.URL, "jdbc:derby:/tmp/hibernate-orm-testing;create=true" );
|
||||
settings.put( org.hibernate.cfg.AvailableSettings.URL, "jdbc:derby:memory:hibernate-orm-testing;create=true" );
|
||||
settings.put( org.hibernate.cfg.AvailableSettings.USER, "" );
|
||||
|
||||
settings.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, "create-drop" );
|
||||
settings.put( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" );
|
||||
settings.put( org.hibernate.cfg.AvailableSettings.DIALECT, DerbyTenSevenDialect.class.getName() );
|
||||
return settings;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if ( entityManagerFactory == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
deleteTestUser( entityManagerFactory );
|
||||
dropProcedures( entityManagerFactory );
|
||||
|
||||
entityManagerFactory.close();
|
||||
}
|
||||
|
||||
private void createProcedures(HibernateEntityManagerFactory emf) {
|
||||
final SessionFactoryImplementor sf = emf.unwrap( SessionFactoryImplementor.class );
|
||||
final Connection conn;
|
||||
try {
|
||||
conn = sf.getConnectionProvider().getConnection();
|
||||
conn.setAutoCommit( false );
|
||||
|
||||
try {
|
||||
Statement statement = conn.createStatement();
|
||||
|
||||
// drop them, just to be sure
|
||||
try {
|
||||
dropProcedures( statement );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
|
||||
createProcedureFindOneUser( statement );
|
||||
createProcedureDeleteAllUsers( statement );
|
||||
try {
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
conn.commit();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
System.out.println( "Unable to commit transaction after creating creating procedures");
|
||||
}
|
||||
|
||||
try {
|
||||
sf.getConnectionProvider().closeConnection( conn );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Unable to create stored procedures", e );
|
||||
}
|
||||
}
|
||||
|
||||
private void dropProcedures(Statement statement) throws SQLException {
|
||||
statement.execute( "DROP PROCEDURE findOneUser" );
|
||||
statement.execute( "DROP PROCEDURE deleteAllUsers" );
|
||||
}
|
||||
|
||||
private void createProcedureFindOneUser(Statement statement) throws SQLException {
|
||||
statement.execute(
|
||||
"CREATE PROCEDURE findOneUser() " +
|
||||
"language java " +
|
||||
"dynamic result sets 1 " +
|
||||
"external name 'org.hibernate.jpa.test.procedure.JpaTckUsageTest.findOneUser' " +
|
||||
"parameter style java"
|
||||
);
|
||||
}
|
||||
|
||||
private void createProcedureDeleteAllUsers(Statement statement) throws SQLException {
|
||||
statement.execute(
|
||||
"CREATE PROCEDURE deleteAllUsers() " +
|
||||
"language java " +
|
||||
"external name 'org.hibernate.jpa.test.procedure.JpaTckUsageTest.deleteAllUsers' " +
|
||||
"parameter style java"
|
||||
);
|
||||
}
|
||||
|
||||
public static void findOneUser(ResultSet[] results) throws SQLException {
|
||||
Connection conn = DriverManager.getConnection( "jdbc:default:connection" );
|
||||
PreparedStatement ps = conn.prepareStatement( "select id, name from t_user where name=?" );
|
||||
ps.setString( 1, "steve" );
|
||||
results[0] = ps.executeQuery();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
public static void findUserIds(ResultSet[] results) throws SQLException {
|
||||
Connection conn = DriverManager.getConnection( "jdbc:default:connection" );
|
||||
PreparedStatement ps = conn.prepareStatement( "select id from t_user" );
|
||||
results[0] = ps.executeQuery();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
public static void deleteAllUsers() throws SQLException {
|
||||
// afaict the only way to return update counts here is to actually perform some DML
|
||||
Connection conn = DriverManager.getConnection( "jdbc:default:connection" );
|
||||
System.out.println( "Preparing delete all" );
|
||||
PreparedStatement ps = conn.prepareStatement( "delete from t_user" );
|
||||
System.out.println( "Executing delete all" );
|
||||
int count = ps.executeUpdate();
|
||||
System.out.println( "Count : " + count );
|
||||
System.out.println( "Closing resources" );
|
||||
ps.close();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
private void createTestUser(HibernateEntityManagerFactory entityManagerFactory) {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
em.persist( new User( 1, "steve" ) );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
private void deleteTestUser(HibernateEntityManagerFactory entityManagerFactory) {
|
||||
EntityManager em = entityManagerFactory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.createQuery( "delete from User" ).executeUpdate();
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
private void dropProcedures(HibernateEntityManagerFactory emf) {
|
||||
|
||||
final SessionFactoryImplementor sf = emf.unwrap( SessionFactoryImplementor.class );
|
||||
final Connection conn;
|
||||
try {
|
||||
conn = sf.getConnectionProvider().getConnection();
|
||||
conn.setAutoCommit( false );
|
||||
|
||||
try {
|
||||
Statement statement = conn.createStatement();
|
||||
dropProcedures( statement );
|
||||
try {
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
conn.commit();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
System.out.println( "Unable to commit transaction after creating dropping procedures");
|
||||
}
|
||||
|
||||
try {
|
||||
sf.getConnectionProvider().closeConnection( conn );
|
||||
}
|
||||
catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Unable to drop stored procedures", e );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import javax.persistence.NamedStoredProcedureQuery;
|
|||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.SqlResultSetMapping;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Strong Liu <stliu@hibernate.org>
|
||||
|
@ -43,6 +44,13 @@ import javax.persistence.StoredProcedureParameter;
|
|||
},
|
||||
resultSetMappings = { "srms" }
|
||||
|
||||
),
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "positional-param",
|
||||
procedureName = "positionalParameterTesting",
|
||||
parameters = {
|
||||
@StoredProcedureParameter( mode = ParameterMode.IN, type = Integer.class )
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
@ -54,11 +62,20 @@ import javax.persistence.StoredProcedureParameter;
|
|||
})
|
||||
}
|
||||
)
|
||||
@Table( name = "T_USER" )
|
||||
public class User {
|
||||
@Id
|
||||
private int id;
|
||||
private String name;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(int id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
# 51 Franklin Street, Fifth Floor
|
||||
# Boston, MA 02110-1301 USA
|
||||
#
|
||||
|
||||
hibernate.dialect org.hibernate.dialect.H2Dialect
|
||||
hibernate.connection.driver_class org.h2.Driver
|
||||
hibernate.connection.url jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE;LOCK_TIMEOUT=10000
|
||||
|
|
|
@ -125,4 +125,10 @@ public interface EnversSettings {
|
|||
* Name of column used for storing ordinal of the change in sets of embeddable elements. Defaults to {@literal SETORDINAL}.
|
||||
*/
|
||||
public static final String EMBEDDABLE_SET_ORDINAL_FIELD_NAME = "org.hibernate.envers.embeddable_set_ordinal_field_name";
|
||||
|
||||
/**
|
||||
* Guarantees proper validity audit strategy behavior when application reuses identifiers of deleted entities.
|
||||
* Exactly one row with {@code null} end date exists for each identifier.
|
||||
*/
|
||||
public static final String ALLOW_IDENTIFIER_REUSE = "org.hibernate.envers.allow_identifier_reuse";
|
||||
}
|
||||
|
|
|
@ -75,6 +75,9 @@ public class GlobalConfiguration {
|
|||
// Use revision entity with native id generator
|
||||
private final boolean useRevisionEntityWithNativeId;
|
||||
|
||||
// Support reused identifiers of previously deleted entities
|
||||
private final boolean allowIdentifierReuse;
|
||||
|
||||
/*
|
||||
Which operator to use in correlated subqueries (when we want a property to be equal to the result of
|
||||
a correlated subquery, for example: e.p <operator> (select max(e2.p) where e2.p2 = e.p2 ...).
|
||||
|
@ -131,6 +134,10 @@ public class GlobalConfiguration {
|
|||
else {
|
||||
revisionListenerClass = null;
|
||||
}
|
||||
|
||||
allowIdentifierReuse = ConfigurationHelper.getBoolean(
|
||||
EnversSettings.ALLOW_IDENTIFIER_REUSE, properties, false
|
||||
);
|
||||
}
|
||||
|
||||
public boolean isGenerateRevisionsForCollections() {
|
||||
|
@ -184,4 +191,8 @@ public class GlobalConfiguration {
|
|||
public boolean isUseRevisionEntityWithNativeId() {
|
||||
return useRevisionEntityWithNativeId;
|
||||
}
|
||||
|
||||
public boolean isAllowIdentifierReuse() {
|
||||
return allowIdentifierReuse;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGen
|
|||
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||
createValidDataRestrictions(
|
||||
globalCfg, auditStrategy, referencedIdData, validQuery, validQuery.getRootParameters(), true
|
||||
globalCfg, auditStrategy, referencedIdData, validQuery, validQuery.getRootParameters()
|
||||
);
|
||||
createValidAndRemovedDataRestrictions( globalCfg, auditStrategy, referencedIdData, removedQuery );
|
||||
|
||||
|
@ -99,8 +99,7 @@ public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGen
|
|||
*/
|
||||
private void createValidDataRestrictions(
|
||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||
MiddleIdData referencedIdData, QueryBuilder qb, Parameters rootParameters,
|
||||
boolean inclusive) {
|
||||
MiddleIdData referencedIdData, QueryBuilder qb, Parameters rootParameters) {
|
||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
// (selecting e entities at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
|
@ -108,7 +107,7 @@ public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGen
|
|||
globalCfg, qb, rootParameters, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencedIdData, revisionPropertyPath,
|
||||
verEntCfg.getOriginalIdPropName(), REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR,
|
||||
inclusive
|
||||
true
|
||||
);
|
||||
// e.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), false, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||
|
@ -126,7 +125,7 @@ public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGen
|
|||
// Restrictions to match all rows deleted at exactly given revision.
|
||||
final Parameters removed = disjoint.addSubParameters( "and" );
|
||||
// Excluding current revision, because we need to match data valid at the previous one.
|
||||
createValidDataRestrictions( globalCfg, auditStrategy, referencedIdData, remQb, valid, false );
|
||||
createValidDataRestrictions( globalCfg, auditStrategy, referencedIdData, remQb, valid );
|
||||
// e.revision = :revision
|
||||
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), false, "=", REVISION_PARAMETER );
|
||||
// e.revision_type = DEL
|
||||
|
|
|
@ -180,7 +180,7 @@ public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenera
|
|||
originalIdPropertyName,
|
||||
REFERENCED_ENTITY_ALIAS,
|
||||
REFERENCED_ENTITY_ALIAS_DEF_AUD_STR,
|
||||
inclusive
|
||||
true
|
||||
);
|
||||
// (selecting f entities at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
|
@ -188,15 +188,15 @@ public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenera
|
|||
globalCfg,
|
||||
qb,
|
||||
rootParameters,
|
||||
REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath,
|
||||
REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionEndFieldName(),
|
||||
INDEX_ENTITY_ALIAS + "." + revisionPropertyPath,
|
||||
INDEX_ENTITY_ALIAS + "." + verEntCfg.getRevisionEndFieldName(),
|
||||
false,
|
||||
referencedIdData,
|
||||
revisionPropertyPath,
|
||||
originalIdPropertyName,
|
||||
INDEX_ENTITY_ALIAS,
|
||||
INDEX_ENTITY_ALIAS_DEF_AUD_STR,
|
||||
inclusive
|
||||
true
|
||||
);
|
||||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
|
|
|
@ -152,7 +152,7 @@ public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
originalIdPropertyName,
|
||||
REFERENCED_ENTITY_ALIAS,
|
||||
REFERENCED_ENTITY_ALIAS_DEF_AUD_STR,
|
||||
inclusive
|
||||
true
|
||||
);
|
||||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
|
|
|
@ -98,8 +98,15 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
|||
session.save( auditedEntityName, data );
|
||||
sessionCacheCleaner.scheduleAuditDataRemoval( session, data );
|
||||
|
||||
// Update the end date of the previous row if this operation is expected to have a previous row
|
||||
if ( getRevisionType( auditCfg, data ) != RevisionType.ADD ) {
|
||||
// Update the end date of the previous row.
|
||||
//
|
||||
// When application reuses identifiers of previously removed entities:
|
||||
// The UPDATE statement will no-op if an entity with a given identifier has been
|
||||
// inserted for the first time. But in case a deleted primary key value was
|
||||
// reused, this guarantees correct strategy behavior: exactly one row with
|
||||
// null end date exists for each identifier.
|
||||
final boolean reuseEntityIdentifier = auditCfg.getGlobalCfg().isAllowIdentifierReuse();
|
||||
if ( reuseEntityIdentifier || getRevisionType( auditCfg, data ) != RevisionType.ADD ) {
|
||||
final Queryable productionEntityQueryable = getQueryable( entityName, sessionImplementor );
|
||||
final Queryable rootProductionEntityQueryable = getQueryable(
|
||||
productionEntityQueryable.getRootEntityName(),
|
||||
|
@ -238,7 +245,7 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
|||
}
|
||||
);
|
||||
|
||||
if ( rowCount != 1 ) {
|
||||
if ( rowCount != 1 && ( !reuseEntityIdentifier || ( getRevisionType( auditCfg, data ) != RevisionType.ADD ) ) ) {
|
||||
throw new RuntimeException(
|
||||
"Cannot update previous revision for entity " + auditedEntityName + " and id " + id
|
||||
);
|
||||
|
|
|
@ -58,9 +58,9 @@ public class CollectionRefIngEntity implements Serializable {
|
|||
this.reference = reference;
|
||||
}
|
||||
|
||||
public CollectionRefIngEntity(String data, CollectionRefEdEntity reference) {
|
||||
public CollectionRefIngEntity(Integer id, String data) {
|
||||
this.id = id;
|
||||
this.data = data;
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
|
|
|
@ -106,7 +106,6 @@ public class NotOwnedBidirectional extends BaseEnversJPAFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
public void testHistoryOfPersonalContact() {
|
||||
System.out.println( getAuditReader().find( PersonalContact.class, pc_id, 1 ).getAddresses() );
|
||||
assert getAuditReader().find( PersonalContact.class, pc_id, 1 ).getAddresses().equals(
|
||||
TestTools.makeSet( new Address( a1_id, "a1" ) )
|
||||
);
|
||||
|
|
|
@ -106,7 +106,6 @@ public class NotOwnedBidirectional extends BaseEnversJPAFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
public void testHistoryOfPersonalContact() {
|
||||
System.out.println( getAuditReader().find( PersonalContact.class, pc_id, 1 ).getAddresses() );
|
||||
assert getAuditReader().find( PersonalContact.class, pc_id, 1 ).getAddresses().equals(
|
||||
TestTools.makeSet( new Address( a1_id, "a1" ) )
|
||||
);
|
||||
|
|
|
@ -156,10 +156,10 @@ public class BasicList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListOwnedEntity rev5 = getAuditReader().find( ListOwnedEntity.class, ed1_id, 5 );
|
||||
|
||||
assert rev1.getReferencing().equals( Collections.EMPTY_LIST );
|
||||
assert TestTools.checkList( rev2.getReferencing(), ing1, ing2 );
|
||||
assert TestTools.checkList( rev3.getReferencing(), ing1, ing2 );
|
||||
assert TestTools.checkList( rev4.getReferencing(), ing2 );
|
||||
assert TestTools.checkList( rev5.getReferencing(), ing2 );
|
||||
assert TestTools.checkCollection( rev2.getReferencing(), ing1, ing2 );
|
||||
assert TestTools.checkCollection( rev3.getReferencing(), ing1, ing2 );
|
||||
assert TestTools.checkCollection( rev4.getReferencing(), ing2 );
|
||||
assert TestTools.checkCollection( rev5.getReferencing(), ing2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -174,10 +174,10 @@ public class BasicList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListOwnedEntity rev5 = getAuditReader().find( ListOwnedEntity.class, ed2_id, 5 );
|
||||
|
||||
assert rev1.getReferencing().equals( Collections.EMPTY_LIST );
|
||||
assert TestTools.checkList( rev2.getReferencing(), ing2 );
|
||||
assert TestTools.checkList( rev3.getReferencing(), ing1, ing2 );
|
||||
assert TestTools.checkList( rev4.getReferencing(), ing1, ing2 );
|
||||
assert TestTools.checkList( rev5.getReferencing(), ing2 );
|
||||
assert TestTools.checkCollection( rev2.getReferencing(), ing2 );
|
||||
assert TestTools.checkCollection( rev3.getReferencing(), ing1, ing2 );
|
||||
assert TestTools.checkCollection( rev4.getReferencing(), ing1, ing2 );
|
||||
assert TestTools.checkCollection( rev5.getReferencing(), ing2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -192,9 +192,9 @@ public class BasicList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListOwningEntity rev5 = getAuditReader().find( ListOwningEntity.class, ing1_id, 5 );
|
||||
|
||||
assert rev1.getReferences().equals( Collections.EMPTY_LIST );
|
||||
assert TestTools.checkList( rev2.getReferences(), ed1 );
|
||||
assert TestTools.checkList( rev3.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkList( rev4.getReferences(), ed2 );
|
||||
assert TestTools.checkCollection( rev2.getReferences(), ed1 );
|
||||
assert TestTools.checkCollection( rev3.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev4.getReferences(), ed2 );
|
||||
assert rev5.getReferences().equals( Collections.EMPTY_LIST );
|
||||
}
|
||||
|
||||
|
@ -210,9 +210,9 @@ public class BasicList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListOwningEntity rev5 = getAuditReader().find( ListOwningEntity.class, ing2_id, 5 );
|
||||
|
||||
assert rev1.getReferences().equals( Collections.EMPTY_LIST );
|
||||
assert TestTools.checkList( rev2.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkList( rev3.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkList( rev4.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkList( rev5.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev2.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev3.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev4.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev5.getReferences(), ed1, ed2 );
|
||||
}
|
||||
}
|
|
@ -150,16 +150,16 @@ public class BasicWhereJoinTable extends BaseEnversJPAFunctionalTestCase {
|
|||
WhereJoinTableEntity rev4 = getAuditReader().find( WhereJoinTableEntity.class, wjte1_id, 4 );
|
||||
|
||||
// Checking 1st list
|
||||
assert TestTools.checkList( rev1.getReferences1() );
|
||||
assert TestTools.checkList( rev2.getReferences1(), ite1_1 );
|
||||
assert TestTools.checkList( rev3.getReferences1(), ite1_1 );
|
||||
assert TestTools.checkList( rev4.getReferences1() );
|
||||
assert TestTools.checkCollection( rev1.getReferences1() );
|
||||
assert TestTools.checkCollection( rev2.getReferences1(), ite1_1 );
|
||||
assert TestTools.checkCollection( rev3.getReferences1(), ite1_1 );
|
||||
assert TestTools.checkCollection( rev4.getReferences1() );
|
||||
|
||||
// Checking 2nd list
|
||||
assert TestTools.checkList( rev1.getReferences2() );
|
||||
assert TestTools.checkList( rev2.getReferences2(), ite2_1 );
|
||||
assert TestTools.checkList( rev3.getReferences2(), ite2_1 );
|
||||
assert TestTools.checkList( rev4.getReferences2(), ite2_1 );
|
||||
assert TestTools.checkCollection( rev1.getReferences2() );
|
||||
assert TestTools.checkCollection( rev2.getReferences2(), ite2_1 );
|
||||
assert TestTools.checkCollection( rev3.getReferences2(), ite2_1 );
|
||||
assert TestTools.checkCollection( rev4.getReferences2(), ite2_1 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -174,15 +174,15 @@ public class BasicWhereJoinTable extends BaseEnversJPAFunctionalTestCase {
|
|||
WhereJoinTableEntity rev4 = getAuditReader().find( WhereJoinTableEntity.class, wjte2_id, 4 );
|
||||
|
||||
// Checking 1st list
|
||||
assert TestTools.checkList( rev1.getReferences1() );
|
||||
assert TestTools.checkList( rev2.getReferences1() );
|
||||
assert TestTools.checkList( rev3.getReferences1(), ite1_1, ite1_2 );
|
||||
assert TestTools.checkList( rev4.getReferences1(), ite1_1, ite1_2 );
|
||||
assert TestTools.checkCollection( rev1.getReferences1() );
|
||||
assert TestTools.checkCollection( rev2.getReferences1() );
|
||||
assert TestTools.checkCollection( rev3.getReferences1(), ite1_1, ite1_2 );
|
||||
assert TestTools.checkCollection( rev4.getReferences1(), ite1_1, ite1_2 );
|
||||
|
||||
// Checking 2nd list
|
||||
assert TestTools.checkList( rev1.getReferences2() );
|
||||
assert TestTools.checkList( rev2.getReferences2() );
|
||||
assert TestTools.checkList( rev3.getReferences2() );
|
||||
assert TestTools.checkList( rev4.getReferences2(), ite2_2 );
|
||||
assert TestTools.checkCollection( rev1.getReferences2() );
|
||||
assert TestTools.checkCollection( rev2.getReferences2() );
|
||||
assert TestTools.checkCollection( rev3.getReferences2() );
|
||||
assert TestTools.checkCollection( rev4.getReferences2(), ite2_2 );
|
||||
}
|
||||
}
|
|
@ -163,11 +163,11 @@ public class BasicBiowned extends BaseEnversJPAFunctionalTestCase {
|
|||
ListBiowning1Entity rev4 = getAuditReader().find( ListBiowning1Entity.class, o1_1_id, 4 );
|
||||
ListBiowning1Entity rev5 = getAuditReader().find( ListBiowning1Entity.class, o1_1_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getReferences() );
|
||||
assert TestTools.checkList( rev2.getReferences(), o2_1 );
|
||||
assert TestTools.checkList( rev3.getReferences(), o2_1, o2_2 );
|
||||
assert TestTools.checkList( rev4.getReferences() );
|
||||
assert TestTools.checkList( rev5.getReferences(), o2_2 );
|
||||
assert TestTools.checkCollection( rev1.getReferences() );
|
||||
assert TestTools.checkCollection( rev2.getReferences(), o2_1 );
|
||||
assert TestTools.checkCollection( rev3.getReferences(), o2_1, o2_2 );
|
||||
assert TestTools.checkCollection( rev4.getReferences() );
|
||||
assert TestTools.checkCollection( rev5.getReferences(), o2_2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -181,12 +181,11 @@ public class BasicBiowned extends BaseEnversJPAFunctionalTestCase {
|
|||
ListBiowning1Entity rev4 = getAuditReader().find( ListBiowning1Entity.class, o1_2_id, 4 );
|
||||
ListBiowning1Entity rev5 = getAuditReader().find( ListBiowning1Entity.class, o1_2_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getReferences() );
|
||||
assert TestTools.checkList( rev2.getReferences(), o2_2 );
|
||||
assert TestTools.checkList( rev3.getReferences(), o2_2 );
|
||||
assert TestTools.checkList( rev4.getReferences(), o2_1, o2_2 );
|
||||
System.out.println( "rev5.getReferences() = " + rev5.getReferences() );
|
||||
assert TestTools.checkList( rev5.getReferences(), o2_2 );
|
||||
assert TestTools.checkCollection( rev1.getReferences() );
|
||||
assert TestTools.checkCollection( rev2.getReferences(), o2_2 );
|
||||
assert TestTools.checkCollection( rev3.getReferences(), o2_2 );
|
||||
assert TestTools.checkCollection( rev4.getReferences(), o2_1, o2_2 );
|
||||
assert TestTools.checkCollection( rev5.getReferences(), o2_2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -200,11 +199,11 @@ public class BasicBiowned extends BaseEnversJPAFunctionalTestCase {
|
|||
ListBiowning2Entity rev4 = getAuditReader().find( ListBiowning2Entity.class, o2_1_id, 4 );
|
||||
ListBiowning2Entity rev5 = getAuditReader().find( ListBiowning2Entity.class, o2_1_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getReferences() );
|
||||
assert TestTools.checkList( rev2.getReferences(), o1_1 );
|
||||
assert TestTools.checkList( rev3.getReferences(), o1_1 );
|
||||
assert TestTools.checkList( rev4.getReferences(), o1_2 );
|
||||
assert TestTools.checkList( rev5.getReferences() );
|
||||
assert TestTools.checkCollection( rev1.getReferences() );
|
||||
assert TestTools.checkCollection( rev2.getReferences(), o1_1 );
|
||||
assert TestTools.checkCollection( rev3.getReferences(), o1_1 );
|
||||
assert TestTools.checkCollection( rev4.getReferences(), o1_2 );
|
||||
assert TestTools.checkCollection( rev5.getReferences() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -218,10 +217,10 @@ public class BasicBiowned extends BaseEnversJPAFunctionalTestCase {
|
|||
ListBiowning2Entity rev4 = getAuditReader().find( ListBiowning2Entity.class, o2_2_id, 4 );
|
||||
ListBiowning2Entity rev5 = getAuditReader().find( ListBiowning2Entity.class, o2_2_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getReferences() );
|
||||
assert TestTools.checkList( rev2.getReferences(), o1_2 );
|
||||
assert TestTools.checkList( rev3.getReferences(), o1_1, o1_2 );
|
||||
assert TestTools.checkList( rev4.getReferences(), o1_2 );
|
||||
assert TestTools.checkList( rev5.getReferences(), o1_1, o1_2 );
|
||||
assert TestTools.checkCollection( rev1.getReferences() );
|
||||
assert TestTools.checkCollection( rev2.getReferences(), o1_2 );
|
||||
assert TestTools.checkCollection( rev3.getReferences(), o1_1, o1_2 );
|
||||
assert TestTools.checkCollection( rev4.getReferences(), o1_2 );
|
||||
assert TestTools.checkCollection( rev5.getReferences(), o1_1, o1_2 );
|
||||
}
|
||||
}
|
|
@ -199,17 +199,17 @@ public class BasicSametable extends BaseEnversJPAFunctionalTestCase {
|
|||
ParentEntity rev4 = getAuditReader().find( ParentEntity.class, p1_id, 4 );
|
||||
ParentEntity rev5 = getAuditReader().find( ParentEntity.class, p1_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren1() );
|
||||
assert TestTools.checkList( rev2.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev3.getChildren1(), c1_1, c1_2 );
|
||||
assert TestTools.checkList( rev4.getChildren1(), c1_2 );
|
||||
assert TestTools.checkList( rev5.getChildren1() );
|
||||
assert TestTools.checkCollection( rev1.getChildren1() );
|
||||
assert TestTools.checkCollection( rev2.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev3.getChildren1(), c1_1, c1_2 );
|
||||
assert TestTools.checkCollection( rev4.getChildren1(), c1_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren1() );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren2() );
|
||||
assert TestTools.checkList( rev2.getChildren2() );
|
||||
assert TestTools.checkList( rev3.getChildren2(), c2_2 );
|
||||
assert TestTools.checkList( rev4.getChildren2(), c2_2 );
|
||||
assert TestTools.checkList( rev5.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev1.getChildren2() );
|
||||
assert TestTools.checkCollection( rev2.getChildren2() );
|
||||
assert TestTools.checkCollection( rev3.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev4.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren2(), c2_2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -224,17 +224,17 @@ public class BasicSametable extends BaseEnversJPAFunctionalTestCase {
|
|||
ParentEntity rev4 = getAuditReader().find( ParentEntity.class, p2_id, 4 );
|
||||
ParentEntity rev5 = getAuditReader().find( ParentEntity.class, p2_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren1() );
|
||||
assert TestTools.checkList( rev2.getChildren1() );
|
||||
assert TestTools.checkList( rev3.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev4.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev5.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev1.getChildren1() );
|
||||
assert TestTools.checkCollection( rev2.getChildren1() );
|
||||
assert TestTools.checkCollection( rev3.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev4.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev5.getChildren1(), c1_1 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren2() );
|
||||
assert TestTools.checkList( rev2.getChildren2(), c2_1 );
|
||||
assert TestTools.checkList( rev3.getChildren2(), c2_1 );
|
||||
assert TestTools.checkList( rev4.getChildren2(), c2_1, c2_2 );
|
||||
assert TestTools.checkList( rev5.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev1.getChildren2() );
|
||||
assert TestTools.checkCollection( rev2.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev3.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev4.getChildren2(), c2_1, c2_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren2(), c2_1 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -248,11 +248,11 @@ public class BasicSametable extends BaseEnversJPAFunctionalTestCase {
|
|||
Child1Entity rev4 = getAuditReader().find( Child1Entity.class, c1_1_id, 4 );
|
||||
Child1Entity rev5 = getAuditReader().find( Child1Entity.class, c1_1_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents(), p1 );
|
||||
assert TestTools.checkList( rev3.getParents(), p1, p2 );
|
||||
assert TestTools.checkList( rev4.getParents(), p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1, p2 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p2 );
|
||||
}
|
||||
|
||||
// TODO: was disabled?
|
||||
|
@ -266,11 +266,11 @@ public class BasicSametable extends BaseEnversJPAFunctionalTestCase {
|
|||
Child1Entity rev4 = getAuditReader().find( Child1Entity.class, c1_2_id, 4 );
|
||||
Child1Entity rev5 = getAuditReader().find( Child1Entity.class, c1_2_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents() );
|
||||
assert TestTools.checkList( rev3.getParents(), p1 );
|
||||
assert TestTools.checkList( rev4.getParents(), p1 );
|
||||
assert TestTools.checkList( rev5.getParents() );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents() );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev5.getParents() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -283,11 +283,11 @@ public class BasicSametable extends BaseEnversJPAFunctionalTestCase {
|
|||
Child2Entity rev4 = getAuditReader().find( Child2Entity.class, c2_1_id, 4 );
|
||||
Child2Entity rev5 = getAuditReader().find( Child2Entity.class, c2_1_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents(), p2 );
|
||||
assert TestTools.checkList( rev3.getParents(), p2 );
|
||||
assert TestTools.checkList( rev4.getParents(), p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -301,10 +301,10 @@ public class BasicSametable extends BaseEnversJPAFunctionalTestCase {
|
|||
Child2Entity rev4 = getAuditReader().find( Child2Entity.class, c2_2_id, 4 );
|
||||
Child2Entity rev5 = getAuditReader().find( Child2Entity.class, c2_2_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents() );
|
||||
assert TestTools.checkList( rev3.getParents(), p1 );
|
||||
assert TestTools.checkList( rev4.getParents(), p1, p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents() );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p1, p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p1 );
|
||||
}
|
||||
}
|
|
@ -151,9 +151,9 @@ public class BasicUniList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListUniEntity rev5 = getAuditReader().find( ListUniEntity.class, ing1_id, 5 );
|
||||
|
||||
assert rev1.getReferences().equals( Collections.EMPTY_LIST );
|
||||
assert TestTools.checkList( rev2.getReferences(), ed1 );
|
||||
assert TestTools.checkList( rev3.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkList( rev4.getReferences(), ed2 );
|
||||
assert TestTools.checkCollection( rev2.getReferences(), ed1 );
|
||||
assert TestTools.checkCollection( rev3.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev4.getReferences(), ed2 );
|
||||
assert rev5.getReferences().equals( Collections.EMPTY_LIST );
|
||||
}
|
||||
|
||||
|
@ -169,9 +169,9 @@ public class BasicUniList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListUniEntity rev5 = getAuditReader().find( ListUniEntity.class, ing2_id, 5 );
|
||||
|
||||
assert rev1.getReferences().equals( Collections.EMPTY_LIST );
|
||||
assert TestTools.checkList( rev2.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkList( rev3.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkList( rev4.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkList( rev5.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev2.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev3.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev4.getReferences(), ed1, ed2 );
|
||||
assert TestTools.checkCollection( rev5.getReferences(), ed1, ed2 );
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import org.hibernate.envers.test.entities.manytomany.unidirectional.M2MIndexedLi
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkList;
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkCollection;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -114,9 +114,9 @@ public class M2MIndexedListNotAuditedTarget extends BaseEnversJPAFunctionalTestC
|
|||
3
|
||||
);
|
||||
|
||||
assertTrue( checkList( rev1.getReferences(), uste1, uste2 ) );
|
||||
assertTrue( checkList( rev2.getReferences(), uste1, uste2 ) );
|
||||
assertTrue( checkList( rev3.getReferences(), uste2, uste1 ) );
|
||||
assertTrue( checkCollection( rev1.getReferences(), uste1, uste2 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences(), uste1, uste2 ) );
|
||||
assertTrue( checkCollection( rev3.getReferences(), uste2, uste1 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -138,7 +138,7 @@ public class M2MIndexedListNotAuditedTarget extends BaseEnversJPAFunctionalTestC
|
|||
);
|
||||
|
||||
assertNull( rev1 );
|
||||
assertTrue( checkList( rev2.getReferences(), uste2 ) );
|
||||
assertTrue( checkList( rev3.getReferences(), uste2 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences(), uste2 ) );
|
||||
assertTrue( checkCollection( rev3.getReferences(), uste2 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.hibernate.envers.test.entities.manytomany.unidirectional.M2MTargetNot
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkList;
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkCollection;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -153,10 +153,10 @@ public class M2MRelationNotAuditedTarget extends BaseEnversJPAFunctionalTestCase
|
|||
M2MTargetNotAuditedEntity rev3 = getAuditReader().find( M2MTargetNotAuditedEntity.class, tnae1_id, 3 );
|
||||
M2MTargetNotAuditedEntity rev4 = getAuditReader().find( M2MTargetNotAuditedEntity.class, tnae1_id, 4 );
|
||||
|
||||
assertTrue( checkList( rev1.getReferences() ) );
|
||||
assertTrue( checkList( rev2.getReferences(), uste1 ) );
|
||||
assertTrue( checkList( rev3.getReferences(), uste1 ) );
|
||||
assertTrue( checkList( rev4.getReferences(), uste1, uste2 ) );
|
||||
assertTrue( checkCollection( rev1.getReferences() ) );
|
||||
assertTrue( checkCollection( rev2.getReferences(), uste1 ) );
|
||||
assertTrue( checkCollection( rev3.getReferences(), uste1 ) );
|
||||
assertTrue( checkCollection( rev4.getReferences(), uste1, uste2 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -169,9 +169,9 @@ public class M2MRelationNotAuditedTarget extends BaseEnversJPAFunctionalTestCase
|
|||
M2MTargetNotAuditedEntity rev3 = getAuditReader().find( M2MTargetNotAuditedEntity.class, tnae2_id, 3 );
|
||||
M2MTargetNotAuditedEntity rev4 = getAuditReader().find( M2MTargetNotAuditedEntity.class, tnae2_id, 4 );
|
||||
|
||||
assertTrue( checkList( rev1.getReferences(), uste1, uste2 ) );
|
||||
assertTrue( checkList( rev2.getReferences(), uste2 ) );
|
||||
assertTrue( checkList( rev3.getReferences() ) );
|
||||
assertTrue( checkList( rev4.getReferences(), uste1 ) );
|
||||
assertTrue( checkCollection( rev1.getReferences(), uste1, uste2 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences(), uste2 ) );
|
||||
assertTrue( checkCollection( rev3.getReferences() ) );
|
||||
assertTrue( checkCollection( rev4.getReferences(), uste1 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,9 +118,9 @@ public class BasicList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListRefEdEntity rev2 = getAuditReader().find( ListRefEdEntity.class, ed1_id, 2 );
|
||||
ListRefEdEntity rev3 = getAuditReader().find( ListRefEdEntity.class, ed1_id, 3 );
|
||||
|
||||
assert TestTools.checkList( rev1.getReffering(), ing1, ing2 );
|
||||
assert TestTools.checkList( rev2.getReffering(), ing2 );
|
||||
assert TestTools.checkList( rev3.getReffering() );
|
||||
assert TestTools.checkCollection( rev1.getReffering(), ing1, ing2 );
|
||||
assert TestTools.checkCollection( rev2.getReffering(), ing2 );
|
||||
assert TestTools.checkCollection( rev3.getReffering() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -132,9 +132,9 @@ public class BasicList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListRefEdEntity rev2 = getAuditReader().find( ListRefEdEntity.class, ed2_id, 2 );
|
||||
ListRefEdEntity rev3 = getAuditReader().find( ListRefEdEntity.class, ed2_id, 3 );
|
||||
|
||||
assert TestTools.checkList( rev1.getReffering() );
|
||||
assert TestTools.checkList( rev2.getReffering(), ing1 );
|
||||
assert TestTools.checkList( rev3.getReffering(), ing1, ing2 );
|
||||
assert TestTools.checkCollection( rev1.getReffering() );
|
||||
assert TestTools.checkCollection( rev2.getReffering(), ing1 );
|
||||
assert TestTools.checkCollection( rev3.getReffering(), ing1, ing2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -126,10 +126,10 @@ public class BasicDetachedList extends BaseEnversJPAFunctionalTestCase {
|
|||
ListRefCollEntity rev3 = getAuditReader().find( ListRefCollEntity.class, coll1_id, 3 );
|
||||
ListRefCollEntity rev4 = getAuditReader().find( ListRefCollEntity.class, coll1_id, 4 );
|
||||
|
||||
assert TestTools.checkList( rev1.getCollection(), str1 );
|
||||
assert TestTools.checkList( rev2.getCollection(), str1, str2 );
|
||||
assert TestTools.checkList( rev3.getCollection(), str2 );
|
||||
assert TestTools.checkList( rev4.getCollection() );
|
||||
assert TestTools.checkCollection( rev1.getCollection(), str1 );
|
||||
assert TestTools.checkCollection( rev2.getCollection(), str1, str2 );
|
||||
assert TestTools.checkCollection( rev3.getCollection(), str2 );
|
||||
assert TestTools.checkCollection( rev4.getCollection() );
|
||||
|
||||
assert "coll1".equals( rev1.getData() );
|
||||
assert "coll1".equals( rev2.getData() );
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.hibernate.envers.test.entities.onetomany.detached.DoubleListJoinColum
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkList;
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkCollection;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
@ -266,15 +266,15 @@ public class DoubleJoinColumnBidirectionalList extends BaseEnversJPAFunctionalTe
|
|||
4
|
||||
);
|
||||
|
||||
assertTrue( checkList( rev1.getReferences1(), ed1_1_fromRev1 ) );
|
||||
assertTrue( checkList( rev2.getReferences1(), ed1_1_fromRev1, ed1_2 ) );
|
||||
assertTrue( checkList( rev3.getReferences1(), ed1_1_fromRev3, ed1_2 ) );
|
||||
assertTrue( checkList( rev4.getReferences1() ) );
|
||||
assertTrue( checkCollection( rev1.getReferences1(), ed1_1_fromRev1 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences1(), ed1_1_fromRev1, ed1_2 ) );
|
||||
assertTrue( checkCollection( rev3.getReferences1(), ed1_1_fromRev3, ed1_2 ) );
|
||||
assertTrue( checkCollection( rev4.getReferences1() ) );
|
||||
|
||||
assertTrue( checkList( rev1.getReferences2(), ed2_1 ) );
|
||||
assertTrue( checkList( rev2.getReferences2(), ed2_1, ed2_2_fromRev1 ) );
|
||||
assertTrue( checkList( rev3.getReferences2(), ed2_1, ed2_2_fromRev3 ) );
|
||||
assertTrue( checkList( rev4.getReferences2(), ed2_2_fromRev3 ) );
|
||||
assertTrue( checkCollection( rev1.getReferences2(), ed2_1 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences2(), ed2_1, ed2_2_fromRev1 ) );
|
||||
assertTrue( checkCollection( rev3.getReferences2(), ed2_1, ed2_2_fromRev3 ) );
|
||||
assertTrue( checkCollection( rev4.getReferences2(), ed2_2_fromRev3 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -319,15 +319,15 @@ public class DoubleJoinColumnBidirectionalList extends BaseEnversJPAFunctionalTe
|
|||
4
|
||||
);
|
||||
|
||||
assertTrue( checkList( rev1.getReferences1(), ed1_2 ) );
|
||||
assertTrue( checkList( rev2.getReferences1() ) );
|
||||
assertTrue( checkList( rev3.getReferences1() ) );
|
||||
assertTrue( checkList( rev4.getReferences1(), ed1_1_fromRev3, ed1_2 ) );
|
||||
assertTrue( checkCollection( rev1.getReferences1(), ed1_2 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences1() ) );
|
||||
assertTrue( checkCollection( rev3.getReferences1() ) );
|
||||
assertTrue( checkCollection( rev4.getReferences1(), ed1_1_fromRev3, ed1_2 ) );
|
||||
|
||||
assertTrue( checkList( rev1.getReferences2(), ed2_2_fromRev1 ) );
|
||||
assertTrue( checkList( rev2.getReferences2() ) );
|
||||
assertTrue( checkList( rev3.getReferences2() ) );
|
||||
assertTrue( checkList( rev4.getReferences2(), ed2_1 ) );
|
||||
assertTrue( checkCollection( rev1.getReferences2(), ed2_2_fromRev1 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences2() ) );
|
||||
assertTrue( checkCollection( rev3.getReferences2() ) );
|
||||
assertTrue( checkCollection( rev4.getReferences2(), ed2_1 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.hibernate.envers.test.entities.onetomany.detached.ListJoinColumnBidir
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkList;
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkCollection;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
@ -199,10 +199,10 @@ public class JoinColumnBidirectionalList extends BaseEnversJPAFunctionalTestCase
|
|||
4
|
||||
);
|
||||
|
||||
assertTrue( checkList( rev1.getReferences(), ed1_fromRev1 ) );
|
||||
assertTrue( checkList( rev2.getReferences(), ed1_fromRev1, ed2 ) );
|
||||
assertTrue( checkList( rev3.getReferences(), ed1_fromRev3, ed2 ) );
|
||||
assertTrue( checkList( rev4.getReferences() ) );
|
||||
assertTrue( checkCollection( rev1.getReferences(), ed1_fromRev1 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences(), ed1_fromRev1, ed2 ) );
|
||||
assertTrue( checkCollection( rev3.getReferences(), ed1_fromRev3, ed2 ) );
|
||||
assertTrue( checkCollection( rev4.getReferences() ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -237,10 +237,10 @@ public class JoinColumnBidirectionalList extends BaseEnversJPAFunctionalTestCase
|
|||
4
|
||||
);
|
||||
|
||||
assertTrue( checkList( rev1.getReferences(), ed2 ) );
|
||||
assertTrue( checkList( rev2.getReferences() ) );
|
||||
assertTrue( checkList( rev3.getReferences() ) );
|
||||
assertTrue( checkList( rev4.getReferences(), ed1, ed2 ) );
|
||||
assertTrue( checkCollection( rev1.getReferences(), ed2 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences() ) );
|
||||
assertTrue( checkCollection( rev3.getReferences() ) );
|
||||
assertTrue( checkCollection( rev4.getReferences(), ed1, ed2 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.hibernate.envers.test.entities.onetomany.detached.ListJoinColumnBidir
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkList;
|
||||
import static org.hibernate.envers.test.tools.TestTools.checkCollection;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
@ -169,8 +169,8 @@ public class JoinColumnBidirectionalListWithInheritance extends BaseEnversJPAFun
|
|||
2
|
||||
);
|
||||
|
||||
assertTrue( checkList( rev1.getReferences(), ed1 ) );
|
||||
assertTrue( checkList( rev2.getReferences(), ed1, ed2 ) );
|
||||
assertTrue( checkCollection( rev1.getReferences(), ed1 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences(), ed1, ed2 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -191,8 +191,8 @@ public class JoinColumnBidirectionalListWithInheritance extends BaseEnversJPAFun
|
|||
2
|
||||
);
|
||||
|
||||
assertTrue( checkList( rev1.getReferences(), ed2 ) );
|
||||
assertTrue( checkList( rev2.getReferences() ) );
|
||||
assertTrue( checkCollection( rev1.getReferences(), ed2 ) );
|
||||
assertTrue( checkCollection( rev2.getReferences() ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -75,17 +75,17 @@ public class HierarchyTest extends BaseEnversJPAFunctionalTestCase {
|
|||
|
||||
Node ver1 = getAuditReader().find( Node.class, parentId, 1 );
|
||||
Assert.assertEquals( parent, ver1 );
|
||||
Assert.assertTrue( TestTools.checkList( ver1.getChildren(), child1, child2 ) );
|
||||
Assert.assertTrue( TestTools.checkCollection( ver1.getChildren(), child1, child2 ) );
|
||||
|
||||
child1.setData( "child1 modified" );
|
||||
|
||||
Node ver2 = getAuditReader().find( Node.class, parentId, 2 );
|
||||
Assert.assertEquals( parent, ver2 );
|
||||
Assert.assertTrue( TestTools.checkList( ver2.getChildren(), child1, child2 ) );
|
||||
Assert.assertTrue( TestTools.checkCollection( ver2.getChildren(), child1, child2 ) );
|
||||
|
||||
Node ver3 = getAuditReader().find( Node.class, parentId, 3 );
|
||||
Assert.assertEquals( parent, ver3 );
|
||||
Assert.assertTrue( TestTools.checkList( ver3.getChildren(), child1 ) );
|
||||
Assert.assertTrue( TestTools.checkCollection( ver3.getChildren(), child1 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.hibernate.envers.test.integration.proxy;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -17,9 +18,13 @@ import org.hibernate.envers.test.entities.IntTestPrivSeqEntity;
|
|||
import org.hibernate.envers.test.entities.StrTestPrivSeqEntity;
|
||||
import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
|
||||
import org.hibernate.envers.test.entities.collection.StringSetEntity;
|
||||
import org.hibernate.envers.test.entities.manytomany.ListOwnedEntity;
|
||||
import org.hibernate.envers.test.entities.manytomany.ListOwningEntity;
|
||||
import org.hibernate.envers.test.entities.manytomany.SetOwnedEntity;
|
||||
import org.hibernate.envers.test.entities.manytomany.SetOwningEntity;
|
||||
import org.hibernate.envers.test.entities.manytomany.unidirectional.M2MIndexedListTargetNotAuditedEntity;
|
||||
import org.hibernate.envers.test.entities.onetomany.CollectionRefEdEntity;
|
||||
import org.hibernate.envers.test.entities.onetomany.CollectionRefIngEntity;
|
||||
import org.hibernate.envers.test.entities.onetomany.SetRefEdEntity;
|
||||
import org.hibernate.envers.test.entities.onetomany.SetRefIngEntity;
|
||||
import org.hibernate.envers.test.integration.manytomany.ternary.TernaryMapEntity;
|
||||
|
@ -55,7 +60,8 @@ public class RemovedObjectQueryTest extends BaseEnversJPAFunctionalTestCase {
|
|||
return new Class<?>[] {
|
||||
SetRefEdEntity.class, SetRefIngEntity.class, SetOwnedEntity.class, SetOwningEntity.class,
|
||||
StringSetEntity.class, UnversionedStrTestEntity.class, M2MIndexedListTargetNotAuditedEntity.class,
|
||||
TernaryMapEntity.class, StrTestPrivSeqEntity.class, IntTestPrivSeqEntity.class
|
||||
TernaryMapEntity.class, StrTestPrivSeqEntity.class, IntTestPrivSeqEntity.class,
|
||||
CollectionRefEdEntity.class, CollectionRefIngEntity.class, ListOwnedEntity.class, ListOwningEntity.class
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -212,30 +218,108 @@ public class RemovedObjectQueryTest extends BaseEnversJPAFunctionalTestCase {
|
|||
|
||||
ternaryMapId = mapEntity.getId();
|
||||
|
||||
// Revision 16 - removing ternary map
|
||||
// Revision 16 - updating ternary map
|
||||
em.getTransaction().begin();
|
||||
intEntity2 = em.find( IntTestPrivSeqEntity.class, intEntity2.getId() );
|
||||
intEntity2.setNumber( 3 );
|
||||
intEntity2 = em.merge( intEntity2 );
|
||||
stringEntity2 = em.find( StrTestPrivSeqEntity.class, stringEntity2.getId() );
|
||||
stringEntity2.setStr( "Value 3" );
|
||||
stringEntity2 = em.merge( stringEntity2 );
|
||||
em.getTransaction().commit();
|
||||
|
||||
// Revision 17 - removing ternary map
|
||||
em.getTransaction().begin();
|
||||
mapEntity = em.find( TernaryMapEntity.class, mapEntity.getId() );
|
||||
em.remove( mapEntity );
|
||||
em.getTransaction().commit();
|
||||
|
||||
CollectionRefEdEntity collEd1 = new CollectionRefEdEntity( 1, "data_ed_1" );
|
||||
CollectionRefIngEntity collIng1 = new CollectionRefIngEntity( 2, "data_ing_1", collEd1 );
|
||||
collEd1.setReffering( new ArrayList<CollectionRefIngEntity>() );
|
||||
collEd1.getReffering().add( collIng1 );
|
||||
|
||||
// Revision 18 - testing one-to-many collection
|
||||
em.getTransaction().begin();
|
||||
em.persist( collEd1 );
|
||||
em.persist( collIng1 );
|
||||
em.getTransaction().commit();
|
||||
|
||||
// Revision 19
|
||||
em.getTransaction().begin();
|
||||
collIng1 = em.find( CollectionRefIngEntity.class, collIng1.getId() );
|
||||
collIng1.setData( "modified data_ing_1" );
|
||||
collIng1 = em.merge( collIng1 );
|
||||
em.getTransaction().commit();
|
||||
|
||||
// Revision 20
|
||||
em.getTransaction().begin();
|
||||
collEd1 = em.find( CollectionRefEdEntity.class, collEd1.getId() );
|
||||
collIng1 = em.find( CollectionRefIngEntity.class, collIng1.getId() );
|
||||
em.remove( collIng1 );
|
||||
em.remove( collEd1 );
|
||||
em.getTransaction().commit();
|
||||
|
||||
ListOwnedEntity listEd1 = new ListOwnedEntity( 1, "data_ed_1" );
|
||||
ListOwningEntity listIng1 = new ListOwningEntity( 2, "data_ing_1" );
|
||||
listEd1.setReferencing( new ArrayList<ListOwningEntity>() );
|
||||
listIng1.setReferences( new ArrayList<ListOwnedEntity>() );
|
||||
listEd1.getReferencing().add( listIng1 );
|
||||
listIng1.getReferences().add( listEd1 );
|
||||
|
||||
// Revision 21 - testing many-to-many collection
|
||||
em.getTransaction().begin();
|
||||
em.persist( listEd1 );
|
||||
em.persist( listIng1 );
|
||||
em.getTransaction().commit();
|
||||
|
||||
// Revision 22
|
||||
em.getTransaction().begin();
|
||||
listIng1 = em.find( ListOwningEntity.class, listIng1.getId() );
|
||||
listIng1.setData( "modified data_ing_1" );
|
||||
listIng1 = em.merge( listIng1 );
|
||||
em.getTransaction().commit();
|
||||
|
||||
// Revision 23
|
||||
em.getTransaction().begin();
|
||||
listIng1 = em.find( ListOwningEntity.class, listIng1.getId() );
|
||||
listEd1 = em.find( ListOwnedEntity.class, listEd1.getId() );
|
||||
em.remove( listIng1 );
|
||||
em.remove( listEd1 );
|
||||
em.getTransaction().commit();
|
||||
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTernaryMap() {
|
||||
final TernaryMapEntity ternaryMap = new TernaryMapEntity();
|
||||
ternaryMap.setId( ternaryMapId );
|
||||
ternaryMap.getMap().put( intEntity1, stringEntity1 );
|
||||
ternaryMap.getMap().put( new IntTestPrivSeqEntity( 2, intEntity2.getId() ) , new StrTestPrivSeqEntity( "Value 2", stringEntity2.getId() ) );
|
||||
|
||||
TernaryMapEntity entity = getAuditReader().find( TernaryMapEntity.class, ternaryMapId, 15 );
|
||||
|
||||
Assert.assertEquals( ternaryMap.getMap(), entity.getMap() );
|
||||
|
||||
ternaryMap.getMap().clear();
|
||||
ternaryMap.getMap().put( intEntity1, stringEntity1 );
|
||||
ternaryMap.getMap().put( intEntity2, stringEntity2 );
|
||||
|
||||
entity = getAuditReader().find( TernaryMapEntity.class, ternaryMapId, 16 );
|
||||
|
||||
Assert.assertEquals( ternaryMap.getMap(), entity.getMap() );
|
||||
|
||||
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( TernaryMapEntity.class, false, true )
|
||||
.add( AuditEntity.id().eq( ternaryMapId ) )
|
||||
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||
.getResultList();
|
||||
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||
|
||||
Assert.assertEquals( 16, getRevisionNumber( objArray[1] ) );
|
||||
Assert.assertEquals( 17, getRevisionNumber( objArray[1] ) );
|
||||
|
||||
TernaryMapEntity mapEntity = (TernaryMapEntity) objArray[0];
|
||||
Assert.assertEquals(
|
||||
TestTools.makeMap( intEntity1, stringEntity1, intEntity2, stringEntity2 ),
|
||||
mapEntity.getMap()
|
||||
);
|
||||
entity = (TernaryMapEntity) objArray[0];
|
||||
Assert.assertEquals( ternaryMap.getMap(), entity.getMap() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -251,7 +335,7 @@ public class RemovedObjectQueryTest extends BaseEnversJPAFunctionalTestCase {
|
|||
|
||||
M2MIndexedListTargetNotAuditedEntity relationNotAuditedEntity = (M2MIndexedListTargetNotAuditedEntity) objArray[0];
|
||||
Assert.assertTrue(
|
||||
TestTools.checkList(
|
||||
TestTools.checkCollection(
|
||||
relationNotAuditedEntity.getReferences(),
|
||||
unversionedEntity1, unversionedEntity2
|
||||
)
|
||||
|
@ -274,6 +358,34 @@ public class RemovedObjectQueryTest extends BaseEnversJPAFunctionalTestCase {
|
|||
|
||||
// One to many tests.
|
||||
|
||||
@Test
|
||||
public void testOneToManyCollectionSemantics() {
|
||||
final CollectionRefEdEntity edVer1 = new CollectionRefEdEntity( 1, "data_ed_1" );
|
||||
final CollectionRefIngEntity ingVer1 = new CollectionRefIngEntity( 2, "data_ing_1" );
|
||||
final CollectionRefIngEntity ingVer2 = new CollectionRefIngEntity( 2, "modified data_ing_1" );
|
||||
|
||||
CollectionRefEdEntity entity = getAuditReader().find( CollectionRefEdEntity.class, 1, 18 );
|
||||
|
||||
Assert.assertEquals( edVer1, entity );
|
||||
Assert.assertTrue( TestTools.checkCollection( entity.getReffering(), ingVer1 ) );
|
||||
|
||||
entity = getAuditReader().find( CollectionRefEdEntity.class, 1, 19 );
|
||||
|
||||
Assert.assertTrue( TestTools.checkCollection( entity.getReffering(), ingVer2 ) );
|
||||
|
||||
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( CollectionRefEdEntity.class, false, true )
|
||||
.add( AuditEntity.id().eq( 1 ) )
|
||||
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||
.getResultList();
|
||||
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||
|
||||
Assert.assertEquals( 20, getRevisionNumber( objArray[1] ) );
|
||||
|
||||
entity = (CollectionRefEdEntity) objArray[0];
|
||||
Assert.assertEquals( "data_ed_1", entity.getData() );
|
||||
Assert.assertTrue( TestTools.checkCollection( entity.getReffering(), ingVer2 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReferencedOneToManySameRevision() {
|
||||
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetRefIngEntity.class, false, true )
|
||||
|
@ -360,6 +472,34 @@ public class RemovedObjectQueryTest extends BaseEnversJPAFunctionalTestCase {
|
|||
|
||||
// Many to many tests.
|
||||
|
||||
@Test
|
||||
public void testManyToManyCollectionSemantics() {
|
||||
final ListOwnedEntity edVer1 = new ListOwnedEntity( 1, "data_ed_1" );
|
||||
final ListOwningEntity ingVer1 = new ListOwningEntity( 2, "data_ing_1" );
|
||||
final ListOwningEntity ingVer2 = new ListOwningEntity( 2, "modified data_ing_1" );
|
||||
|
||||
ListOwnedEntity entity = getAuditReader().find( ListOwnedEntity.class, 1, 21 );
|
||||
|
||||
Assert.assertEquals( edVer1, entity );
|
||||
Assert.assertTrue( TestTools.checkCollection( entity.getReferencing(), ingVer1 ) );
|
||||
|
||||
entity = getAuditReader().find( ListOwnedEntity.class, 1, 22 );
|
||||
|
||||
Assert.assertTrue( TestTools.checkCollection( entity.getReferencing(), ingVer2 ) );
|
||||
|
||||
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( ListOwnedEntity.class, false, true )
|
||||
.add( AuditEntity.id().eq( 1 ) )
|
||||
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||
.getResultList();
|
||||
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||
|
||||
Assert.assertEquals( 23, getRevisionNumber( objArray[1] ) );
|
||||
|
||||
entity = (ListOwnedEntity) objArray[0];
|
||||
Assert.assertEquals( "data_ed_1", entity.getData() );
|
||||
Assert.assertTrue( TestTools.checkCollection( entity.getReferencing(), ingVer2 ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnedManyToManySameRevision() {
|
||||
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetOwningEntity.class, false, true )
|
||||
|
|
|
@ -134,7 +134,7 @@ public class AggregateQuery extends BaseEnversJPAFunctionalTestCase {
|
|||
.add( AuditEntity.id().between( 2, 3 ) )
|
||||
.getResultList();
|
||||
Assert.assertTrue(
|
||||
TestTools.checkList(
|
||||
TestTools.checkCollection(
|
||||
list,
|
||||
new IntTestEntity( 10, 2 ), new IntTestEntity( 8, 3 ), new IntTestEntity( 52, 2 )
|
||||
)
|
||||
|
|
|
@ -311,7 +311,7 @@ public class SimpleQuery extends BaseEnversJPAFunctionalTestCase {
|
|||
.addProjection( AuditEntity.revisionType() ).add( AuditEntity.id().eq( id1 ) )
|
||||
.getSingleResult();
|
||||
|
||||
Assert.assertTrue( TestTools.checkList( result, site1, site2, site3 ) );
|
||||
Assert.assertTrue( TestTools.checkCollection( result, site1, site2, site3 ) );
|
||||
Assert.assertEquals( revisionType, RevisionType.ADD );
|
||||
}
|
||||
|
||||
|
@ -330,7 +330,7 @@ public class SimpleQuery extends BaseEnversJPAFunctionalTestCase {
|
|||
.addProjection( AuditEntity.revisionType() ).add( AuditEntity.id().eq( id1 ) )
|
||||
.getSingleResult();
|
||||
|
||||
Assert.assertTrue( TestTools.checkList( result, site1, site2 ) );
|
||||
Assert.assertTrue( TestTools.checkCollection( result, site1, site2 ) );
|
||||
Assert.assertEquals( revisionType, RevisionType.MOD );
|
||||
}
|
||||
|
||||
|
@ -348,7 +348,7 @@ public class SimpleQuery extends BaseEnversJPAFunctionalTestCase {
|
|||
.addProjection( AuditEntity.revisionType() ).add( AuditEntity.id().eq( id1 ) )
|
||||
.getSingleResult();
|
||||
|
||||
Assert.assertTrue( TestTools.checkList( result, site1 ) );
|
||||
Assert.assertTrue( TestTools.checkCollection( result, site1 ) );
|
||||
Assert.assertEquals( revisionType, RevisionType.DEL );
|
||||
}
|
||||
|
||||
|
|
|
@ -91,14 +91,14 @@ public class DefaultTrackingEntitiesTest extends BaseEnversJPAFunctionalTestCase
|
|||
StrTestEntity ste = new StrTestEntity( "x", steId );
|
||||
StrIntTestEntity site = new StrIntTestEntity( "y", 1, siteId );
|
||||
|
||||
assert TestTools.checkList( getCrossTypeRevisionChangesReader().findEntities( 1 ), ste, site );
|
||||
assert TestTools.checkCollection( getCrossTypeRevisionChangesReader().findEntities( 1 ), ste, site );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrackModifiedEntities() {
|
||||
StrIntTestEntity site = new StrIntTestEntity( "y", 2, siteId );
|
||||
|
||||
assert TestTools.checkList( getCrossTypeRevisionChangesReader().findEntities( 2 ), site );
|
||||
assert TestTools.checkCollection( getCrossTypeRevisionChangesReader().findEntities( 2 ), site );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -106,7 +106,7 @@ public class DefaultTrackingEntitiesTest extends BaseEnversJPAFunctionalTestCase
|
|||
StrTestEntity ste = new StrTestEntity( null, steId );
|
||||
StrIntTestEntity site = new StrIntTestEntity( null, null, siteId );
|
||||
|
||||
assert TestTools.checkList( getCrossTypeRevisionChangesReader().findEntities( 3 ), site, ste );
|
||||
assert TestTools.checkCollection( getCrossTypeRevisionChangesReader().findEntities( 3 ), site, ste );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -120,9 +120,9 @@ public class DefaultTrackingEntitiesTest extends BaseEnversJPAFunctionalTestCase
|
|||
StrIntTestEntity site = new StrIntTestEntity( "y", 1, siteId );
|
||||
|
||||
Map<RevisionType, List<Object>> result = getCrossTypeRevisionChangesReader().findEntitiesGroupByRevisionType( 1 );
|
||||
assert TestTools.checkList( result.get( RevisionType.ADD ), site, ste );
|
||||
assert TestTools.checkList( result.get( RevisionType.MOD ) );
|
||||
assert TestTools.checkList( result.get( RevisionType.DEL ) );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.ADD ), site, ste );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.MOD ) );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.DEL ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -130,9 +130,9 @@ public class DefaultTrackingEntitiesTest extends BaseEnversJPAFunctionalTestCase
|
|||
StrIntTestEntity site = new StrIntTestEntity( "y", 2, siteId );
|
||||
|
||||
Map<RevisionType, List<Object>> result = getCrossTypeRevisionChangesReader().findEntitiesGroupByRevisionType( 2 );
|
||||
assert TestTools.checkList( result.get( RevisionType.ADD ) );
|
||||
assert TestTools.checkList( result.get( RevisionType.MOD ), site );
|
||||
assert TestTools.checkList( result.get( RevisionType.DEL ) );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.ADD ) );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.MOD ), site );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.DEL ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -141,9 +141,9 @@ public class DefaultTrackingEntitiesTest extends BaseEnversJPAFunctionalTestCase
|
|||
StrIntTestEntity site = new StrIntTestEntity( null, null, siteId );
|
||||
|
||||
Map<RevisionType, List<Object>> result = getCrossTypeRevisionChangesReader().findEntitiesGroupByRevisionType( 3 );
|
||||
assert TestTools.checkList( result.get( RevisionType.ADD ) );
|
||||
assert TestTools.checkList( result.get( RevisionType.MOD ) );
|
||||
assert TestTools.checkList( result.get( RevisionType.DEL ), site, ste );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.ADD ) );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.MOD ) );
|
||||
assert TestTools.checkCollection( result.get( RevisionType.DEL ), site, ste );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -151,7 +151,7 @@ public class DefaultTrackingEntitiesTest extends BaseEnversJPAFunctionalTestCase
|
|||
StrTestEntity ste = new StrTestEntity( "x", steId );
|
||||
StrIntTestEntity site = new StrIntTestEntity( "y", 1, siteId );
|
||||
|
||||
assert TestTools.checkList(
|
||||
assert TestTools.checkCollection(
|
||||
getCrossTypeRevisionChangesReader().findEntities( 1, RevisionType.ADD ),
|
||||
ste,
|
||||
site
|
||||
|
@ -162,7 +162,10 @@ public class DefaultTrackingEntitiesTest extends BaseEnversJPAFunctionalTestCase
|
|||
public void testFindChangedEntitiesByRevisionTypeMOD() {
|
||||
StrIntTestEntity site = new StrIntTestEntity( "y", 2, siteId );
|
||||
|
||||
assert TestTools.checkList( getCrossTypeRevisionChangesReader().findEntities( 2, RevisionType.MOD ), site );
|
||||
assert TestTools.checkCollection(
|
||||
getCrossTypeRevisionChangesReader().findEntities( 2, RevisionType.MOD ),
|
||||
site
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -170,7 +173,7 @@ public class DefaultTrackingEntitiesTest extends BaseEnversJPAFunctionalTestCase
|
|||
StrTestEntity ste = new StrTestEntity( null, steId );
|
||||
StrIntTestEntity site = new StrIntTestEntity( null, null, siteId );
|
||||
|
||||
assert TestTools.checkList(
|
||||
assert TestTools.checkCollection(
|
||||
getCrossTypeRevisionChangesReader().findEntities( 3, RevisionType.DEL ),
|
||||
ste,
|
||||
site
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package org.hibernate.envers.test.integration.strategy;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.envers.configuration.EnversSettings;
|
||||
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
|
||||
import org.hibernate.envers.test.entities.IntNoAutoIdTestEntity;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* Tests that reusing identifiers doesn't cause auditing misbehavior.
|
||||
*
|
||||
* @author adar
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-8280")
|
||||
public class IdentifierReuseTest extends BaseEnversJPAFunctionalTestCase {
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put( EnversSettings.ALLOW_IDENTIFIER_REUSE, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { IntNoAutoIdTestEntity.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdentifierReuse() {
|
||||
final Integer reusedId = 1;
|
||||
|
||||
EntityManager entityManager = getEntityManager();
|
||||
saveUpdateAndRemoveEntity( entityManager, reusedId );
|
||||
saveUpdateAndRemoveEntity( entityManager, reusedId );
|
||||
entityManager.close();
|
||||
|
||||
assertEquals(
|
||||
Arrays.asList( 1, 2, 3, 4, 5, 6 ),
|
||||
getAuditReader().getRevisions( IntNoAutoIdTestEntity.class, reusedId )
|
||||
);
|
||||
}
|
||||
|
||||
private void saveUpdateAndRemoveEntity(EntityManager entityManager, Integer id) {
|
||||
EntityTransaction transaction = entityManager.getTransaction();
|
||||
|
||||
transaction.begin();
|
||||
IntNoAutoIdTestEntity entity = new IntNoAutoIdTestEntity( 0, id );
|
||||
entityManager.persist( entity );
|
||||
assertEquals( id, entity.getId() );
|
||||
transaction.commit();
|
||||
|
||||
transaction.begin();
|
||||
entity = entityManager.find( IntNoAutoIdTestEntity.class, id );
|
||||
entity.setNumVal( 1 );
|
||||
entity = entityManager.merge( entity );
|
||||
assertEquals( id, entity.getId() );
|
||||
transaction.commit();
|
||||
|
||||
transaction.begin();
|
||||
entity = entityManager.find( IntNoAutoIdTestEntity.class, id );
|
||||
assertNotNull( entity );
|
||||
entityManager.remove( entity );
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
|
@ -291,17 +291,17 @@ public class ValidityAuditStrategyRevEndTestCustomRevEnt extends BaseEnversJPAFu
|
|||
ParentEntity rev4 = getAuditReader().find( ParentEntity.class, p1_id, 4 );
|
||||
ParentEntity rev5 = getAuditReader().find( ParentEntity.class, p1_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren1() );
|
||||
assert TestTools.checkList( rev2.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev3.getChildren1(), c1_1, c1_2 );
|
||||
assert TestTools.checkList( rev4.getChildren1(), c1_2 );
|
||||
assert TestTools.checkList( rev5.getChildren1() );
|
||||
assert TestTools.checkCollection( rev1.getChildren1() );
|
||||
assert TestTools.checkCollection( rev2.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev3.getChildren1(), c1_1, c1_2 );
|
||||
assert TestTools.checkCollection( rev4.getChildren1(), c1_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren1() );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren2() );
|
||||
assert TestTools.checkList( rev2.getChildren2() );
|
||||
assert TestTools.checkList( rev3.getChildren2(), c2_2 );
|
||||
assert TestTools.checkList( rev4.getChildren2(), c2_2 );
|
||||
assert TestTools.checkList( rev5.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev1.getChildren2() );
|
||||
assert TestTools.checkCollection( rev2.getChildren2() );
|
||||
assert TestTools.checkCollection( rev3.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev4.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren2(), c2_2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -319,17 +319,17 @@ public class ValidityAuditStrategyRevEndTestCustomRevEnt extends BaseEnversJPAFu
|
|||
ParentEntity rev4 = getAuditReader().find( ParentEntity.class, p2_id, 4 );
|
||||
ParentEntity rev5 = getAuditReader().find( ParentEntity.class, p2_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren1() );
|
||||
assert TestTools.checkList( rev2.getChildren1() );
|
||||
assert TestTools.checkList( rev3.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev4.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev5.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev1.getChildren1() );
|
||||
assert TestTools.checkCollection( rev2.getChildren1() );
|
||||
assert TestTools.checkCollection( rev3.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev4.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev5.getChildren1(), c1_1 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren2() );
|
||||
assert TestTools.checkList( rev2.getChildren2(), c2_1 );
|
||||
assert TestTools.checkList( rev3.getChildren2(), c2_1 );
|
||||
assert TestTools.checkList( rev4.getChildren2(), c2_1, c2_2 );
|
||||
assert TestTools.checkList( rev5.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev1.getChildren2() );
|
||||
assert TestTools.checkCollection( rev2.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev3.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev4.getChildren2(), c2_1, c2_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren2(), c2_1 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -358,11 +358,11 @@ public class ValidityAuditStrategyRevEndTestCustomRevEnt extends BaseEnversJPAFu
|
|||
5
|
||||
);
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents(), p1 );
|
||||
assert TestTools.checkList( rev3.getParents(), p1, p2 );
|
||||
assert TestTools.checkList( rev4.getParents(), p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1, p2 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p2 );
|
||||
}
|
||||
|
||||
// TODO: this was disabled?
|
||||
|
@ -391,11 +391,11 @@ public class ValidityAuditStrategyRevEndTestCustomRevEnt extends BaseEnversJPAFu
|
|||
5
|
||||
);
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents() );
|
||||
assert TestTools.checkList( rev3.getParents(), p1 );
|
||||
assert TestTools.checkList( rev4.getParents(), p1 );
|
||||
assert TestTools.checkList( rev5.getParents() );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents() );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev5.getParents() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -423,11 +423,11 @@ public class ValidityAuditStrategyRevEndTestCustomRevEnt extends BaseEnversJPAFu
|
|||
5
|
||||
);
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents(), p2 );
|
||||
assert TestTools.checkList( rev3.getParents(), p2 );
|
||||
assert TestTools.checkList( rev4.getParents(), p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -456,11 +456,11 @@ public class ValidityAuditStrategyRevEndTestCustomRevEnt extends BaseEnversJPAFu
|
|||
5
|
||||
);
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents() );
|
||||
assert TestTools.checkList( rev3.getParents(), p1 );
|
||||
assert TestTools.checkList( rev4.getParents(), p1, p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents() );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p1, p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p1 );
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> getRevisions(
|
||||
|
|
|
@ -289,17 +289,17 @@ public class ValidityAuditStrategyRevEndTsTest extends BaseEnversJPAFunctionalTe
|
|||
ParentEntity rev4 = getAuditReader().find( ParentEntity.class, p1_id, 4 );
|
||||
ParentEntity rev5 = getAuditReader().find( ParentEntity.class, p1_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren1() );
|
||||
assert TestTools.checkList( rev2.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev3.getChildren1(), c1_1, c1_2 );
|
||||
assert TestTools.checkList( rev4.getChildren1(), c1_2 );
|
||||
assert TestTools.checkList( rev5.getChildren1() );
|
||||
assert TestTools.checkCollection( rev1.getChildren1() );
|
||||
assert TestTools.checkCollection( rev2.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev3.getChildren1(), c1_1, c1_2 );
|
||||
assert TestTools.checkCollection( rev4.getChildren1(), c1_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren1() );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren2() );
|
||||
assert TestTools.checkList( rev2.getChildren2() );
|
||||
assert TestTools.checkList( rev3.getChildren2(), c2_2 );
|
||||
assert TestTools.checkList( rev4.getChildren2(), c2_2 );
|
||||
assert TestTools.checkList( rev5.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev1.getChildren2() );
|
||||
assert TestTools.checkCollection( rev2.getChildren2() );
|
||||
assert TestTools.checkCollection( rev3.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev4.getChildren2(), c2_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren2(), c2_2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -317,17 +317,17 @@ public class ValidityAuditStrategyRevEndTsTest extends BaseEnversJPAFunctionalTe
|
|||
ParentEntity rev4 = getAuditReader().find( ParentEntity.class, p2_id, 4 );
|
||||
ParentEntity rev5 = getAuditReader().find( ParentEntity.class, p2_id, 5 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren1() );
|
||||
assert TestTools.checkList( rev2.getChildren1() );
|
||||
assert TestTools.checkList( rev3.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev4.getChildren1(), c1_1 );
|
||||
assert TestTools.checkList( rev5.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev1.getChildren1() );
|
||||
assert TestTools.checkCollection( rev2.getChildren1() );
|
||||
assert TestTools.checkCollection( rev3.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev4.getChildren1(), c1_1 );
|
||||
assert TestTools.checkCollection( rev5.getChildren1(), c1_1 );
|
||||
|
||||
assert TestTools.checkList( rev1.getChildren2() );
|
||||
assert TestTools.checkList( rev2.getChildren2(), c2_1 );
|
||||
assert TestTools.checkList( rev3.getChildren2(), c2_1 );
|
||||
assert TestTools.checkList( rev4.getChildren2(), c2_1, c2_2 );
|
||||
assert TestTools.checkList( rev5.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev1.getChildren2() );
|
||||
assert TestTools.checkCollection( rev2.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev3.getChildren2(), c2_1 );
|
||||
assert TestTools.checkCollection( rev4.getChildren2(), c2_1, c2_2 );
|
||||
assert TestTools.checkCollection( rev5.getChildren2(), c2_1 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -356,11 +356,11 @@ public class ValidityAuditStrategyRevEndTsTest extends BaseEnversJPAFunctionalTe
|
|||
5
|
||||
);
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents(), p1 );
|
||||
assert TestTools.checkList( rev3.getParents(), p1, p2 );
|
||||
assert TestTools.checkList( rev4.getParents(), p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1, p2 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p2 );
|
||||
}
|
||||
|
||||
// TODO: this was disabled?
|
||||
|
@ -389,11 +389,11 @@ public class ValidityAuditStrategyRevEndTsTest extends BaseEnversJPAFunctionalTe
|
|||
5
|
||||
);
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents() );
|
||||
assert TestTools.checkList( rev3.getParents(), p1 );
|
||||
assert TestTools.checkList( rev4.getParents(), p1 );
|
||||
assert TestTools.checkList( rev5.getParents() );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents() );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev5.getParents() );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -421,11 +421,11 @@ public class ValidityAuditStrategyRevEndTsTest extends BaseEnversJPAFunctionalTe
|
|||
5
|
||||
);
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents(), p2 );
|
||||
assert TestTools.checkList( rev3.getParents(), p2 );
|
||||
assert TestTools.checkList( rev4.getParents(), p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -454,11 +454,11 @@ public class ValidityAuditStrategyRevEndTsTest extends BaseEnversJPAFunctionalTe
|
|||
5
|
||||
);
|
||||
|
||||
assert TestTools.checkList( rev1.getParents() );
|
||||
assert TestTools.checkList( rev2.getParents() );
|
||||
assert TestTools.checkList( rev3.getParents(), p1 );
|
||||
assert TestTools.checkList( rev4.getParents(), p1, p2 );
|
||||
assert TestTools.checkList( rev5.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev1.getParents() );
|
||||
assert TestTools.checkCollection( rev2.getParents() );
|
||||
assert TestTools.checkCollection( rev3.getParents(), p1 );
|
||||
assert TestTools.checkCollection( rev4.getParents(), p1, p2 );
|
||||
assert TestTools.checkCollection( rev5.getParents(), p1 );
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> getRevisions(
|
||||
|
|
|
@ -25,6 +25,7 @@ package org.hibernate.envers.test.tools;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -63,7 +64,7 @@ public class TestTools {
|
|||
return ret;
|
||||
}
|
||||
|
||||
public static <T> boolean checkList(List<T> list, T... objects) {
|
||||
public static <T> boolean checkCollection(Collection<T> list, T... objects) {
|
||||
if ( list.size() != objects.length ) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -35,12 +35,10 @@ dependencies {
|
|||
|
||||
// Local copies of all jars needed fur the OSGi runtime.
|
||||
osgiRuntime( "org.jboss.arquillian.osgi:arquillian-osgi-bundle:1.0.3.Final" )
|
||||
osgiRuntime( "org.ops4j.pax.url:pax-url-wrap:1.5.2" )
|
||||
// TODO: Temporarily using a pre-built jar in src/test/resources. It's needed for a recent manifest change. Once this is available in Maven, use it.
|
||||
//osgiRuntime( "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0-SNAPSHOT" )
|
||||
osgiRuntime( libraries.jpa )
|
||||
osgiRuntime( "javax.enterprise:cdi-api:1.1-PFD" )
|
||||
osgiRuntime( "org.jboss.spec.javax.interceptor:jboss-interceptors-api_1.2_spec:1.0.0.Alpha1" )
|
||||
osgiRuntime( "org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.0.0.Alpha1" )
|
||||
osgiRuntime( libraries.jta )
|
||||
osgiRuntime( "commons-collections:commons-collections:3.2.1" )
|
||||
osgiRuntime( "commons-pool:commons-pool:1.6" )
|
||||
osgiRuntime( "commons-dbcp:commons-dbcp:1.4" )
|
||||
|
@ -93,7 +91,7 @@ task copyBnd(type: Copy) {
|
|||
|
||||
task runBnd(type: JavaExec){
|
||||
main = "-jar"
|
||||
args "$buildDir/osgi-lib/bnd/bnd.jar", "$buildDir/osgi-lib/bnd/cdi-api.bnd", "$buildDir/osgi-lib/bnd/el-api.bnd", "$buildDir/osgi-lib/bnd/jandex.bnd", "$buildDir/osgi-lib/bnd/javassist.bnd", "$buildDir/osgi-lib/bnd/serp.bnd"
|
||||
args "$buildDir/osgi-lib/bnd/bnd.jar", "$buildDir/osgi-lib/bnd/cdi-api.bnd", "$buildDir/osgi-lib/bnd/el-api.bnd", "$buildDir/osgi-lib/bnd/jandex.bnd", "$buildDir/osgi-lib/bnd/serp.bnd"
|
||||
}
|
||||
|
||||
task copyToLib(type: Copy) {
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.hibernate.jpa.HibernatePersistenceProvider;
|
|||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
/**
|
||||
* This BundleActivator provides three different uses of Hibernate in OSGi
|
||||
|
@ -59,6 +60,10 @@ import org.osgi.framework.FrameworkUtil;
|
|||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public class HibernateBundleActivator implements BundleActivator {
|
||||
|
||||
private ServiceRegistration<?> persistenceProviderService;
|
||||
private ServiceRegistration<?> sessionFactoryService;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void start(BundleContext context) throws Exception {
|
||||
|
@ -75,12 +80,12 @@ public class HibernateBundleActivator implements BundleActivator {
|
|||
final Dictionary properties = new Hashtable();
|
||||
// In order to support existing persistence.xml files, register using the legacy provider name.
|
||||
properties.put( "javax.persistence.provider", HibernatePersistenceProvider.class.getName() );
|
||||
context.registerService(
|
||||
persistenceProviderService = context.registerService(
|
||||
PersistenceProvider.class.getName(),
|
||||
new OsgiPersistenceProviderService( osgiClassLoader, osgiJtaPlatform, context ),
|
||||
properties
|
||||
);
|
||||
context.registerService(
|
||||
sessionFactoryService = context.registerService(
|
||||
SessionFactory.class.getName(),
|
||||
new OsgiSessionFactoryService( osgiClassLoader, osgiJtaPlatform, context ),
|
||||
new Hashtable()
|
||||
|
@ -89,6 +94,11 @@ public class HibernateBundleActivator implements BundleActivator {
|
|||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
// Nothing else to do?
|
||||
persistenceProviderService.unregister();
|
||||
persistenceProviderService = null;
|
||||
sessionFactoryService.unregister();
|
||||
sessionFactoryService = null;
|
||||
|
||||
ClassLoaderHelper.overridenClassLoader = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,17 @@ package org.hibernate.osgi.test;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.hibernate.osgi.OsgiPersistenceProviderService;
|
||||
import org.hibernate.osgi.OsgiSessionFactoryService;
|
||||
import org.hibernate.osgi.test.result.OsgiTestResults;
|
||||
import org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.arquillian.junit.Arquillian;
|
||||
import org.jboss.arquillian.junit.InSequence;
|
||||
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||
import org.jboss.osgi.metadata.OSGiManifestBuilder;
|
||||
import org.jboss.shrinkwrap.api.ShrinkWrap;
|
||||
|
@ -94,6 +98,8 @@ public class OsgiTestCase {
|
|||
builder.addBundleSymbolicName( archive.getName() );
|
||||
builder.addBundleManifestVersion( 2 );
|
||||
builder.addImportPackages( OsgiTestResults.class );
|
||||
// needed primarily to test service cleanup in #testStop
|
||||
builder.addImportPackages( OsgiSessionFactoryService.class );
|
||||
return builder.openStream();
|
||||
}
|
||||
} );
|
||||
|
@ -107,19 +113,16 @@ public class OsgiTestCase {
|
|||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@InSequence(1)
|
||||
public void testClientBundle() throws Exception {
|
||||
assertNotNull( "BundleContext injected", context );
|
||||
assertEquals( "System Bundle ID", 0, context.getBundle().getBundleId() );
|
||||
|
||||
testHibernateBundle( "org.hibernate.core" );
|
||||
testHibernateBundle( "org.hibernate.entitymanager" );
|
||||
commonTests();
|
||||
|
||||
final Bundle testClientBundle = findHibernateBundle( "testClientBundle" );
|
||||
assertNotNull( "The test client bundle was not found!", testClientBundle );
|
||||
testClientBundle.start();
|
||||
assertEquals( "The test client bundle was not activated!", Bundle.ACTIVE, testClientBundle.getState() );
|
||||
|
||||
final ServiceReference serviceReference = context.getServiceReference( OsgiTestResults.class.getName() );
|
||||
final ServiceReference<?> serviceReference = context.getServiceReference( OsgiTestResults.class.getName() );
|
||||
final OsgiTestResults testResults = (OsgiTestResults) context.getService( serviceReference );
|
||||
|
||||
if ( testResults.getFailures().size() > 0 ) {
|
||||
|
@ -127,6 +130,36 @@ public class OsgiTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that stopping the hibernate-osgi bundle happens cleanly.
|
||||
*
|
||||
* TODO: This will be really simplistic at first, but should be expanded upon.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
// Arquillian does not restart the container between runs (afaik). Without the ordering, the tests will
|
||||
// intermittently fail since this method stops the bundle.
|
||||
@InSequence(2)
|
||||
public void testStop() throws Exception {
|
||||
commonTests();
|
||||
|
||||
findHibernateBundle( "org.hibernate.osgi" ).stop();
|
||||
testHibernateBundle( "org.hibernate.osgi", Bundle.RESOLVED );
|
||||
|
||||
assertNull( context.getServiceReference( OsgiSessionFactoryService.class ) );
|
||||
assertNull( context.getServiceReference( OsgiPersistenceProviderService.class ) );
|
||||
}
|
||||
|
||||
private void commonTests() {
|
||||
assertNotNull( "BundleContext injected", context );
|
||||
assertEquals( "System Bundle ID", 0, context.getBundle().getBundleId() );
|
||||
|
||||
testHibernateBundle( "org.hibernate.core", Bundle.ACTIVE );
|
||||
testHibernateBundle( "org.hibernate.entitymanager", Bundle.ACTIVE );
|
||||
testHibernateBundle( "org.hibernate.osgi", Bundle.ACTIVE );
|
||||
}
|
||||
|
||||
private Bundle findHibernateBundle(String symbolicName) {
|
||||
for ( Bundle bundle : context.getBundles() ) {
|
||||
if ( bundle.getSymbolicName().equals( symbolicName ) ) {
|
||||
|
@ -136,10 +169,10 @@ public class OsgiTestCase {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void testHibernateBundle(String symbolicName) {
|
||||
private void testHibernateBundle(String symbolicName, int state) {
|
||||
final Bundle bundle = findHibernateBundle( symbolicName );
|
||||
|
||||
assertNotNull( "Bundle " + symbolicName + " was not found!", bundle );
|
||||
assertEquals( "Bundle " + symbolicName + " was not activated!", Bundle.ACTIVE, bundle.getState() );
|
||||
assertEquals( "Bundle " + symbolicName + " was not in the expected state!", state, bundle.getState() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
Bundle-SymbolicName: javassist
|
||||
Bundle-Version: 3.18.0
|
||||
|
||||
Include-Resource: @../javassist-3.18.0-GA.jar
|
||||
Import-Package: com.sun.jdi;resolution:=optional,com.sun.jdi.connect;resolution:=optional,com.sun.jdi.event;resolution:=optional,com.sun.jdi.request;resolution:=optional
|
||||
-exportcontents: javassist,javassist.bytecode,javassist.bytecode.analysis,javassist.bytecode.annotation,javassist.bytecode.stackmap,javassist.compiler,javassist.compiler.ast,javassist.convert,javassist.expr,javassist.runtime,javassist.scopedpool,javassist.tools,javassist.tools.reflect,javassist.tools.rmi,javassist.tools.web,javassist.util,javassist.util.proxy
|
|
@ -14,11 +14,9 @@ felix.log.level=4
|
|||
felix.auto.install.1=\
|
||||
file:target/osgi-lib/testClientBundle.jar
|
||||
|
||||
# TODO: Temporarily using a pre-built hibernate-jpa-2.1-api-1.0.0-SNAPSHOT.jar in src/test/resources.
|
||||
# It's needed for a recent manifest change. Once this is available in Maven, use it.
|
||||
felix.auto.start.1=\
|
||||
file:target/osgi-lib/arquillian-osgi-bundle-1.0.3.Final.jar \
|
||||
file:src/test/resources/hibernate-jpa-2.1-api-1.0.0-SNAPSHOT.jar \
|
||||
file:target/osgi-lib/hibernate-jpa-2.1-api-1.0.0.Final.jar \
|
||||
file:target/osgi-lib/bnd/el-api-2.2.0.jar \
|
||||
file:target/osgi-lib/bnd/cdi-api-1.1.0.jar \
|
||||
file:target/osgi-lib/jboss-interceptors-api_1.2_spec-1.0.0.Alpha1.jar \
|
||||
|
@ -30,7 +28,7 @@ felix.auto.start.1=\
|
|||
file:target/osgi-lib/bnd/serp-1.14.1.jar \
|
||||
file:target/osgi-lib/h2-1.3.170.jar \
|
||||
file:target/osgi-lib/org.apache.servicemix.bundles.antlr-2.7.7_5.jar \
|
||||
file:target/osgi-lib/bnd/javassist-3.18.0.jar \
|
||||
file:target/osgi-lib/javassist-3.18.1-Beta1.jar \
|
||||
file:target/osgi-lib/org.apache.servicemix.specs.jsr303-api-1.0.0-2.2.0.jar \
|
||||
file:target/osgi-lib/org.apache.servicemix.bundles.ant-1.8.2_2.jar \
|
||||
file:target/osgi-lib/org.apache.servicemix.specs.stax-api-1.2-2.2.0.jar \
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue