diff --git a/test/org/hibernate/junit/AbstractClassLoaderIsolatedTestCase.java b/test/org/hibernate/junit/AbstractClassLoaderIsolatedTestCase.java new file mode 100644 index 0000000000..ac7a879a5f --- /dev/null +++ b/test/org/hibernate/junit/AbstractClassLoaderIsolatedTestCase.java @@ -0,0 +1,34 @@ +package org.hibernate.junit; + +/** + * A specialized TestCase for running tests in an isolated class-loader + * + * @author Steve Ebersole + */ +public abstract class AbstractClassLoaderIsolatedTestCase extends UnitTestCase { + private ClassLoader parentLoader; + private ClassLoader isolatedLoader; + + public AbstractClassLoaderIsolatedTestCase(String string) { + super( string ); + } + + protected void setUp() throws Exception { + parentLoader = Thread.currentThread().getContextClassLoader(); + isolatedLoader = buildIsolatedClassLoader( parentLoader ); + Thread.currentThread().setContextClassLoader( isolatedLoader ); + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + Thread.currentThread().setContextClassLoader( parentLoader ); + releaseIsolatedClassLoader( isolatedLoader ); + parentLoader = null; + isolatedLoader = null; + } + + protected abstract ClassLoader buildIsolatedClassLoader(ClassLoader parent); + + protected abstract void releaseIsolatedClassLoader(ClassLoader isolatedLoader); +} diff --git a/test/org/hibernate/junit/FailureExpectedCollector.java b/test/org/hibernate/junit/FailureExpectedCollector.java new file mode 100644 index 0000000000..1ef0b92d4f --- /dev/null +++ b/test/org/hibernate/junit/FailureExpectedCollector.java @@ -0,0 +1,50 @@ +package org.hibernate.junit; + +import java.util.Set; +import java.util.HashSet; +import java.util.Iterator; + +import junit.framework.TestSuite; +import junit.framework.Test; +import junit.framework.TestCase; + +import org.hibernate.test.AllTests; + +/** + * A simple class to collect the names of "failure expected" tests... + * + * @author Steve Ebersole + */ +public class FailureExpectedCollector { + + public static void main(String[] args) { + Set testNames = collectAllFailureExpectedTestNames(); + Iterator itr = testNames.iterator(); + int i = 0; + while ( itr.hasNext() ) { + i++; + System.out.println( i + ") " + itr.next() ); + } + } + + public static Set collectAllFailureExpectedTestNames() { + Set names = new HashSet(); + collectFailureExpectedTestNames( names, ( TestSuite ) AllTests.unfilteredSuite() ); + return names; + } + + public static void collectFailureExpectedTestNames(final Set names, TestSuite suite) { + TestSuiteVisitor.Handler handler = new TestSuiteVisitor.Handler() { + public void handleTestCase(Test test) { + TestCase testCase = ( TestCase ) test; + if ( testCase.getName().endsWith( "FailureExpected" ) ) { + names.add( testCase.getClass().getName() + "#" + testCase.getName() ); + } + } + public void startingTestSuite(TestSuite suite) {} + public void completedTestSuite(TestSuite suite) {} + }; + TestSuiteVisitor visitor = new TestSuiteVisitor( handler ); + visitor.visit( suite ); + } +} diff --git a/test/org/hibernate/junit/SkipLog.java b/test/org/hibernate/junit/SkipLog.java new file mode 100644 index 0000000000..381a06c499 --- /dev/null +++ b/test/org/hibernate/junit/SkipLog.java @@ -0,0 +1,13 @@ +package org.hibernate.junit; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Well-known-location lookup for the test-skip log... + * + * @author Steve Ebersole + */ +public class SkipLog { + public static final Log LOG = LogFactory.getLog( "org.hibernate.test.SKIPPED" ); +} diff --git a/test/org/hibernate/junit/TestSuiteVisitor.java b/test/org/hibernate/junit/TestSuiteVisitor.java new file mode 100644 index 0000000000..4d6e4802c9 --- /dev/null +++ b/test/org/hibernate/junit/TestSuiteVisitor.java @@ -0,0 +1,42 @@ +package org.hibernate.junit; + +import java.util.Enumeration; + +import junit.framework.TestSuite; +import junit.framework.Test; + +/** + * Handles walking a TestSuite hierarchy for recognition of individual tests. + * + * @author Steve Ebersole + */ +public class TestSuiteVisitor { + + private final TestSuiteVisitor.Handler handler; + + public TestSuiteVisitor(TestSuiteVisitor.Handler handler) { + this.handler = handler; + } + + public void visit(TestSuite testSuite) { + handler.startingTestSuite( testSuite ); + Enumeration tests = testSuite.tests(); + while ( tests.hasMoreElements() ) { + Test test = ( Test ) tests.nextElement(); + if ( test instanceof TestSuite ) { + visit( ( TestSuite ) test ); + } + else { + handler.handleTestCase( test ); + } + } + handler.completedTestSuite( testSuite ); + } + + public static interface Handler { + public void handleTestCase(Test test); + public void startingTestSuite(TestSuite suite); + public void completedTestSuite(TestSuite suite); + } + +} diff --git a/test/org/hibernate/junit/UnitTestCase.java b/test/org/hibernate/junit/UnitTestCase.java new file mode 100644 index 0000000000..4eb22b6bf7 --- /dev/null +++ b/test/org/hibernate/junit/UnitTestCase.java @@ -0,0 +1,84 @@ +package org.hibernate.junit; + +import java.util.Iterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import junit.framework.AssertionFailedError; + + +/** + * A basic JUnit {@link junit.framework.TestCase} subclass for + * adding some Hibernate specific behavior and functionality. + * + * @author Steve Ebersole + */ +public abstract class UnitTestCase extends junit.framework.TestCase { + + private static final Log log = LogFactory.getLog( UnitTestCase.class ); + + public UnitTestCase(String string) { + super( string ); + } + + /** + * runBare overridden in order to apply FailureExpected validations + * as well as start/complete logging + * + * @throws Throwable + */ + public void runBare() throws Throwable { + final boolean doValidate = getName().endsWith( "FailureExpected" ) && Boolean.getBoolean( "hibernate.test.validatefailureexpected" ); + try { + log.info( "Starting test [" + fullTestName() + "]" ); + super.runBare(); + if ( doValidate ) { + fail( "Test marked as FailureExpected, but did not fail!" ); + } + } + catch( Throwable t ) { + if ( doValidate ) { + skipExpectedFailure( t ); + } + else { + throw t; + } + } + finally { + log.info( "Completed test [" + fullTestName() + "]" ); + } + } + + protected void skipExpectedFailure(Throwable error) { + reportSkip( "ignoring *FailuredExpected methods", "Failed with: " + error.toString() ); + } + + // additional assertions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public static void assertElementTypeAssignability(java.util.Collection collection, Class clazz) throws AssertionFailedError { + Iterator itr = collection.iterator(); + while ( itr.hasNext() ) { + assertClassAssignability( itr.next().getClass(), clazz ); + } + } + + public static void assertClassAssignability(Class source, Class target) throws AssertionFailedError { + if ( !target.isAssignableFrom( source ) ) { + throw new AssertionFailedError( + "Classes were not assignment-compatible : source<" + source.getName() + + "> target<" + target.getName() + ">" + ); + } + } + + + // test skipping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public String fullTestName() { + return this.getClass().getName() + "#" + this.getName(); + } + + protected void reportSkip(String reason, String testDescription) { + SkipLog.LOG.warn( "*** skipping [" + fullTestName() + "] - " + testDescription + " : " + reason, new Exception() ); + } +} diff --git a/test/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java b/test/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java new file mode 100644 index 0000000000..f6cb49cfc2 --- /dev/null +++ b/test/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java @@ -0,0 +1,27 @@ +package org.hibernate.junit.functional; + +import org.hibernate.junit.SkipLog; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public abstract class DatabaseSpecificFunctionalTestCase extends FunctionalTestCase { + public DatabaseSpecificFunctionalTestCase(String string) { + super( string ); + } + + protected void runTest() throws Throwable { + // Note: this protection comes into play when running + // tests individually. The suite as a whole is already + // "protected" by the fact that these tests are actually + // filtered out of the suite + if ( appliesTo( getDialect() ) ) { + super.runTest(); + } + else { + SkipLog.LOG.warn( "skipping database-specific test [" + fullTestName() + "] for dialect [" + getDialect().getClass().getName() + "]" ); + } + } +} diff --git a/test/org/hibernate/junit/functional/ExecutionEnvironment.java b/test/org/hibernate/junit/functional/ExecutionEnvironment.java new file mode 100644 index 0000000000..3955cd257b --- /dev/null +++ b/test/org/hibernate/junit/functional/ExecutionEnvironment.java @@ -0,0 +1,161 @@ +package org.hibernate.junit.functional; + +import java.util.Iterator; +import java.sql.Blob; +import java.sql.Clob; + +import org.hibernate.dialect.Dialect; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.cfg.Mappings; +import org.hibernate.SessionFactory; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.SimpleValue; +import org.hibernate.mapping.Collection; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class ExecutionEnvironment { + + public static final Dialect DIALECT = Dialect.getDialect(); + + private final ExecutionEnvironment.Settings settings; + + private Configuration configuration; + private SessionFactory sessionFactory; + private boolean allowRebuild; + + public ExecutionEnvironment(ExecutionEnvironment.Settings settings) { + this.settings = settings; + } + + public boolean isAllowRebuild() { + return allowRebuild; + } + + public void setAllowRebuild(boolean allowRebuild) { + this.allowRebuild = allowRebuild; + } + + public Dialect getDialect() { + return DIALECT; + } + + public Configuration getConfiguration() { + return configuration; + } + + public SessionFactory getSessionFactory() { + return sessionFactory; + } + + public void initialize() { + if ( sessionFactory != null ) { + throw new IllegalStateException( "attempt to initialize already initialized ExecutionEnvironment" ); + } + if ( ! settings.appliesTo( getDialect() ) ) { + return; + } + + Configuration configuration = new Configuration(); + configuration.setProperty( Environment.CACHE_PROVIDER, "org.hibernate.cache.HashtableCacheProvider" ); + + settings.configure( configuration ); + + applyMappings( configuration ); + applyCacheSettings( configuration ); + + + if ( settings.createSchema() ) { + configuration.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); + } + + // make sure we use the same dialect... + configuration.setProperty( Environment.DIALECT, getDialect().getClass().getName() ); + + configuration.buildMappings(); + settings.afterConfigurationBuilt( configuration.createMappings(), getDialect() ); + + SessionFactory sessionFactory = configuration.buildSessionFactory(); + this.configuration = configuration; + this.sessionFactory = sessionFactory; + + settings.afterSessionFactoryBuilt( ( SessionFactoryImplementor ) sessionFactory ); + } + + private void applyMappings(Configuration configuration) { + String[] mappings = settings.getMappings(); + for ( int i = 0; i < mappings.length; i++ ) { + configuration.addResource( settings.getBaseForMappings() + mappings[i], ExecutionEnvironment.class.getClassLoader() ); + } + } + + private void applyCacheSettings(Configuration configuration) { + if ( settings.getCacheConcurrencyStrategy() != null ) { + Iterator iter = configuration.getClassMappings(); + while ( iter.hasNext() ) { + PersistentClass clazz = (PersistentClass) iter.next(); + Iterator props = clazz.getPropertyClosureIterator(); + boolean hasLob = false; + while ( props.hasNext() ) { + Property prop = (Property) props.next(); + if ( prop.getValue().isSimpleValue() ) { + String type = ( ( SimpleValue ) prop.getValue() ).getTypeName(); + if ( "blob".equals(type) || "clob".equals(type) ) { + hasLob = true; + } + if ( Blob.class.getName().equals(type) || Clob.class.getName().equals(type) ) { + hasLob = true; + } + } + } + if ( !hasLob && !clazz.isInherited() && settings.overrideCacheStrategy() ) { + configuration.setCacheConcurrencyStrategy( clazz.getEntityName(), settings.getCacheConcurrencyStrategy() ); + } + } + iter = configuration.getCollectionMappings(); + while ( iter.hasNext() ) { + Collection coll = (Collection) iter.next(); + configuration.setCollectionCacheConcurrencyStrategy( coll.getRole(), settings.getCacheConcurrencyStrategy() ); + } + } + } + + public void rebuild() { + if ( !allowRebuild ) { + return; + } + if ( sessionFactory != null ) { + sessionFactory.close(); + sessionFactory = null; + } + sessionFactory = configuration.buildSessionFactory(); + settings.afterSessionFactoryBuilt( ( SessionFactoryImplementor ) sessionFactory ); + } + + public void complete() { + if ( sessionFactory != null ) { + sessionFactory.close(); + sessionFactory = null; + } + configuration = null; + } + + public static interface Settings { + public String[] getMappings(); + public String getBaseForMappings(); + public boolean createSchema(); + public boolean recreateSchemaAfterFailure(); + public void configure(Configuration cfg); + public boolean overrideCacheStrategy(); + public String getCacheConcurrencyStrategy(); + public void afterSessionFactoryBuilt(SessionFactoryImplementor sfi); + public void afterConfigurationBuilt(Mappings mappings, Dialect dialect); + public boolean appliesTo(Dialect dialect); + } +} diff --git a/test/org/hibernate/junit/functional/FunctionalTestCase.java b/test/org/hibernate/junit/functional/FunctionalTestCase.java new file mode 100644 index 0000000000..e1fe9043cf --- /dev/null +++ b/test/org/hibernate/junit/functional/FunctionalTestCase.java @@ -0,0 +1,505 @@ +package org.hibernate.junit.functional; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; + +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Mappings; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.dialect.DerbyDialect; +import org.hibernate.SessionFactory; +import org.hibernate.HibernateException; +import org.hibernate.Interceptor; +import org.hibernate.Session; +import org.hibernate.junit.UnitTestCase; +import org.hibernate.engine.SessionFactoryImplementor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Most of the Hibernate test suite in fact is a series of functional tests, not + * unit tests. Here is a base class for these functional tests. + * + * @author Steve Ebersole + */ +public abstract class FunctionalTestCase extends UnitTestCase implements ExecutionEnvironment.Settings { + + private static final Log log = LogFactory.getLog( FunctionalTestCase.class ); + + private ExecutionEnvironment environment; + private boolean isEnvironmentLocallyManaged; + + private org.hibernate.classic.Session session; + + public FunctionalTestCase(String string) { + super( string ); + } + + public ExecutionEnvironment getEnvironment() { + return environment; + } + + public void setEnvironment(ExecutionEnvironment environment) { + this.environment = environment; + } + + protected void prepareTest() throws Exception { + } + + protected void cleanupTest() throws Exception { + } + + // JUnit hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Override {@link junit.framework.TestCase#setUp()} to check if we need + * to build a locally managed execution environment. + * + * @throws Exception + */ + protected final void setUp() throws Exception { + if ( environment == null ) { + log.info( "Building locally managed execution env" ); + isEnvironmentLocallyManaged = true; + environment = new ExecutionEnvironment( this ); + environment.initialize(); + } + prepareTest(); + } + + /** + * Override {@link junit.framework.TestCase#tearDown()} to tear down + * the execution environment if it is locally managed. + * + * @throws Exception + */ + protected final void tearDown() throws Exception { + cleanupTest(); + if ( isEnvironmentLocallyManaged ) { + log.info( "Destroying locally managed execution env" ); + environment.complete(); + environment = null; + } + } + + /** + * runTest is overridden in order to apply session closure assertions. + * + * @throws Throwable + */ + protected void runTest() throws Throwable { + final boolean stats = sfi().getStatistics().isStatisticsEnabled(); + try { + if ( stats ) { + sfi().getStatistics().clear(); + } + + super.runTest(); + + if ( stats ) { + sfi().getStatistics().logSummary(); + } + + if ( session != null && session.isOpen() ) { + if ( session.isConnected() ) { + session.connection().rollback(); + } + session.close(); + session = null; + fail( "unclosed session" ); + } + else { + session = null; + } + assertAllDataRemoved(); + } + catch ( Throwable e ) { + log.trace( "test run resulted in error; attempting to cleanup", e ); + try { + if ( session != null && session.isOpen() ) { + if ( session.isConnected() ) { + session.connection().rollback(); + } + session.close(); + } + } + catch ( Exception ignore ) { + } + try { + if ( recreateSchemaAfterFailure() && environment != null ) { + environment.rebuild(); + } + } + catch ( Exception ignore ) { + } + throw e; + } + } + + protected void assertAllDataRemoved() { + if ( !createSchema() ) { + return; // no tables were created... + } + if ( !Boolean.getBoolean( "hibernate.test.validateDataCleanup" ) ) { + return; + } + + Session tmpSession = getSessions().openSession(); + try { + List list = tmpSession.createQuery( "select o from java.lang.Object o" ).list(); + + Map items = new HashMap(); + if ( !list.isEmpty() ) { + for ( Iterator iter = list.iterator(); iter.hasNext(); ) { + Object element = iter.next(); + Integer l = ( Integer ) items.get( tmpSession.getEntityName( element ) ); + if ( l == null ) { + l = new Integer( 0 ); + } + l = new Integer( l.intValue() + 1 ); + items.put( tmpSession.getEntityName( element ), l ); + System.out.println( "Data left: " + element ); + } + fail( "Data is left in the database: " + items.toString() ); + } + } + finally { + try { + tmpSession.close(); + } + catch( Throwable t ) { + // intentionally empty + } + } + } + + protected void skipExpectedFailure(Throwable error) { + super.skipExpectedFailure( error ); + try { + if ( recreateSchemaAfterFailure() && environment != null ) { + environment.rebuild(); + } + } + catch ( Exception ignore ) { + } + } + + // ExecutionEnvironment.Settings implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public String getBaseForMappings() { + return "org/hibernate/test/"; + } + + public boolean createSchema() { + return true; + } + + public boolean recreateSchemaAfterFailure() { + return true; + } + + public void configure(Configuration cfg) { + } + + public boolean overrideCacheStrategy() { + return true; + } + + public String getCacheConcurrencyStrategy() { + return "nonstrict-read-write"; + } + + public void afterSessionFactoryBuilt(SessionFactoryImplementor sfi) { + } + + public void afterConfigurationBuilt(Mappings mappings, Dialect dialect) { + } + + /** + * Intended to indicate that this test class as a whole is intended for + * a dialect or series of dialects. Skips here (appliesTo = false) therefore + * simply indicate that the given tests target a particular feature of the + * checked database and none of the tests on this class should be run for the + * checked dialect. + * + * @param dialect The dialect to be checked. + * @return False if the test class as a whole is specifically targetting + * a dialect (or series of dialects) other than the indicated dialect + * and the test should therefore be skipped in its entirety; + * true otherwise. + */ + public boolean appliesTo(Dialect dialect) { + return true; + } + + + // methods for subclasses to access environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Get the factory for this test environment. + * + * @return The factory. + */ + protected SessionFactory getSessions() { + return environment.getSessionFactory(); + } + + /** + * Get the factory for this test environment, casted to {@link org.hibernate.engine.SessionFactoryImplementor}. + *

+ * Shorthand for ( {@link org.hibernate.engine.SessionFactoryImplementor} ) {@link #getSessions()}... + * + * @return The factory + */ + protected SessionFactoryImplementor sfi() { + return ( SessionFactoryImplementor ) getSessions(); + } + + protected Dialect getDialect() { + return ExecutionEnvironment.DIALECT; + } + + protected Configuration getCfg() { + return environment.getConfiguration(); + } + + public org.hibernate.classic.Session openSession() throws HibernateException { + session = getSessions().openSession(); + return session; + } + + public org.hibernate.classic.Session openSession(Interceptor interceptor) throws HibernateException { + session = getSessions().openSession(interceptor); + return session; + } + + + + + /** + * Is connection at least read committed? + *

+ * Not, that this skip check relies on the JDBC driver reporting + * the true isolation level correctly. HSQLDB, for example, will + * report whatever you specify as the isolation + * (Connection.setTransationIsolation()), even though it only supports + * read-uncommitted. + * + * @param scenario text description of the scenario being tested. + * @return true if read-committed isolation is maintained. + */ + protected boolean readCommittedIsolationMaintained(String scenario) { + int isolation = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED; + Session testSession = null; + try { + testSession = openSession(); + isolation = testSession.connection().getTransactionIsolation(); + } + catch( Throwable ignore ) { + } + finally { + if ( testSession != null ) { + try { + testSession.close(); + } + catch( Throwable ignore ) { + } + } + } + if ( isolation < java.sql.Connection.TRANSACTION_READ_COMMITTED ) { + reportSkip( "environment does not support at least read committed isolation", scenario ); + return false; + } + else { + return true; + } + } + + /** + * Does the db/dialect support using a column's physical name in the order-by clause + * even after it has been aliased in the select clause. This is not actually + * required by the SQL spec, although virtually ever DB in the world supports this + * (the most glaring omission here being IBM-variant DBs ala DB2 and Derby). + * + * @param testDescription description of the scenario being tested. + * @return true if is allowed + */ + protected boolean allowsPhysicalColumnNameInOrderby(String testDescription) { + if ( DB2Dialect.class.isInstance( getDialect() ) ) { + // https://issues.apache.org/jira/browse/DERBY-1624 + reportSkip( "Dialect does not support physical column name in order-by clause after it is aliased", testDescription ); + return false; + } + return true; + } + + /** + * Does the db/dialect support using a column's physical name in the having clause + * even after it has been aliased in the select/group-by clause. This is not actually + * required by the SQL spec, although virtually ever DB in the world supports this. + * + * @param testDescription description of the scenario being tested. + * @return true if is allowed + */ + protected boolean allowsPhysicalColumnNameInHaving(String testDescription) { + // I only *know* of this being a limitation on Derby, although I highly suspect + // it is a limitation on any IBM/DB2 variant + if ( DerbyDialect.class.isInstance( getDialect() ) ) { + // https://issues.apache.org/jira/browse/DERBY-1624 + reportSkip( "Dialect does not support physical column name in having clause after it is aliased", testDescription ); + return false; + } + return true; + } + + /** + * Does the db/dialect support empty lists in the IN operator? + *

+ * For example, is "... a.b IN () ..." supported? + * + * @param testDescription description of the scenario being tested. + * @return true if is allowed + */ + protected boolean dialectSupportsEmptyInList(String testDescription) { + if ( ! getDialect().supportsEmptyInList() ) { + reportSkip( "Dialect does not support SQL empty in list : x in ()", testDescription ); + return false; + } + return true; + } + + /** + * Is the db/dialect sensitive in terms of string comparisons? + * @param testDescription description of the scenario being tested. + * @return true if sensitive + */ + protected boolean dialectIsCaseSensitive(String testDescription) { + if ( ! getDialect().areStringComparisonsCaseInsensitive() ) { + reportSkip( "Dialect is case sensitive. ", testDescription ); + return true; + } + return false; + } + + protected boolean supportsRowValueConstructorSyntaxInInList() { + if ( ! getDialect().supportsRowValueConstructorSyntaxInInList() ) { + reportSkip( "Dialect does not support 'tuple' syntax as part of an IN value list", "query support" ); + return false; + } + return true; + } + + protected boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() { + if ( ! getDialect().supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() ) { + reportSkip( "Driver does not support 'position query' methods on forward-only cursors", "query support" ); + return false; + } + return true; + } + + protected boolean supportsCircularCascadeDelete() { + if ( ! getDialect().supportsCircularCascadeDeleteConstraints() ) { + reportSkip( "db/dialect does not support 'circular' cascade delete constraints", "cascade delete constraint support" ); + return false; + } + return true; + } + + protected boolean supportsSubselectOnLeftSideIn() { + if ( ! getDialect().supportsSubselectAsInPredicateLHS() ) { + reportSkip( "Database does not support () in ( ... ) ", "query support" ); + return false; + } + return true; + } + + /** + * Expected LOB usage pattern is such that I can perform an insert + * via prepared statement with a parameter binding for a LOB value + * without crazy casting to JDBC driver implementation-specific classes... + *

+ * Part of the trickiness here is the fact that this is largely + * driver dependent. For Oracle, which is notoriously bad with + * LOB support in their drivers actually does a pretty good job with + * LOB support as of the 10.2.x versions of their drivers... + * + * @return True if expected usage pattern is support; false otherwise. + */ + protected boolean supportsExpectedLobUsagePattern() { + if ( ! getDialect().supportsExpectedLobUsagePattern() ) { + reportSkip( "database/driver does not support expected LOB usage pattern", "LOB support" ); + return false; + } + return true; + } + + /** + * Does the current dialect support propogating changes to LOB + * values back to the database? Talking about mutating the + * underlying value as opposed to supplying a new + * LOB instance... + * + * @return True if the changes are propogated back to the + * database; false otherwise. + */ + protected boolean supportsLobValueChangePropogation() { + if ( ! getDialect().supportsLobValueChangePropogation() ) { + reportSkip( "database/driver does not support propogating LOB value change back to database", "LOB support" ); + return false; + } + return true; + } + + /** + * Is it supported to materialize a LOB locator outside the transaction in + * which it was created? + *

+ * Again, part of the trickiness here is the fact that this is largely + * driver dependent. + *

+ * NOTE: all database I have tested which {@link #supportsExpectedLobUsagePattern()} + * also support the ability to materialize a LOB outside the owning transaction... + * + * @return True if unbounded materialization is supported; false otherwise. + */ + protected boolean supportsUnboundedLobLocatorMaterialization() { + if ( !getDialect().supportsUnboundedLobLocatorMaterialization() ) { + reportSkip( "database/driver does not support materializing a LOB locator outside the 'owning' transaction", "LOB support" ); + return false; + } + return true; + } + + protected boolean supportsSubqueryOnMutatingTable() { + if ( !getDialect().supportsSubqueryOnMutatingTable() ) { + reportSkip( "database/driver does not support referencing mutating table in subquery", "bulk DML support" ); + return false; + } + return true; + } + + protected boolean dialectIs(Class dialectClass) { + return dialectClass.isInstance( getDialect() ); + } + + protected boolean dialectIsOneOf(Class[] dialectClasses) { + for ( int i = 0; i < dialectClasses.length; i++ ) { + if ( dialectClasses[i].isInstance( getDialect() ) ) { + return true; + } + } + return false; + } + + protected boolean dialectIsNot(Class dialectClass) { + return ! dialectIs( dialectClass ); + } + + protected boolean dialectIsNot(Class[] dialectClasses) { + return ! dialectIsOneOf( dialectClasses ); + } +} diff --git a/test/org/hibernate/junit/functional/FunctionalTestClassTestSuite.java b/test/org/hibernate/junit/functional/FunctionalTestClassTestSuite.java new file mode 100644 index 0000000000..f941976f21 --- /dev/null +++ b/test/org/hibernate/junit/functional/FunctionalTestClassTestSuite.java @@ -0,0 +1,129 @@ +package org.hibernate.junit.functional; + +import junit.framework.TestSuite; +import junit.framework.Test; +import junit.framework.TestResult; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A specialized {@link junit.framework.TestSuite} implementation intended + * for use as an aggregate for a single test class specifically for the purpose + * of maintaing a single {@link org.hibernate.SessionFactory} for executings all + * tests defined as part of the given functional test class. + * + * @author Steve Ebersole + */ +public class FunctionalTestClassTestSuite extends TestSuite { + + private static final Log log = LogFactory.getLog( FunctionalTestClassTestSuite.class ); + + private ExecutionEnvironment.Settings settings; + private ExecutionEnvironment environment; + private Throwable environmentSetupError; + private int testCount; + private int testPosition; + + public FunctionalTestClassTestSuite(Class testClass, String name) { + super( testClass, name ); + } + + public FunctionalTestClassTestSuite(Class testClass) { + this( testClass, testClass.getName() ); + } + + /** + * Constructor form used during {@link org.hibernate.test.AllTests} filtering... + * + * @param name The name. + */ + private FunctionalTestClassTestSuite(String name) { + super( name ); + } + + public void addTest(Test test) { + log.trace( "adding test [" + test + "]" ); + if ( settings == null ) { + if ( test instanceof ExecutionEnvironment.Settings ) { + settings = ( ExecutionEnvironment.Settings ) test; + // todo : we could also centralize the skipping of "database specific" tests here + // instead of duplicating this notion in AllTests and DatabaseSpecificFunctionalTestCase. + // as a test gets added, simply check to see if we should really add it via + // DatabaseSpecificFunctionalTestCase.appliesTo( ExecutionEnvironment.DIALECT )... + } + } + testCount++; + super.addTest( test ); + } + + public void run(TestResult testResult) { + if ( testCount == 0 ) { + // might be zero if database-specific... + return; + } + try { + log.info( "Starting test-suite [" + getName() + "]" ); + setUp(); + testPosition = 0; + super.run( testResult ); + } + finally { + try { + tearDown(); + } + catch( Throwable ignore ) { + } + log.info( "Completed test-suite [" + getName() + "]" ); + } + } + + public void runTest(Test test, TestResult testResult) { + testPosition++; + if ( environmentSetupError != null ) { + testResult.startTest( test ); + testResult.addError( test, environmentSetupError ); + testResult.endTest( test ); + return; + } + if ( ! ( test instanceof FunctionalTestCase ) ) { + super.runTest( test, testResult ); + } + else { + FunctionalTestCase functionalTest = ( ( FunctionalTestCase ) test ); + try { + // disallow rebuilding the schema because this is the last test + // in this suite, thus it is about to get dropped immediately + // afterwards anyway... + environment.setAllowRebuild( testPosition < testCount ); + functionalTest.setEnvironment( environment ); + super.runTest( functionalTest, testResult ); + } + finally { + functionalTest.setEnvironment( null ); + } + } + } + + protected void setUp() { + if ( settings == null ) { + return; + } + log.info( "Building aggregated execution environment" ); + try { + environment = new ExecutionEnvironment( settings ); + environment.initialize(); + } + catch( Throwable t ) { + environmentSetupError = t; + } + } + + protected void tearDown() { + if ( environment != null ) { + log.info( "Destroying aggregated execution environment" ); + environment.complete(); + this.environment = null; + } + } +} diff --git a/test/org/hibernate/test/AllTests.java b/test/org/hibernate/test/AllTests.java new file mode 100644 index 0000000000..80fccacb16 --- /dev/null +++ b/test/org/hibernate/test/AllTests.java @@ -0,0 +1,441 @@ +//$Id$ +package org.hibernate.test; + +import java.lang.reflect.Constructor; + +import junit.framework.Test; +import junit.framework.TestSuite; +import junit.textui.TestRunner; + +import org.hibernate.dialect.Dialect; +import org.hibernate.junit.TestSuiteVisitor; +import org.hibernate.test.abstractembeddedcomponents.cid.AbstractCompositeIdTest; +import org.hibernate.test.abstractembeddedcomponents.propertyref.AbstractComponentPropertyRefTest; +import org.hibernate.test.any.AnyTypeTest; +import org.hibernate.test.array.ArrayTest; +import org.hibernate.test.ast.ASTIteratorTest; +import org.hibernate.test.ast.ASTUtilTest; +import org.hibernate.test.batchfetch.BatchFetchTest; +import org.hibernate.test.bidi.AuctionTest; +import org.hibernate.test.bidi.AuctionTest2; +import org.hibernate.test.bytecode.BytecodeSuite; +import org.hibernate.test.cache.CacheSuite; +import org.hibernate.test.cascade.RefreshTest; +import org.hibernate.test.cid.CompositeIdTest; +import org.hibernate.test.collection.CollectionSuite; +import org.hibernate.test.component.ComponentSuite; +import org.hibernate.test.compositeelement.CompositeElementTest; +import org.hibernate.test.connections.ConnectionsSuite; +import org.hibernate.test.criteria.CriteriaQueryTest; +import org.hibernate.test.cuk.CompositePropertyRefTest; +import org.hibernate.test.cut.CompositeUserTypeTest; +import org.hibernate.test.deletetransient.DeleteTransientEntityTest; +import org.hibernate.test.dialect.functional.DialectFunctionalTestsSuite; +import org.hibernate.test.dialect.unit.DialectUnitTestsSuite; +import org.hibernate.test.discriminator.DiscriminatorTest; +import org.hibernate.test.dynamicentity.interceptor.InterceptorDynamicEntityTest; +import org.hibernate.test.dynamicentity.tuplizer.TuplizerDynamicEntityTest; +import org.hibernate.test.ecid.EmbeddedCompositeIdTest; +import org.hibernate.test.entitymode.EntityModeSuite; +import org.hibernate.test.exception.SQLExceptionConversionTest; +import org.hibernate.test.extralazy.ExtraLazyTest; +import org.hibernate.test.filter.DynamicFilterTest; +import org.hibernate.test.formulajoin.FormulaJoinTest; +import org.hibernate.test.generated.GeneratedPropertySuite; +import org.hibernate.test.generatedkeys.GeneratedKeysSuite; +import org.hibernate.test.hql.HQLSuite; +import org.hibernate.test.id.MultipleHiLoPerTableGeneratorTest; +import org.hibernate.test.idbag.IdBagTest; +import org.hibernate.test.idclass.IdClassTest; +import org.hibernate.test.idprops.IdentifierPropertyReferencesTest; +import org.hibernate.test.immutable.ImmutableTest; +import org.hibernate.test.insertordering.InsertOrderingTest; +import org.hibernate.test.instrument.buildtime.InstrumentTest; +import org.hibernate.test.instrument.runtime.CGLIBInstrumentationTest; +import org.hibernate.test.instrument.runtime.JavassistInstrumentationTest; +import org.hibernate.test.interceptor.InterceptorTest; +import org.hibernate.test.interfaceproxy.InterfaceProxyTest; +import org.hibernate.test.iterate.IterateTest; +import org.hibernate.test.join.JoinTest; +import org.hibernate.test.joinedsubclass.JoinedSubclassTest; +import org.hibernate.test.joinfetch.JoinFetchTest; +import org.hibernate.test.jpa.JPAComplianceSuite; +import org.hibernate.test.keymanytoone.KeyManyToOneSuite; +import org.hibernate.test.lazycache.InstrumentCacheTest; +import org.hibernate.test.lazycache.InstrumentCacheTest2; +import org.hibernate.test.lazyonetoone.LazyOneToOneTest; +import org.hibernate.test.legacy.ABCProxyTest; +import org.hibernate.test.legacy.ABCTest; +import org.hibernate.test.legacy.CacheTest; +import org.hibernate.test.legacy.ComponentNotNullTest; +import org.hibernate.test.legacy.ConfigurationPerformanceTest; +import org.hibernate.test.legacy.FooBarTest; +import org.hibernate.test.legacy.FumTest; +import org.hibernate.test.legacy.IJ2Test; +import org.hibernate.test.legacy.IJTest; +import org.hibernate.test.legacy.MapTest; +import org.hibernate.test.legacy.MasterDetailTest; +import org.hibernate.test.legacy.MultiTableTest; +import org.hibernate.test.legacy.NonReflectiveBinderTest; +import org.hibernate.test.legacy.OneToOneCacheTest; +import org.hibernate.test.legacy.ParentChildTest; +import org.hibernate.test.legacy.QueryByExampleTest; +import org.hibernate.test.legacy.SQLFunctionsTest; +import org.hibernate.test.legacy.SQLLoaderTest; +import org.hibernate.test.legacy.StatisticsTest; +import org.hibernate.test.lob.LobSuite; +import org.hibernate.test.manytomany.ManyToManyTest; +import org.hibernate.test.map.MapIndexFormulaTest; +import org.hibernate.test.mapcompelem.MapCompositeElementTest; +import org.hibernate.test.mapelemformula.MapElementFormulaTest; +import org.hibernate.test.mapping.PersistentClassVisitorTest; +import org.hibernate.test.mapping.ValueVisitorTest; +import org.hibernate.test.mappingexception.MappingExceptionTest; +import org.hibernate.test.mixed.MixedTest; +import org.hibernate.test.naturalid.NaturalIdSuite; +import org.hibernate.test.ondelete.OnDeleteTest; +import org.hibernate.test.onetomany.OneToManyTest; +import org.hibernate.test.onetoone.OneToOneSuite; +import org.hibernate.test.ops.OpsSuite; +import org.hibernate.test.optlock.OptimisticLockTest; +import org.hibernate.test.ordered.OrderByTest; +import org.hibernate.test.orphan.OrphanSuite; +import org.hibernate.test.pagination.PaginationTest; +import org.hibernate.test.propertyref.PropertyRefSuite; +import org.hibernate.test.proxy.ProxyTest; +import org.hibernate.test.querycache.QueryCacheTest; +import org.hibernate.test.readonly.ReadOnlyTest; +import org.hibernate.test.reattachment.ReattachmentSuite; +import org.hibernate.test.rowid.RowIdTest; +import org.hibernate.test.sorted.SortTest; +import org.hibernate.test.sql.NativeSqlSupportSuite; +import org.hibernate.test.stats.SessionStatsTest; +import org.hibernate.test.stats.StatsTest; +import org.hibernate.test.subclassfilter.DiscrimSubclassFilterTest; +import org.hibernate.test.subclassfilter.JoinedSubclassFilterTest; +import org.hibernate.test.subclassfilter.UnionSubclassFilterTest; +import org.hibernate.test.subselect.SubselectTest; +import org.hibernate.test.subselectfetch.SubselectFetchTest; +import org.hibernate.test.ternary.TernaryTest; +import org.hibernate.test.timestamp.TimestampTest; +import org.hibernate.test.tm.CMTTest; +import org.hibernate.test.typedmanytoone.TypedManyToOneTest; +import org.hibernate.test.typedonetoone.TypedOneToOneTest; +import org.hibernate.test.typeparameters.TypeParameterTest; +import org.hibernate.test.unconstrained.UnconstrainedTest; +import org.hibernate.test.unidir.BackrefTest; +import org.hibernate.test.unionsubclass.UnionSubclassTest; +import org.hibernate.test.usercollection.UserCollectionTypeSuite; +import org.hibernate.test.util.UtilSuite; +import org.hibernate.test.version.VersionTest; +import org.hibernate.test.version.db.DbVersionTest; +import org.hibernate.test.version.sybase.SybaseTimestampVersioningTest; +import org.hibernate.test.where.WhereTest; + +/** + * @author Gavin King + */ +public class AllTests { + + /** + * Returns the entire test suite (both legacy and new + * + * @return the entire test suite + */ + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest( NewTests.suite() ); + suite.addTest( LegacyTests.suite() ); + return suite; + } + + /** + * Returns the entire test suite (both legacy and new) w/o filtering + * + * @return the entire test suite + */ + public static Test unfilteredSuite() { + TestSuite suite = new TestSuite(); + suite.addTest( NewTests.unfilteredSuite() ); + suite.addTest( LegacyTests.unfilteredSuite() ); + return suite; + } + + /** + * Runs the entire test suite. + *

+ * @see #suite + * @param args n/a + */ + public static void main(String args[]) { + TestRunner.run( suite() ); + } + + /** + * An inner class representing the new test suite. + */ + public static class NewTests { + + /** + * Returns the new test suite (filtered) + * + * @return the new test suite + */ + public static Test suite() { + return filter( ( TestSuite ) unfilteredSuite() ); + } + + + /** + * Returns the new test suite (unfiltered) + * + * @return the new test suite + */ + public static Test unfilteredSuite() { + TestSuite suite = new TestSuite("New tests suite"); + suite.addTest( OpsSuite.suite() ); + suite.addTest( NaturalIdSuite.suite() ); + suite.addTest( ComponentSuite.suite() ); + suite.addTest( ProxyTest.suite() ); + suite.addTest( VersionTest.suite() ); + suite.addTest( TimestampTest.suite() ); + suite.addTest( InterceptorTest.suite() ); + suite.addTest( EmbeddedCompositeIdTest.suite() ); + suite.addTest( ImmutableTest.suite() ); + suite.addTest( ReadOnlyTest.suite() ); + suite.addTest( IdClassTest.suite() ); + suite.addTest( ArrayTest.suite() ); + suite.addTest( TernaryTest.suite() ); + suite.addTest( CollectionSuite.suite() ); + suite.addTest( IdBagTest.suite() ); + suite.addTest( MapCompositeElementTest.suite() ); + suite.addTest( MapIndexFormulaTest.suite() ); + suite.addTest( MapElementFormulaTest.suite() ); + suite.addTest( BackrefTest.suite() ); + suite.addTest( BatchFetchTest.suite() ); + suite.addTest( CompositeIdTest.suite() ); + suite.addTest( CompositeElementTest.suite() ); + suite.addTest( CompositePropertyRefTest.suite() ); + suite.addTest( FormulaJoinTest.suite() ); + suite.addTest( DiscriminatorTest.suite() ); + suite.addTest( EntityModeSuite.suite() ); + suite.addTest( DynamicFilterTest.suite() ); + suite.addTest( InterfaceProxyTest.suite() ); + suite.addTest( OrphanSuite.suite() ); + suite.addTest( JoinTest.suite() ); + suite.addTest( JoinedSubclassTest.suite() ); + suite.addTest( org.hibernate.test.unionsubclass2.UnionSubclassTest.suite() ); + suite.addTest( MixedTest.suite() ); + suite.addTest( OneToManyTest.suite() ); + suite.addTest( ManyToManyTest.suite() ); + suite.addTest( OneToOneSuite.suite() ); + suite.addTest( OptimisticLockTest.suite() ); + suite.addTest( PropertyRefSuite.suite() ); + suite.addTest( NativeSqlSupportSuite.suite() ); + suite.addTest( CriteriaQueryTest.suite() ); + suite.addTest( SubselectTest.suite() ); + suite.addTest( SubselectFetchTest.suite() ); + suite.addTest( JoinFetchTest.suite() ); + suite.addTest( UnionSubclassTest.suite() ); + suite.addTest( ASTIteratorTest.suite() ); + suite.addTest( HQLSuite.suite() ); + suite.addTest( ASTUtilTest.suite() ); + suite.addTest( CacheSuite.suite() ); + suite.addTest( QueryCacheTest.suite() ); + suite.addTest( CompositeUserTypeTest.suite() ); + suite.addTest( TypeParameterTest.suite() ); + suite.addTest( TypedOneToOneTest.suite() ); + suite.addTest( TypedManyToOneTest.suite() ); + suite.addTest( CMTTest.suite() ); + suite.addTest( MultipleHiLoPerTableGeneratorTest.suite() ); + suite.addTest( UnionSubclassFilterTest.suite() ); + suite.addTest( JoinedSubclassFilterTest.suite() ); + suite.addTest( DiscrimSubclassFilterTest.suite() ); + suite.addTest( UnconstrainedTest.suite() ); + suite.addTest( RowIdTest.suite() ); + suite.addTest( OnDeleteTest.suite() ); + suite.addTest( OrderByTest.suite() ); + suite.addTest( SortTest.suite() ); + suite.addTest( WhereTest.suite() ); + suite.addTest( IterateTest.suite() ); + suite.addTest( RefreshTest.suite() ); + suite.addTest( ExtraLazyTest.suite() ); + suite.addTest( StatsTest.suite() ); + suite.addTest( SessionStatsTest.suite() ); + suite.addTest( ConnectionsSuite.suite() ); + suite.addTest( SQLExceptionConversionTest.suite() ); + suite.addTest( ValueVisitorTest.suite() ); + suite.addTest( PersistentClassVisitorTest.suite() ); + suite.addTest( AuctionTest.suite() ); + suite.addTest( AuctionTest2.suite() ); + suite.addTest( PaginationTest.suite() ); + suite.addTest( MappingExceptionTest.suite() ); + if ( InstrumentTest.isRunnable() ) { + suite.addTest( InstrumentTest.suite() ); + } + if ( LazyOneToOneTest.isRunnable() ) { + suite.addTest( LazyOneToOneTest.suite() ); + } + if ( InstrumentCacheTest.isRunnable() ) { + suite.addTest( InstrumentCacheTest.suite() ); + } + if ( InstrumentCacheTest2.isRunnable() ) { + suite.addTest( InstrumentCacheTest2.suite() ); + } + suite.addTest( CGLIBInstrumentationTest.suite() ); + suite.addTest( JavassistInstrumentationTest.suite() ); + suite.addTest( SybaseTimestampVersioningTest.suite() ); + suite.addTest( DbVersionTest.suite() ); + suite.addTest( GeneratedPropertySuite.suite() ); + suite.addTest( GeneratedKeysSuite.suite() ); + suite.addTest( InterceptorDynamicEntityTest.suite() ); + suite.addTest( TuplizerDynamicEntityTest.suite() ); + suite.addTest( BytecodeSuite.suite() ); + suite.addTest( JPAComplianceSuite.suite() ); + suite.addTest( AbstractComponentPropertyRefTest.suite() ); + suite.addTest( AbstractCompositeIdTest.suite() ); + suite.addTest( UtilSuite.suite() ); + suite.addTest( AnyTypeTest.suite() ); + suite.addTest( LobSuite.suite() ); + suite.addTest( IdentifierPropertyReferencesTest.suite() ); + suite.addTest( DeleteTransientEntityTest.suite() ); + suite.addTest( UserCollectionTypeSuite.suite() ); + suite.addTest( KeyManyToOneSuite.suite() ); + suite.addTest( DialectFunctionalTestsSuite.suite() ); + suite.addTest( DialectUnitTestsSuite.suite() ); + suite.addTest( InsertOrderingTest.suite() ); + suite.addTest( ReattachmentSuite.suite() ); + + return suite; + } + + /** + * Runs the new test suite + * + * @param args n/a + */ + public static void main(String[] args) { + TestRunner.run( suite() ); + } + } + + /** + * An inner class representing the legacy test suite. + */ + public static class LegacyTests { + + /** + * Returns the legacy test suite + * + * @return the legacy test suite + */ + public static Test suite() { + return filter( ( TestSuite ) unfilteredSuite() ); + } + + public static Test unfilteredSuite() { + TestSuite suite = new TestSuite("Legacy tests suite"); + suite.addTest( FumTest.suite() ); + suite.addTest( MasterDetailTest.suite() ); + suite.addTest( ParentChildTest.suite() ); + suite.addTest( ABCTest.suite() ); + suite.addTest( ABCProxyTest.suite() ); + suite.addTest( SQLFunctionsTest.suite() ); + suite.addTest( SQLLoaderTest.suite() ); + suite.addTest( MultiTableTest.suite() ); + suite.addTest( MapTest.suite() ); + suite.addTest( QueryByExampleTest.suite() ); + suite.addTest( ComponentNotNullTest.suite() ); + suite.addTest( IJTest.suite() ); + suite.addTest( IJ2Test.suite() ); + suite.addTest( FooBarTest.suite() ); + suite.addTest( StatisticsTest.suite() ); + suite.addTest( CacheTest.suite() ); + suite.addTest( OneToOneCacheTest.suite() ); + suite.addTest( NonReflectiveBinderTest.suite() ); + suite.addTest( ConfigurationPerformanceTest.suite() ); // Added to ensure we can utilize the recommended performance tips ;) + return suite; + } + + /** + * Run the legacy test suite + * + * @param args n/a + */ + public static void main(String[] args) { + TestRunner.run( suite() ); + } + } + + private static TestSuite filter(TestSuite testSuite) { + FilterHandler handler = new FilterHandler(); + TestSuiteVisitor visitor = new TestSuiteVisitor( handler ); + visitor.visit( testSuite ); + return handler.getFilteredTestSuite(); + } + + private static class TestSuiteStackEntry { + public final TestSuite testSuite; + public final TestSuiteStackEntry parentEntry; + + public TestSuiteStackEntry(TestSuite testSuite, TestSuiteStackEntry parentEntry) { + this.testSuite = testSuite; + this.parentEntry = parentEntry; + if ( parentEntry != null ) { + parentEntry.testSuite.addTest( testSuite ); + } + } + } + + private static class FilterHandler implements TestSuiteVisitor.Handler { + private TestSuiteStackEntry topStackElement; + private TestSuiteStackEntry currentStackElement; + private Dialect dialect = Dialect.getDialect(); + + public void handleTestCase(Test test) { + if ( test instanceof TestCase ) { + TestCase hibernateTestCase = ( TestCase ) test; + if ( ! hibernateTestCase.appliesTo( dialect ) ) { + System.out.println( "skipping test [" + hibernateTestCase.fullTestName() + "] for dialect [" + dialect.getClass().getName() + "]" ); + } + else { + currentStackElement.testSuite.addTest( test ); + } + } + else { + currentStackElement.testSuite.addTest( test ); + } + } + + public void startingTestSuite(TestSuite suite) { + currentStackElement = new TestSuiteStackEntry( instantiateCopy( suite ), currentStackElement ); + if ( topStackElement == null ) { + topStackElement = currentStackElement; + } + } + + public void completedTestSuite(TestSuite suite) { + if ( currentStackElement != null ) { + currentStackElement = currentStackElement.parentEntry; + } + } + + public TestSuite getFilteredTestSuite() { + return topStackElement.testSuite; + } + + private static final Class[] EXPECTED_CTOR_SIG = new Class[] { String.class }; + + private TestSuite instantiateCopy(TestSuite suite) { + try { + Class testSuiteClass = suite.getClass(); + Constructor ctor = testSuiteClass.getDeclaredConstructor( EXPECTED_CTOR_SIG ); + ctor.setAccessible( true ); + return ( TestSuite ) ctor.newInstance( new Object[] { suite.getName() } ); + } + catch ( Throwable t ) { + throw new RuntimeException( "Unable to build test suite copy [" + suite + "]", t ); + } + } + } +} \ No newline at end of file diff --git a/test/org/hibernate/test/TestCase.java b/test/org/hibernate/test/TestCase.java new file mode 100644 index 0000000000..f47a88dc0f --- /dev/null +++ b/test/org/hibernate/test/TestCase.java @@ -0,0 +1,616 @@ +//$Id$ +package org.hibernate.test; + +import java.sql.Blob; +import java.sql.Clob; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import junit.framework.AssertionFailedError; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.HibernateException; +import org.hibernate.Interceptor; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.DerbyDialect; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.mapping.Collection; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.SimpleValue; + +public abstract class TestCase extends junit.framework.TestCase { + + private static SessionFactory sessions; + private static Configuration cfg; + private static Dialect dialect; + private static Class lastTestClass; + private org.hibernate.classic.Session session; + + public TestCase(String name) { + super( name ); + } + + + // methods for subclasses to change test environment ~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Get the mapping resources to be used to build the configuration. + *

+ * Resources should be relative to {@link #getBaseForMappings()} + * + * @return The mapping resources + */ + protected abstract String[] getMappings(); + + /** + * The base name for relative mapping resources. The default is + * org/hibernate/test/ + * + * @return the mapping resource base + */ + protected String getBaseForMappings() { + return "org/hibernate/test/"; + } + + /** + * Should the database schema be (re)created + * + * @return True for auto export (including recreation on test failure). + */ + protected boolean recreateSchema() { + return true; + } + + protected boolean dropAfterFailure() { + return true; + } + + /** + * Apply any test-specific configuration prior to building the factory. + * + * @param cfg The configuration which will be used to construct the factory. + */ + protected void configure(Configuration cfg) { + } + + protected boolean overrideCacheStrategy() { + return true; + } + + protected String getCacheConcurrencyStrategy() { + return "nonstrict-read-write"; + } + + + // methods for subclasses to access environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Get the factory for this test environment. + * + * @return The factory. + */ + protected SessionFactory getSessions() { + return sessions; + } + + /** + * Get the factory for this test environment, casted to {@link SessionFactoryImplementor}. + *

+ * Shorthand for ( {@link SessionFactoryImplementor} ) {@link #getSessions()}... + * + * @return The factory + */ + protected SessionFactoryImplementor sfi() { + return ( SessionFactoryImplementor ) getSessions(); + } + + protected Dialect getDialect() { + if ( dialect == null ) { + dialect = Dialect.getDialect(); + } + return dialect; + } + + protected Configuration getCfg() { + return cfg; + } + + public org.hibernate.classic.Session openSession() throws HibernateException { + session = getSessions().openSession(); + return session; + } + + public org.hibernate.classic.Session openSession(Interceptor interceptor) + throws HibernateException { + session = getSessions().openSession(interceptor); + return session; + } + + + // JUnit hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * The Hibernate test suite tries to only build the db schema once + * per test class (not test case which = instance) hence all the + * static vars. + *

+ * Here is the crux of that attempt. We only build a factory when one was + * not previously built, or when we start a new test class. + * + * @throws Exception + */ + protected void setUp() throws Exception { + if ( getSessions() == null || lastTestClass != getClass() ) { + buildSessionFactory(); + lastTestClass = getClass(); + } + } + + + private void buildSessionFactory() throws Exception { + if ( getSessions()!=null ) { + getSessions().close(); + } + + TestCase.dialect = Dialect.getDialect(); + if ( ! appliesTo( getDialect() ) ) { + return; + } + + try { + + TestCase.cfg = new Configuration(); + cfg.setProperty( Environment.CACHE_PROVIDER, "org.hibernate.cache.HashtableCacheProvider" ); + if( recreateSchema() ) { + cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); + } + addMappings( getMappings(), cfg ); + configure( cfg ); + + if ( getCacheConcurrencyStrategy() != null ) { + Iterator iter = cfg.getClassMappings(); + while ( iter.hasNext() ) { + PersistentClass clazz = (PersistentClass) iter.next(); + Iterator props = clazz.getPropertyClosureIterator(); + boolean hasLob = false; + while ( props.hasNext() ) { + Property prop = (Property) props.next(); + if ( prop.getValue().isSimpleValue() ) { + String type = ( (SimpleValue) prop.getValue() ).getTypeName(); + if ( "blob".equals(type) || "clob".equals(type) ) hasLob = true; + if ( Blob.class.getName().equals(type) || Clob.class.getName().equals(type) ) hasLob = true; + } + } + if ( !hasLob && !clazz.isInherited() && overrideCacheStrategy() ) { + cfg.setCacheConcurrencyStrategy( + clazz.getEntityName(), + getCacheConcurrencyStrategy() + ); + } + } + iter = cfg.getCollectionMappings(); + while ( iter.hasNext() ) { + Collection coll = (Collection) iter.next(); + cfg.setCollectionCacheConcurrencyStrategy( + coll.getRole(), + getCacheConcurrencyStrategy() + ); + } + } + + // make sure we use the same dialect... + cfg.setProperty( Environment.DIALECT, TestCase.dialect.getClass().getName() ); + TestCase.sessions = cfg.buildSessionFactory(); + afterSessionFactoryBuilt(); + } + catch ( Exception e ) { + e.printStackTrace(); + throw e; + } + } + + protected void addMappings(String[] files, Configuration cfg) { + for ( int i = 0; i < files.length; i++ ) { + if ( !files[i].startsWith( "net/" ) ) { + files[i] = getBaseForMappings() + files[i]; + } + cfg.addResource( files[i], TestCase.class.getClassLoader() ); + } + } + + protected void afterSessionFactoryBuilt() throws Exception { + // for subclasses to override in order to perform extra "stuff" only + // when SF (re)built... + } + + protected void runTest() throws Throwable { + final boolean stats = sessions.getStatistics().isStatisticsEnabled(); + try { + if ( stats ) { + sessions.getStatistics().clear(); + } + + super.runTest(); + + if ( stats ) { + sessions.getStatistics().logSummary(); + } + + if ( session != null && session.isOpen() ) { + if ( session.isConnected() ) { + session.connection().rollback(); + } + session.close(); + session = null; + fail( "unclosed session" ); + } + else { + session = null; + } + assertAllDataRemoved(); + } + catch ( Throwable e ) { + try { + if ( session != null && session.isOpen() ) { + if ( session.isConnected() ) { + session.connection().rollback(); + } + session.close(); + } + } + catch ( Exception ignore ) { + } + try { + if ( dropAfterFailure() && sessions != null ) { + sessions.close(); + sessions = null; + } + } + catch ( Exception ignore ) { + } + throw e; + } + } + + public void runBare() throws Throwable { + String sysPropName = "hibernate.test.validatefailureexpected"; + assertNotNull( getName() ); + if ( Boolean.getBoolean( sysPropName ) ) { + if ( getName().endsWith( "FailureExpected" ) ) { + Throwable t = null; + try { + super.runBare(); + } + catch ( Throwable afe ) { + t = afe; + } + if ( t == null ) { + fail( "Test where marked as FailureExpected, but did not fail!" ); + } + else { + reportSkip( "ignoring *FailuredExpected methods", "Failed with: " + t.toString() ); + } + } + else { + super.runBare(); + } + } + else { + super.runBare(); + } + } + + protected void assertAllDataRemoved() { + if ( !recreateSchema() ) { + return; // no tables were created... + } + if ( !Boolean.getBoolean( "hibernate.test.validateDataCleanup" ) ) { + return; + } + + Session tmpSession = sessions.openSession(); + try { + List list = tmpSession.createQuery( "select o from java.lang.Object o" ).list(); + + Map items = new HashMap(); + if ( !list.isEmpty() ) { + for ( Iterator iter = list.iterator(); iter.hasNext(); ) { + Object element = iter.next(); + Integer l = ( Integer ) items.get( tmpSession.getEntityName( element ) ); + if ( l == null ) { + l = new Integer( 0 ); + } + l = new Integer( l.intValue() + 1 ); + items.put( tmpSession.getEntityName( element ), l ); + System.out.println( "Data left: " + element ); + } + fail( "Data is left in the database: " + items.toString() ); + } + } + finally { + try { + tmpSession.close(); + } + catch( Throwable t ) { + // intentionally empty + } + } + } + + public static void assertElementTypeAssignability(java.util.Collection collection, Class clazz) throws AssertionFailedError { + Iterator itr = collection.iterator(); + while ( itr.hasNext() ) { + assertClassAssignability( itr.next().getClass(), clazz ); + } + } + + public static void assertClassAssignability(Class source, Class target) throws AssertionFailedError { + if ( !target.isAssignableFrom( source ) ) { + throw new AssertionFailedError( + "Classes were not assignment-compatible : source<" + source.getName() + + "> target<" + target.getName() + ">" + ); + } + } + + + // test skipping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + protected static final Log SKIP_LOG = LogFactory.getLog("org.hibernate.test.SKIPPED"); + + public String fullTestName() { + return this.getName() + " (" + this.getClass().getName() + ")"; + } + + protected void reportSkip(String reason, String testDescription) { + SKIP_LOG.warn( "*** skipping [" + fullTestName() + "] - " + testDescription + " : " + reason, new Exception() ); + } + + /** + * Intended to indicate that this test class as a whole is intended for + * a dialect or series of dialects. Skips here (appliesTo = false) therefore + * simply indicate that the given tests target a particular feature of the + * checked database and none of the tests on this class should be run for the + * checked dialect. + * + * @param dialect The dialect to be checked. + * @return True if all the tests on this class apply to the given dialect (and + * therefore should be run); false otherwise. + */ + public boolean appliesTo(Dialect dialect) { + return true; + } + + /** + * Is connection at least read committed? + *

+ * Not, that this skip check relies on the JDBC driver reporting + * the true isolation level correctly. HSQLDB, for example, will + * report whatever you specify as the isolation + * (Connection.setTransationIsolation()), even though it only supports + * read-uncommitted. + * + * @param scenario text description of the scenario being tested. + * @return true if read-committed isolation is maintained. + */ + protected boolean readCommittedIsolationMaintained(String scenario) { + int isolation = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED; + Session testSession = null; + try { + testSession = openSession(); + isolation = testSession.connection().getTransactionIsolation(); + } + catch( Throwable ignore ) { + } + finally { + if ( testSession != null ) { + try { + testSession.close(); + } + catch( Throwable ignore ) { + } + } + } + if ( isolation < java.sql.Connection.TRANSACTION_READ_COMMITTED ) { + reportSkip( "environment does not support at least read committed isolation", scenario ); + return false; + } + else { + return true; + } + } + + /** + * Does the db/dialect support using a column's physical name in the order-by clause + * even after it has been aliased in the select clause. This is not actually + * required by the SQL spec, although virtually ever DB in the world supports this + * (the most glaring omission here being IBM-variant DBs ala DB2 and Derby). + * + * @param testDescription description of the scenario being tested. + * @return true if is allowed + */ + protected boolean allowsPhysicalColumnNameInOrderby(String testDescription) { + if ( DB2Dialect.class.isInstance( getDialect() ) ) { + // https://issues.apache.org/jira/browse/DERBY-1624 + reportSkip( "Dialect does not support physical column name in order-by clause after it is aliased", testDescription ); + return false; + } + return true; + } + + /** + * Does the db/dialect support using a column's physical name in the having clause + * even after it has been aliased in the select/group-by clause. This is not actually + * required by the SQL spec, although virtually ever DB in the world supports this. + * + * @param testDescription description of the scenario being tested. + * @return true if is allowed + */ + protected boolean allowsPhysicalColumnNameInHaving(String testDescription) { + // I only *know* of this being a limitation on Derby, although I highly suspect + // it is a limitation on any IBM/DB2 variant + if ( DerbyDialect.class.isInstance( getDialect() ) ) { + // https://issues.apache.org/jira/browse/DERBY-1624 + reportSkip( "Dialect does not support physical column name in having clause after it is aliased", testDescription ); + return false; + } + return true; + } + + /** + * Does the db/dialect support empty lists in the IN operator? + *

+ * For example, is "... a.b IN () ..." supported? + * + * @param testDescription description of the scenario being tested. + * @return true if is allowed + */ + protected boolean dialectSupportsEmptyInList(String testDescription) { + if ( ! getDialect().supportsEmptyInList() ) { + reportSkip( "Dialect does not support SQL empty in list : x in ()", testDescription ); + return false; + } + return true; + } + + /** + * Is the db/dialect sensitive in terms of string comparisons? + * @param testDescription description of the scenario being tested. + * @return true if sensitive + */ + protected boolean dialectIsCaseSensitive(String testDescription) { + if ( getDialect().areStringComparisonsCaseInsensitive() ) { + reportSkip( "Dialect is case sensitive. ", testDescription ); + return true; + } + return false; + } + + protected boolean supportsRowValueConstructorSyntaxInInList() { + if ( ! getDialect().supportsRowValueConstructorSyntaxInInList() ) { + reportSkip( "Dialect does not support 'tuple' syntax as part of an IN value list", "query support" ); + return false; + } + return true; + } + + protected boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() { + if ( ! getDialect().supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() ) { + reportSkip( "Driver does not support 'position query' methods on forward-only cursors", "query support" ); + return false; + } + return true; + } + + protected boolean supportsCircularCascadeDelete() { + if ( ! getDialect().supportsCircularCascadeDeleteConstraints() ) { + reportSkip( "db/dialect does not support 'circular' cascade delete constraints", "cascade delete constraint support" ); + return false; + } + return true; + } + + protected boolean supportsSubselectOnLeftSideIn() { + if ( ! getDialect().supportsSubselectAsInPredicateLHS() ) { + reportSkip( "Database does not support () in ( ... ) ", "query support" ); + return false; + } + return true; + } + + /** + * Expected LOB usage pattern is such that I can perform an insert + * via prepared statement with a parameter binding for a LOB value + * without crazy casting to JDBC driver implementation-specific classes... + *

+ * Part of the trickiness here is the fact that this is largely + * driver dependent. For Oracle, which is notoriously bad with + * LOB support in their drivers actually does a pretty good job with + * LOB support as of the 10.2.x versions of their drivers... + * + * @return True if expected usage pattern is support; false otherwise. + */ + protected boolean supportsExpectedLobUsagePattern() { + if ( ! getDialect().supportsExpectedLobUsagePattern() ) { + reportSkip( "database/driver does not support expected LOB usage pattern", "LOB support" ); + return false; + } + return true; + } + + /** + * Does the current dialect support propogating changes to LOB + * values back to the database? Talking about mutating the + * underlying value as opposed to supplying a new + * LOB instance... + * + * @return True if the changes are propogated back to the + * database; false otherwise. + */ + protected boolean supportsLobValueChangePropogation() { + if ( ! getDialect().supportsLobValueChangePropogation() ) { + reportSkip( "database/driver does not support propogating LOB value change back to database", "LOB support" ); + return false; + } + return true; + } + + /** + * Is it supported to materialize a LOB locator outside the transaction in + * which it was created? + *

+ * Again, part of the trickiness here is the fact that this is largely + * driver dependent. + *

+ * NOTE: all database I have tested which {@link #supportsExpectedLobUsagePattern()} + * also support the ability to materialize a LOB outside the owning transaction... + * + * @return True if unbounded materialization is supported; false otherwise. + */ + protected boolean supportsUnboundedLobLocatorMaterialization() { + if ( !getDialect().supportsUnboundedLobLocatorMaterialization() ) { + reportSkip( "database/driver does not support materializing a LOB locator outside the 'owning' transaction", "LOB support" ); + return false; + } + return true; + } + + protected boolean supportsSubqueryOnMutatingTable() { + if ( !getDialect().supportsSubqueryOnMutatingTable() ) { + reportSkip( "database/driver does not support referencing mutating table in subquery", "bulk DML support" ); + return false; + } + return true; + } + + protected boolean dialectIs(Class dialectClass) { + return dialectClass.isInstance( getDialect() ); + } + + protected boolean dialectIsOneOf(Class[] dialectClasses) { + for ( int i = 0; i < dialectClasses.length; i++ ) { + if ( dialectClasses[i].isInstance( getDialect() ) ) { + return true; + } + } + return false; + } + + protected boolean dialectIsNot(Class dialectClass) { + return ! dialectIs( dialectClass ); + } + + protected boolean dialectIsNot(Class[] dialectClasses) { + return ! dialectIsOneOf( dialectClasses ); + } + +} \ No newline at end of file diff --git a/test/org/hibernate/test/TestSelector.java b/test/org/hibernate/test/TestSelector.java new file mode 100644 index 0000000000..836db00134 --- /dev/null +++ b/test/org/hibernate/test/TestSelector.java @@ -0,0 +1,64 @@ +package org.hibernate.test; + +import java.util.Set; +import java.util.HashSet; +import java.io.File; + +import org.apache.tools.ant.types.selectors.FileSelector; +import org.apache.tools.ant.BuildException; + +import org.hibernate.junit.TestSuiteVisitor; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * A custom Ant FileSelector used to limit the tests run from the Ant + * build script to only those defined in the {@link org.hibernate.test.AllTests} suite. + *

+ * {@link org.hibernate.test.AllTests} is used/maintained by the developers to easily + * run the test suite in all IDEs. It represents all the tests + * which should actually be run and included in test results. + * + * @author Steve Ebersole + */ +public class TestSelector implements FileSelector { + + private final Set allTestClassNames = new HashSet(); + + public TestSelector() { + TestSuiteVisitor.Handler handler = new TestSuiteVisitor.Handler() { + public void handleTestCase(Test test) { + allTestClassNames.add( test.getClass().getName() ); + } + public void startingTestSuite(TestSuite suite) {} + public void completedTestSuite(TestSuite suite) {} + }; + TestSuiteVisitor visitor = new TestSuiteVisitor( handler ); + visitor.visit( ( TestSuite ) AllTests.suite() ); + } + + + // FileSelector impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public boolean isSelected(File dir, String fileFromDir, File fullFile) throws BuildException { + String correspondingClassName = determineClassName( fileFromDir ); + return allTestClassNames.contains( correspondingClassName ); + } + + private String determineClassName(String file) { + if ( file.endsWith( ".class" ) ) { + file = file.substring( 0, file.length() - 6 ); + } + else if ( file.endsWith( ".java" ) ) { + file = file.substring( 0, file.length() - 5 ); + } + else { + return null; + } + file = file.replace( '\\', '.' ); + file = file.replace( '/', '.' ); + return file; + } + +} diff --git a/test/org/hibernate/test/abstractembeddedcomponents/cid/AbstractCompositeIdTest.java b/test/org/hibernate/test/abstractembeddedcomponents/cid/AbstractCompositeIdTest.java new file mode 100644 index 0000000000..96b61fd558 --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/cid/AbstractCompositeIdTest.java @@ -0,0 +1,44 @@ +package org.hibernate.test.abstractembeddedcomponents.cid; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +import junit.framework.Test; + +/** + * @author Steve Ebersole + */ +public class AbstractCompositeIdTest extends FunctionalTestCase { + public AbstractCompositeIdTest(String x) { + super( x ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( AbstractCompositeIdTest.class ); + } + + public String[] getMappings() { + return new String[] { "abstractembeddedcomponents/cid/Mappings.hbm.xml" }; + } + + public void testEmbeddedCompositeIdentifierOnAbstractClass() { + MyInterfaceImpl myInterface = new MyInterfaceImpl(); + myInterface.setKey1( "key1" ); + myInterface.setKey2( "key2" ); + myInterface.setName( "test" ); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.save( myInterface ); + s.flush(); + + s.createQuery( "from MyInterface" ).list(); + + s.delete( myInterface ); + t.commit(); + s.close(); + + } +} diff --git a/test/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml b/test/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml new file mode 100644 index 0000000000..31b0d30f6d --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java b/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java new file mode 100644 index 0000000000..802277a75c --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java @@ -0,0 +1,15 @@ +package org.hibernate.test.abstractembeddedcomponents.cid; + +import java.io.Serializable; + +/** + * @author Steve Ebersole + */ +public interface MyInterface extends Serializable { + public String getKey1(); + public void setKey1(String key1); + public String getKey2(); + public void setKey2(String key2); + public String getName(); + public void setName(String name); +} diff --git a/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java b/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java new file mode 100644 index 0000000000..29db6751cb --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java @@ -0,0 +1,36 @@ +package org.hibernate.test.abstractembeddedcomponents.cid; + +import org.hibernate.test.abstractembeddedcomponents.cid.MyInterface; + +/** + * @author Steve Ebersole + */ +public class MyInterfaceImpl implements MyInterface { + private String key1; + private String key2; + private String name; + + public String getKey1() { + return key1; + } + + public void setKey1(String key1) { + this.key1 = key1; + } + + public String getKey2() { + return key2; + } + + public void setKey2(String key2) { + this.key2 = key2; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AbstractComponentPropertyRefTest.java b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AbstractComponentPropertyRefTest.java new file mode 100644 index 0000000000..b6057a19f5 --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AbstractComponentPropertyRefTest.java @@ -0,0 +1,49 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +import junit.framework.Test; + +/** + * @author Steve Ebersole + */ +public class AbstractComponentPropertyRefTest extends FunctionalTestCase { + public AbstractComponentPropertyRefTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( AbstractComponentPropertyRefTest.class ); + } + + public String[] getMappings() { + return new String[] { "abstractembeddedcomponents/propertyref/Mappings.hbm.xml" }; + } + + public void testPropertiesRefCascades() { + Session session = openSession(); + Transaction trans = session.beginTransaction(); + ServerImpl server = new ServerImpl(); + session.save( server ); + AddressImpl address = new AddressImpl(); + server.setAddress( address ); + address.setServer( server ); + session.flush(); + session.createQuery( "from Server s join fetch s.address" ).list(); + trans.commit(); + session.close(); + + assertNotNull( server.getId() ); + assertNotNull( address.getId() ); + + session = openSession(); + trans = session.beginTransaction(); + session.delete( address ); + session.delete( server ); + trans.commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java new file mode 100644 index 0000000000..204c0ac1bb --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java @@ -0,0 +1,13 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +/** + * @author Steve Ebersole + */ +public interface Address { + public Long getId(); + public void setId(Long id); + public String getAddressType(); + public void setAddressType(String addressType); + public Server getServer(); + public void setServer(Server server); +} diff --git a/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java new file mode 100644 index 0000000000..9b123e7ead --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java @@ -0,0 +1,36 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +import org.hibernate.test.abstractembeddedcomponents.propertyref.Address; + +/** + * @author Steve Ebersole + */ +public class AddressImpl implements Address { + private Long id; + private String addressType; + private Server server; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAddressType() { + return addressType; + } + + public void setAddressType(String addressType) { + this.addressType = addressType; + } + + public Server getServer() { + return server; + } + + public void setServer(Server server) { + this.server = server; + } +} diff --git a/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml new file mode 100644 index 0000000000..9531178498 --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java new file mode 100644 index 0000000000..9bf0719388 --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java @@ -0,0 +1,15 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +import org.hibernate.test.abstractembeddedcomponents.propertyref.Address; + +/** + * @author Steve Ebersole + */ +public interface Server { + public Long getId(); + public void setId(Long id); + public String getServerType(); + public void setServerType(String serverType); + public Address getAddress(); + public void setAddress(Address address); +} diff --git a/test/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java new file mode 100644 index 0000000000..8542dcaaa8 --- /dev/null +++ b/test/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java @@ -0,0 +1,37 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +import org.hibernate.test.abstractembeddedcomponents.propertyref.Address; +import org.hibernate.test.abstractembeddedcomponents.propertyref.Server; + +/** + * @author Steve Ebersole + */ +public class ServerImpl implements Server { + private Long id; + private String serverType; + private Address address; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getServerType() { + return serverType; + } + + public void setServerType(String serverType) { + this.serverType = serverType; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } +} diff --git a/test/org/hibernate/test/any/Address.java b/test/org/hibernate/test/any/Address.java new file mode 100644 index 0000000000..c5ff5dc3d5 --- /dev/null +++ b/test/org/hibernate/test/any/Address.java @@ -0,0 +1,30 @@ +package org.hibernate.test.any; + +import java.util.Set; +import java.util.HashSet; + +/** + * todo: describe Address + * + * @author Steve Ebersole + */ +public class Address { + private Long id; + private Set lines = new HashSet(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Set getLines() { + return lines; + } + + public void setLines(Set lines) { + this.lines = lines; + } +} diff --git a/test/org/hibernate/test/any/AnyTypeTest.java b/test/org/hibernate/test/any/AnyTypeTest.java new file mode 100644 index 0000000000..b9a4ea2fd8 --- /dev/null +++ b/test/org/hibernate/test/any/AnyTypeTest.java @@ -0,0 +1,59 @@ +package org.hibernate.test.any; + +import org.hibernate.Session; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.junit.functional.FunctionalTestCase; + +import junit.framework.Test; + +/** + * todo: describe AnyTypeTest + * + * @author Steve Ebersole + */ +public class AnyTypeTest extends FunctionalTestCase { + public AnyTypeTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "any/Person.hbm.xml" }; + } + + public String getCacheConcurrencyStrategy() { + // having second level cache causes a condition whereby the original test case would not fail... + return null; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( AnyTypeTest.class ); + } + + /** + * Specific test for HHH-1663... + */ + public void testFlushProcessing() { + Session session = openSession(); + session.beginTransaction(); + Person person = new Person(); + Address address = new Address(); + person.setData( address ); + session.saveOrUpdate(person); + session.saveOrUpdate(address); + session.getTransaction().commit(); + session.close(); + + session = openSession(); + session.beginTransaction(); + person = (Person) session.load( Person.class, person.getId() ); + person.setName("makingpersondirty"); + session.getTransaction().commit(); + session.close(); + + session = openSession(); + session.beginTransaction(); + session.delete( person ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/any/ComplexPropertyValue.java b/test/org/hibernate/test/any/ComplexPropertyValue.java new file mode 100644 index 0000000000..3c84fc9980 --- /dev/null +++ b/test/org/hibernate/test/any/ComplexPropertyValue.java @@ -0,0 +1,47 @@ +package org.hibernate.test.any; + +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; + +/** + * todo: describe ${NAME} + * + * @author Steve Ebersole + */ +public class ComplexPropertyValue implements PropertyValue { + private Long id; + private Map subProperties = new HashMap(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Map getSubProperties() { + return subProperties; + } + + public void setSubProperties(Map subProperties) { + this.subProperties = subProperties; + } + + public String asString() { + return "complex[" + keyString() + "]"; + } + + private String keyString() { + StringBuffer buff = new StringBuffer(); + Iterator itr = subProperties.keySet().iterator(); + while ( itr.hasNext() ) { + buff.append( itr.next() ); + if ( itr.hasNext() ) { + buff.append( ", " ); + } + } + return buff.toString(); + } +} diff --git a/test/org/hibernate/test/any/IntegerPropertyValue.java b/test/org/hibernate/test/any/IntegerPropertyValue.java new file mode 100644 index 0000000000..5b19354d21 --- /dev/null +++ b/test/org/hibernate/test/any/IntegerPropertyValue.java @@ -0,0 +1,38 @@ +package org.hibernate.test.any; + +/** + * todo: describe IntegerPropertyValue + * + * @author Steve Ebersole + */ +public class IntegerPropertyValue implements PropertyValue { + private Long id; + private int value; + + public IntegerPropertyValue() { + } + + public IntegerPropertyValue(int value) { + this.value = value; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public String asString() { + return Integer.toString( value ); + } +} diff --git a/test/org/hibernate/test/any/Person.hbm.xml b/test/org/hibernate/test/any/Person.hbm.xml new file mode 100644 index 0000000000..ca3d07b95b --- /dev/null +++ b/test/org/hibernate/test/any/Person.hbm.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/any/Person.java b/test/org/hibernate/test/any/Person.java new file mode 100644 index 0000000000..d742934e66 --- /dev/null +++ b/test/org/hibernate/test/any/Person.java @@ -0,0 +1,37 @@ +package org.hibernate.test.any; + +/** + * todo: describe Person + * + * @author Steve Ebersole + */ +public class Person { + private Long id; + private String name; + private Object data; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/test/org/hibernate/test/any/Properties.hbm.xml b/test/org/hibernate/test/any/Properties.hbm.xml new file mode 100644 index 0000000000..f790630581 --- /dev/null +++ b/test/org/hibernate/test/any/Properties.hbm.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/any/PropertySet.java b/test/org/hibernate/test/any/PropertySet.java new file mode 100644 index 0000000000..721a4b82fb --- /dev/null +++ b/test/org/hibernate/test/any/PropertySet.java @@ -0,0 +1,55 @@ +package org.hibernate.test.any; + +import java.util.Map; +import java.util.HashMap; + +/** + * todo: describe PropertySet + * + * @author Steve Ebersole + */ +public class PropertySet { + private Long id; + private String name; + private PropertyValue someSpecificProperty; + private Map generalProperties = new HashMap(); + + public PropertySet() { + } + + public PropertySet(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public PropertyValue getSomeSpecificProperty() { + return someSpecificProperty; + } + + public void setSomeSpecificProperty(PropertyValue someSpecificProperty) { + this.someSpecificProperty = someSpecificProperty; + } + + public Map getGeneralProperties() { + return generalProperties; + } + + public void setGeneralProperties(Map generalProperties) { + this.generalProperties = generalProperties; + } +} diff --git a/test/org/hibernate/test/any/PropertyValue.java b/test/org/hibernate/test/any/PropertyValue.java new file mode 100644 index 0000000000..7111c36118 --- /dev/null +++ b/test/org/hibernate/test/any/PropertyValue.java @@ -0,0 +1,10 @@ +package org.hibernate.test.any; + +/** + * todo: describe PropertyValue + * + * @author Steve Ebersole + */ +public interface PropertyValue { + public String asString(); +} diff --git a/test/org/hibernate/test/any/StringPropertyValue.java b/test/org/hibernate/test/any/StringPropertyValue.java new file mode 100644 index 0000000000..12a8e25f60 --- /dev/null +++ b/test/org/hibernate/test/any/StringPropertyValue.java @@ -0,0 +1,38 @@ +package org.hibernate.test.any; + +/** + * todo: describe StringPropertyValue + * + * @author Steve Ebersole + */ +public class StringPropertyValue implements PropertyValue { + private Long id; + private String value; + + public StringPropertyValue() { + } + + public StringPropertyValue(String value) { + this.value = value; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String asString() { + return value; + } +} diff --git a/test/org/hibernate/test/array/A.hbm.xml b/test/org/hibernate/test/array/A.hbm.xml new file mode 100755 index 0000000000..31ab463751 --- /dev/null +++ b/test/org/hibernate/test/array/A.hbm.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/array/A.java b/test/org/hibernate/test/array/A.java new file mode 100755 index 0000000000..a696173ecc --- /dev/null +++ b/test/org/hibernate/test/array/A.java @@ -0,0 +1,26 @@ +//$Id$ +package org.hibernate.test.array; + +/** + * @author Emmanuel Bernard + */ +public class A { + private Integer id; + private B[] bs; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public B[] getBs() { + return bs; + } + + public void setBs(B[] bs) { + this.bs = bs; + } +} diff --git a/test/org/hibernate/test/array/ArrayTest.java b/test/org/hibernate/test/array/ArrayTest.java new file mode 100755 index 0000000000..6ee68f0ff1 --- /dev/null +++ b/test/org/hibernate/test/array/ArrayTest.java @@ -0,0 +1,53 @@ +//$Id$ +package org.hibernate.test.array; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Emmanuel Bernard + */ +public class ArrayTest extends FunctionalTestCase { + + public ArrayTest(String x) { + super( x ); + } + + public String[] getMappings() { + return new String[] { "array/A.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ArrayTest.class ); + } + + public void testArrayJoinFetch() throws Exception { + Session s; + Transaction tx; + s = openSession(); + tx = s.beginTransaction(); + A a = new A(); + B b = new B(); + a.setBs( new B[] {b} ); + s.persist( a ); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + a = (A) s.get( A.class, a.getId() ); + assertNotNull( a ); + assertNotNull( a.getBs() ); + assertEquals( a.getBs().length, 1 ); + assertNotNull( a.getBs()[0] ); + + s.delete(a); + s.delete(a.getBs()[0]); + tx.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/array/B.java b/test/org/hibernate/test/array/B.java new file mode 100755 index 0000000000..efd5beecc5 --- /dev/null +++ b/test/org/hibernate/test/array/B.java @@ -0,0 +1,17 @@ +//$Id$ +package org.hibernate.test.array; + +/** + * @author Emmanuel Bernard + */ +public class B { + private Integer id; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/test/org/hibernate/test/ast/ASTIteratorTest.java b/test/org/hibernate/test/ast/ASTIteratorTest.java new file mode 100644 index 0000000000..5d8dfe9018 --- /dev/null +++ b/test/org/hibernate/test/ast/ASTIteratorTest.java @@ -0,0 +1,120 @@ +// $Id$ +package org.hibernate.test.ast; + +import java.io.PrintWriter; + +import antlr.ASTFactory; +import antlr.collections.AST; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.hql.antlr.HqlTokenTypes; +import org.hibernate.hql.ast.HqlParser; +import org.hibernate.hql.ast.util.ASTIterator; +import org.hibernate.hql.ast.util.ASTParentsFirstIterator; +import org.hibernate.hql.ast.util.ASTPrinter; +import org.hibernate.hql.ast.util.ASTUtil; +import org.hibernate.junit.UnitTestCase; + +/** + * Test ASTIterator. + */ +public class ASTIteratorTest extends UnitTestCase { + private ASTFactory factory; + + /** + * Standard JUnit test case constructor. + * + * @param name The name of the test case. + */ + public ASTIteratorTest(String name) { + super( name ); + } + + public static Test suite() { + return new TestSuite( ASTIteratorTest.class ); + } + + protected void setUp() throws Exception { + super.setUp(); + factory = new ASTFactory(); + } + + /** + * Test a simple tree, make sure the iterator encounters every node. + */ + public void testSimpleTree() throws Exception { + String input = "select foo from foo in class org.hibernate.test.Foo, fee in class org.hibernate.test.Fee where foo.dependent = fee order by foo.string desc, foo.component.count asc, fee.id"; + HqlParser parser = HqlParser.getInstance( input ); + parser.statement(); + AST ast = parser.getAST(); + ASTPrinter printer = new ASTPrinter( HqlTokenTypes.class ); + printer.showAst( ast, new PrintWriter( System.out ) ); + ASTIterator iterator = new ASTIterator( ast ); + int count = 0; + while ( iterator.hasNext() ) { + assertTrue( iterator.next() instanceof AST ); + count++; + } + assertEquals( 43, count ); + + UnsupportedOperationException uoe = null; + try { + iterator.remove(); + } + catch ( UnsupportedOperationException e ) { + uoe = e; + } + assertNotNull( uoe ); + } + + public void testParentsFirstIterator() throws Exception { + AST[] tree = new AST[4]; + AST grandparent = tree[0] = ASTUtil.create( factory, 1, "grandparent" ); + AST parent = tree[1] = ASTUtil.create( factory, 2, "parent" ); + AST child = tree[2] = ASTUtil.create( factory, 3, "child" ); + AST baby = tree[3] = ASTUtil.create( factory, 4, "baby" ); + AST t = ASTUtil.createTree( factory, tree ); + AST brother = ASTUtil.create( factory, 10, "brother" ); + child.setNextSibling( brother ); + AST sister = ASTUtil.create( factory, 11, "sister" ); + brother.setNextSibling( sister ); + AST uncle = factory.make( new AST[]{ + factory.create( 20, "uncle" ), + factory.create( 21, "cousin1" ), + factory.create( 22, "cousin2" ), + factory.create( 23, "cousin3" )} ); + parent.setNextSibling( uncle ); + System.out.println( t.toStringTree() ); + + System.out.println( "--- ASTParentsFirstIterator ---" ); + ASTParentsFirstIterator iter = new ASTParentsFirstIterator( t ); + int count = 0; + while ( iter.hasNext() ) { + AST n = iter.nextNode(); + count++; + System.out.println( n ); + } + assertEquals( 10, count ); + + System.out.println( "--- ASTIterator ---" ); + ASTIterator iter2 = new ASTIterator( t ); + int count2 = 0; + while ( iter2.hasNext() ) { + AST n = iter2.nextNode(); + count2++; + System.out.println( n ); + } + assertEquals( 10, count2 ); + + System.out.println( "--- ASTParentsFirstIterator (parent) ---" ); + ASTParentsFirstIterator iter3 = new ASTParentsFirstIterator( parent ); + int count3 = 0; + while ( iter3.hasNext() ) { + AST n = iter3.nextNode(); + count3++; + System.out.println( n ); + } + assertEquals( 5, count3 ); + } +} diff --git a/test/org/hibernate/test/ast/ASTUtilTest.java b/test/org/hibernate/test/ast/ASTUtilTest.java new file mode 100644 index 0000000000..94ec397126 --- /dev/null +++ b/test/org/hibernate/test/ast/ASTUtilTest.java @@ -0,0 +1,77 @@ +// $Id$ +package org.hibernate.test.ast; + +import antlr.ASTFactory; +import antlr.collections.AST; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.hql.ast.util.ASTUtil; +import org.hibernate.junit.UnitTestCase; + +/** + * Unit test for ASTUtil. + */ +public class ASTUtilTest extends UnitTestCase { + private ASTFactory factory; + + /** + * Standard JUnit test case constructor. + * + * @param name The name of the test case. + */ + public ASTUtilTest(String name) { + super( name ); + } + + protected void setUp() throws Exception { + super.setUp(); + factory = new ASTFactory(); + } + + public void testCreate() throws Exception { + AST n = ASTUtil.create( factory, 1, "one"); + assertNull( n.getFirstChild() ); + assertEquals("one",n.getText()); + assertEquals(1,n.getType()); + } + /** + * Test adding a tree of children. + */ + public void testCreateTree() throws Exception { + AST[] tree = new AST[4]; + AST grandparent = tree[0] = ASTUtil.create(factory, 1, "grandparent"); + AST parent = tree[1] = ASTUtil.create(factory,2,"parent"); + AST child = tree[2] = ASTUtil.create(factory,3,"child"); + AST baby = tree[3] = ASTUtil.create(factory,4,"baby"); + AST t = ASTUtil.createTree( factory, tree); + assertSame(t,grandparent); + assertSame(parent,t.getFirstChild()); + assertSame(child,t.getFirstChild().getFirstChild()); + assertSame(baby,t.getFirstChild().getFirstChild().getFirstChild()); + } + + public void testFindPreviousSibling() throws Exception { + AST child1 = ASTUtil.create(factory,2, "child1"); + AST child2 = ASTUtil.create(factory,3, "child2"); + AST n = factory.make( new AST[] { + ASTUtil.create(factory, 1, "parent"), + child1, + child2, + }); + assertSame(child1,ASTUtil.findPreviousSibling( n,child2)); + Exception e = null; + try { + ASTUtil.findPreviousSibling(child1,null); + } + catch (Exception x) { + e = x; + } + assertNotNull(e); + } + + public static Test suite() { + return new TestSuite( ASTUtilTest.class ); + } + +} diff --git a/test/org/hibernate/test/batch/BatchTest.java b/test/org/hibernate/test/batch/BatchTest.java new file mode 100755 index 0000000000..fa63c37e50 --- /dev/null +++ b/test/org/hibernate/test/batch/BatchTest.java @@ -0,0 +1,89 @@ +//$Id$ +package org.hibernate.test.batch; + +import java.math.BigDecimal; + +import junit.framework.Test; + +import org.hibernate.CacheMode; +import org.hibernate.ScrollMode; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; + +/** + * This is how to do batch processing in Hibernate. + * Remember to enable JDBC batch updates, or this + * test will take a Very Long Time! + * + * @author Gavin King + */ +public class BatchTest extends FunctionalTestCase { + + public BatchTest(String str) { + super( str ); + } + + public String[] getMappings() { + return new String[] { "batch/DataPoint.hbm.xml" }; + } + + public String getCacheConcurrencyStrategy() { + return null; + } + + public void configure(Configuration cfg) { + cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "20" ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BatchTest.class ); + } + + public void testBatchInsertUpdate() { + long start = System.currentTimeMillis(); + final int N = 5000; //26 secs with batch flush, 26 without + //final int N = 100000; //53 secs with batch flush, OOME without + //final int N = 250000; //137 secs with batch flush, OOME without + + Session s = openSession(); + s.setCacheMode( CacheMode.IGNORE ); + Transaction t = s.beginTransaction(); + for ( int i = 0; i < N; i++ ) { + DataPoint dp = new DataPoint(); + dp.setX( new BigDecimal( i * 0.1d ).setScale( 19, BigDecimal.ROUND_DOWN ) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale( 19, BigDecimal.ROUND_DOWN ) ); + s.save( dp ); + if ( i % 20 == 0 ) { + s.flush(); + s.clear(); + } + } + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + int i = 0; + ScrollableResults sr = s.createQuery( "from DataPoint dp order by dp.x asc" ) + .scroll( ScrollMode.FORWARD_ONLY ); + while ( sr.next() ) { + DataPoint dp = ( DataPoint ) sr.get( 0 ); + dp.setDescription( "done!" ); + if ( ++i % 20 == 0 ) { + s.flush(); + s.clear(); + } + } + t.commit(); + s.close(); + System.out.println( System.currentTimeMillis() - start ); + } + +} + diff --git a/test/org/hibernate/test/batch/DataPoint.hbm.xml b/test/org/hibernate/test/batch/DataPoint.hbm.xml new file mode 100755 index 0000000000..d8e9db7510 --- /dev/null +++ b/test/org/hibernate/test/batch/DataPoint.hbm.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/batch/DataPoint.java b/test/org/hibernate/test/batch/DataPoint.java new file mode 100755 index 0000000000..bd459272e5 --- /dev/null +++ b/test/org/hibernate/test/batch/DataPoint.java @@ -0,0 +1,62 @@ +//$Id$ +package org.hibernate.test.batch; + +import java.math.BigDecimal; + +/** + * @author Gavin King + */ +public class DataPoint { + private long id; + private BigDecimal x; + private BigDecimal y; + private String description; + /** + * @return Returns the description. + */ + public String getDescription() { + return description; + } + /** + * @param description The description to set. + */ + public void setDescription(String description) { + this.description = description; + } + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(long id) { + this.id = id; + } + /** + * @return Returns the x. + */ + public BigDecimal getX() { + return x; + } + /** + * @param x The x to set. + */ + public void setX(BigDecimal x) { + this.x = x; + } + /** + * @return Returns the y. + */ + public BigDecimal getY() { + return y; + } + /** + * @param y The y to set. + */ + public void setY(BigDecimal y) { + this.y = y; + } +} diff --git a/test/org/hibernate/test/batchfetch/BatchFetchTest.java b/test/org/hibernate/test/batchfetch/BatchFetchTest.java new file mode 100755 index 0000000000..1e784a30da --- /dev/null +++ b/test/org/hibernate/test/batchfetch/BatchFetchTest.java @@ -0,0 +1,122 @@ +//$Id$ +package org.hibernate.test.batchfetch; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class BatchFetchTest extends FunctionalTestCase { + + public BatchFetchTest(String str) { + super( str ); + } + + public String[] getMappings() { + return new String[] { "batchfetch/ProductLine.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BatchFetchTest.class ); + } + + public void testBatchFetch() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + ProductLine cars = new ProductLine(); + cars.setDescription( "Cars" ); + Model monaro = new Model( cars ); + monaro.setName( "monaro" ); + monaro.setDescription( "Holden Monaro" ); + Model hsv = new Model( cars ); + hsv.setName( "hsv" ); + hsv.setDescription( "Holden Commodore HSV" ); + s.save( cars ); + + ProductLine oss = new ProductLine(); + oss.setDescription( "OSS" ); + Model jboss = new Model( oss ); + jboss.setName( "JBoss" ); + jboss.setDescription( "JBoss Application Server" ); + Model hibernate = new Model( oss ); + hibernate.setName( "Hibernate" ); + hibernate.setDescription( "Hibernate" ); + Model cache = new Model( oss ); + cache.setName( "JBossCache" ); + cache.setDescription( "JBoss TreeCache" ); + s.save( oss ); + + t.commit(); + s.close(); + + s.getSessionFactory().evict( Model.class ); + s.getSessionFactory().evict( ProductLine.class ); + + s = openSession(); + t = s.beginTransaction(); + + List list = s.createQuery( "from ProductLine pl order by pl.description" ).list(); + cars = ( ProductLine ) list.get( 0 ); + oss = ( ProductLine ) list.get( 1 ); + assertFalse( Hibernate.isInitialized( cars.getModels() ) ); + assertFalse( Hibernate.isInitialized( oss.getModels() ) ); + assertEquals( cars.getModels().size(), 2 ); //fetch both collections + assertTrue( Hibernate.isInitialized( cars.getModels() ) ); + assertTrue( Hibernate.isInitialized( oss.getModels() ) ); + + s.clear(); + + list = s.createQuery( "from Model m" ).list(); + hibernate = ( Model ) s.get( Model.class, hibernate.getId() ); + hibernate.getProductLine().getId(); + for ( Iterator i = list.iterator(); i.hasNext(); ) { + assertFalse( Hibernate.isInitialized( ( ( Model ) i.next() ).getProductLine() ) ); + } + assertEquals( hibernate.getProductLine().getDescription(), "OSS" ); //fetch both productlines + + s.clear(); + + Iterator iter = s.createQuery( "from Model" ).iterate(); + list = new ArrayList(); + while ( iter.hasNext() ) { + list.add( iter.next() ); + } + Model m = ( Model ) list.get( 0 ); + m.getDescription(); //fetch a batch of 4 + + s.clear(); + + list = s.createQuery( "from ProductLine" ).list(); + ProductLine pl = ( ProductLine ) list.get( 0 ); + ProductLine pl2 = ( ProductLine ) list.get( 1 ); + s.evict( pl2 ); + pl.getModels().size(); //fetch just one collection! (how can we write an assertion for that??) + + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + list = s.createQuery( "from ProductLine pl order by pl.description" ).list(); + cars = ( ProductLine ) list.get( 0 ); + oss = ( ProductLine ) list.get( 1 ); + assertEquals( cars.getModels().size(), 2 ); + assertEquals( oss.getModels().size(), 3 ); + s.delete( cars ); + s.delete( oss ); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/batchfetch/Model.java b/test/org/hibernate/test/batchfetch/Model.java new file mode 100755 index 0000000000..c1229bce1f --- /dev/null +++ b/test/org/hibernate/test/batchfetch/Model.java @@ -0,0 +1,44 @@ +//$Id$ +package org.hibernate.test.batchfetch; + +/** + * @author Gavin King + */ +public class Model { + private String id; + private String name; + private String description; + private ProductLine productLine; + + Model() {} + + public Model(ProductLine pl) { + this.productLine = pl; + pl.getModels().add(this); + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public ProductLine getProductLine() { + return productLine; + } + public void setProductLine(ProductLine productLine) { + this.productLine = productLine; + } +} diff --git a/test/org/hibernate/test/batchfetch/ProductLine.hbm.xml b/test/org/hibernate/test/batchfetch/ProductLine.hbm.xml new file mode 100755 index 0000000000..5ed506a327 --- /dev/null +++ b/test/org/hibernate/test/batchfetch/ProductLine.hbm.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/batchfetch/ProductLine.java b/test/org/hibernate/test/batchfetch/ProductLine.java new file mode 100755 index 0000000000..ab6e6875df --- /dev/null +++ b/test/org/hibernate/test/batchfetch/ProductLine.java @@ -0,0 +1,34 @@ +//$Id$ +package org.hibernate.test.batchfetch; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Gavin King + */ +public class ProductLine { + + private String id; + private String description; + private Set models = new HashSet(); + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public Set getModels() { + return models; + } + public void setModels(Set models) { + this.models = models; + } +} diff --git a/test/org/hibernate/test/bidi/Auction.hbm.xml b/test/org/hibernate/test/bidi/Auction.hbm.xml new file mode 100755 index 0000000000..7dbf882746 --- /dev/null +++ b/test/org/hibernate/test/bidi/Auction.hbm.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + id + 1 + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/bidi/Auction.java b/test/org/hibernate/test/bidi/Auction.java new file mode 100755 index 0000000000..fe11640f71 --- /dev/null +++ b/test/org/hibernate/test/bidi/Auction.java @@ -0,0 +1,48 @@ +//$Id$ +package org.hibernate.test.bidi; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author Gavin King + */ +public class Auction { + private Long id; + private String description; + private List bids = new ArrayList(); + private Bid successfulBid; + private Date end; + + public Date getEnd() { + return end; + } + public void setEnd(Date end) { + this.end = end; + } + public List getBids() { + return bids; + } + public void setBids(List bids) { + this.bids = bids; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Bid getSuccessfulBid() { + return successfulBid; + } + public void setSuccessfulBid(Bid successfulBid) { + this.successfulBid = successfulBid; + } +} diff --git a/test/org/hibernate/test/bidi/Auction2.hbm.xml b/test/org/hibernate/test/bidi/Auction2.hbm.xml new file mode 100755 index 0000000000..d45f3af548 --- /dev/null +++ b/test/org/hibernate/test/bidi/Auction2.hbm.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + exists(select a.id from TAuction2 a where a.successfulBid=id) + + + + diff --git a/test/org/hibernate/test/bidi/AuctionTest.java b/test/org/hibernate/test/bidi/AuctionTest.java new file mode 100755 index 0000000000..175940f7b9 --- /dev/null +++ b/test/org/hibernate/test/bidi/AuctionTest.java @@ -0,0 +1,119 @@ +//$Id$ +package org.hibernate.test.bidi; + +import java.math.BigDecimal; +import java.util.Date; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.dialect.PostgreSQLDialect; + +/** + * @author Gavin King + */ +public class AuctionTest extends FunctionalTestCase { + + public AuctionTest(String str) { + super( str ); + } + + public String[] getMappings() { + return new String[] { "bidi/Auction.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( AuctionTest.class ); + } + + public void testLazy() { + if ( getDialect() instanceof PostgreSQLDialect ) { + return; //doesn't like boolean=1 + } + + Session s = openSession(); + Transaction t = s.beginTransaction(); + Auction a = new Auction(); + a.setDescription( "an auction for something" ); + a.setEnd( new Date() ); + Bid b = new Bid(); + b.setAmount( new BigDecimal( 123.34 ).setScale( 19, BigDecimal.ROUND_DOWN ) ); + b.setSuccessful( true ); + b.setDatetime( new Date() ); + b.setItem( a ); + a.getBids().add( b ); + a.setSuccessfulBid( b ); + s.persist( b ); + t.commit(); + s.close(); + + Long aid = a.getId(); + Long bid = b.getId(); + + s = openSession(); + t = s.beginTransaction(); + b = ( Bid ) s.load( Bid.class, bid ); + assertFalse( Hibernate.isInitialized( b ) ); + a = ( Auction ) s.get( Auction.class, aid ); + assertFalse( Hibernate.isInitialized( a.getBids() ) ); + assertTrue( Hibernate.isInitialized( a.getSuccessfulBid() ) ); + assertSame( a.getBids().iterator().next(), b ); + assertSame( b, a.getSuccessfulBid() ); + assertTrue( Hibernate.isInitialized( b ) ); + assertTrue( b.isSuccessful() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + b = ( Bid ) s.load( Bid.class, bid ); + assertFalse( Hibernate.isInitialized( b ) ); + a = ( Auction ) s.createQuery( "from Auction a left join fetch a.bids" ).uniqueResult(); + assertTrue( Hibernate.isInitialized( b ) ); + assertTrue( Hibernate.isInitialized( a.getBids() ) ); + assertSame( b, a.getSuccessfulBid() ); + assertSame( a.getBids().iterator().next(), b ); + assertTrue( b.isSuccessful() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + b = ( Bid ) s.load( Bid.class, bid ); + a = ( Auction ) s.load( Auction.class, aid ); + assertFalse( Hibernate.isInitialized( b ) ); + assertFalse( Hibernate.isInitialized( a ) ); + s.createQuery( "from Auction a left join fetch a.successfulBid" ).list(); + assertTrue( Hibernate.isInitialized( b ) ); + assertTrue( Hibernate.isInitialized( a ) ); + assertSame( b, a.getSuccessfulBid() ); + assertFalse( Hibernate.isInitialized( a.getBids() ) ); + assertSame( a.getBids().iterator().next(), b ); + assertTrue( b.isSuccessful() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + b = ( Bid ) s.load( Bid.class, bid ); + a = ( Auction ) s.load( Auction.class, aid ); + assertFalse( Hibernate.isInitialized( b ) ); + assertFalse( Hibernate.isInitialized( a ) ); + assertSame( s.get( Bid.class, bid ), b ); + assertTrue( Hibernate.isInitialized( b ) ); + assertSame( s.get( Auction.class, aid ), a ); + assertTrue( Hibernate.isInitialized( a ) ); + assertSame( b, a.getSuccessfulBid() ); + assertFalse( Hibernate.isInitialized( a.getBids() ) ); + assertSame( a.getBids().iterator().next(), b ); + assertTrue( b.isSuccessful() ); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/bidi/AuctionTest2.java b/test/org/hibernate/test/bidi/AuctionTest2.java new file mode 100755 index 0000000000..0c70f6d82c --- /dev/null +++ b/test/org/hibernate/test/bidi/AuctionTest2.java @@ -0,0 +1,123 @@ +//$Id$ +package org.hibernate.test.bidi; + +import java.math.BigDecimal; +import java.util.Date; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.dialect.Oracle9Dialect; + +import junit.framework.Test; + +/** + * @author Gavin King + */ +public class AuctionTest2 extends FunctionalTestCase { + + public AuctionTest2(String str) { + super( str ); + } + + public String[] getMappings() { + return new String[] { "bidi/Auction2.hbm.xml" }; + } + + public boolean createSchema() { + return getDialect().supportsExistsInSelect(); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( AuctionTest2.class ); + } + + public void testLazy() { + if ( ! getDialect().supportsExistsInSelect() ) { + reportSkip( "dialect does not support exist fragments in the select clause", "bidi support" ); + return; + } + + Session s = openSession(); + Transaction t = s.beginTransaction(); + Auction a = new Auction(); + a.setDescription( "an auction for something" ); + a.setEnd( new Date() ); + Bid b = new Bid(); + b.setAmount( new BigDecimal( 123.34 ).setScale( 19, BigDecimal.ROUND_DOWN ) ); + b.setSuccessful( true ); + b.setDatetime( new Date() ); + b.setItem( a ); + a.getBids().add( b ); + a.setSuccessfulBid( b ); + s.persist( b ); + t.commit(); + s.close(); + + Long aid = a.getId(); + Long bid = b.getId(); + + s = openSession(); + t = s.beginTransaction(); + b = ( Bid ) s.load( Bid.class, bid ); + assertFalse( Hibernate.isInitialized( b ) ); + a = ( Auction ) s.get( Auction.class, aid ); + assertFalse( Hibernate.isInitialized( a.getBids() ) ); + assertFalse( Hibernate.isInitialized( a.getSuccessfulBid() ) ); + assertSame( a.getBids().iterator().next(), b ); + assertSame( b, a.getSuccessfulBid() ); + assertTrue( Hibernate.isInitialized( b ) ); + assertTrue( b.isSuccessful() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + b = ( Bid ) s.load( Bid.class, bid ); + assertFalse( Hibernate.isInitialized( b ) ); + a = ( Auction ) s.createQuery( "from Auction a left join fetch a.bids" ).uniqueResult(); + assertTrue( Hibernate.isInitialized( b ) ); + assertTrue( Hibernate.isInitialized( a.getBids() ) ); + assertSame( b, a.getSuccessfulBid() ); + assertSame( a.getBids().iterator().next(), b ); + assertTrue( b.isSuccessful() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + b = ( Bid ) s.load( Bid.class, bid ); + a = ( Auction ) s.load( Auction.class, aid ); + assertFalse( Hibernate.isInitialized( b ) ); + assertFalse( Hibernate.isInitialized( a ) ); + s.createQuery( "from Auction a left join fetch a.successfulBid" ).list(); + assertTrue( Hibernate.isInitialized( b ) ); + assertTrue( Hibernate.isInitialized( a ) ); + assertSame( b, a.getSuccessfulBid() ); + assertFalse( Hibernate.isInitialized( a.getBids() ) ); + assertSame( a.getBids().iterator().next(), b ); + assertTrue( b.isSuccessful() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + b = ( Bid ) s.load( Bid.class, bid ); + a = ( Auction ) s.load( Auction.class, aid ); + assertFalse( Hibernate.isInitialized( b ) ); + assertFalse( Hibernate.isInitialized( a ) ); + assertSame( s.get( Bid.class, bid ), b ); + assertTrue( Hibernate.isInitialized( b ) ); + assertSame( s.get( Auction.class, aid ), a ); + assertTrue( Hibernate.isInitialized( a ) ); + assertSame( b, a.getSuccessfulBid() ); + assertFalse( Hibernate.isInitialized( a.getBids() ) ); + assertSame( a.getBids().iterator().next(), b ); + assertTrue( b.isSuccessful() ); + t.commit(); + s.close(); + } + +} diff --git a/test/org/hibernate/test/bidi/Bid.java b/test/org/hibernate/test/bidi/Bid.java new file mode 100755 index 0000000000..556cef81b7 --- /dev/null +++ b/test/org/hibernate/test/bidi/Bid.java @@ -0,0 +1,47 @@ +//$Id$ +package org.hibernate.test.bidi; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author Gavin King + */ +public class Bid { + private Long id; + private Auction item; + private BigDecimal amount; + private boolean successful; + private Date datetime; + + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public BigDecimal getAmount() { + return amount; + } + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + public Auction getItem() { + return item; + } + public void setItem(Auction item) { + this.item = item; + } + public boolean isSuccessful() { + return successful; + } + public void setSuccessful(boolean successful) { + this.successful = successful; + } + public Date getDatetime() { + return datetime; + } + public void setDatetime(Date datetime) { + this.datetime = datetime; + } +} diff --git a/test/org/hibernate/test/bytecode/Bean.hbm.xml b/test/org/hibernate/test/bytecode/Bean.hbm.xml new file mode 100644 index 0000000000..dab2880662 --- /dev/null +++ b/test/org/hibernate/test/bytecode/Bean.hbm.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/bytecode/Bean.java b/test/org/hibernate/test/bytecode/Bean.java new file mode 100644 index 0000000000..c920440a01 --- /dev/null +++ b/test/org/hibernate/test/bytecode/Bean.java @@ -0,0 +1,78 @@ +package org.hibernate.test.bytecode; + +import java.util.Date; +import java.text.ParseException; + +/** + * @author Steve Ebersole + */ +public class Bean { + private String someString; + private Long someLong; + private Integer someInteger; + private Date someDate; + private long somelong; + private int someint; + private Object someObject; + + + public String getSomeString() { + return someString; + } + + public void setSomeString(String someString) { + this.someString = someString; + } + + public Long getSomeLong() { + return someLong; + } + + public void setSomeLong(Long someLong) { + this.someLong = someLong; + } + + public Integer getSomeInteger() { + return someInteger; + } + + public void setSomeInteger(Integer someInteger) { + this.someInteger = someInteger; + } + + public Date getSomeDate() { + return someDate; + } + + public void setSomeDate(Date someDate) { + this.someDate = someDate; + } + + public long getSomelong() { + return somelong; + } + + public void setSomelong(long somelong) { + this.somelong = somelong; + } + + public int getSomeint() { + return someint; + } + + public void setSomeint(int someint) { + this.someint = someint; + } + + public Object getSomeObject() { + return someObject; + } + + public void setSomeObject(Object someObject) { + this.someObject = someObject; + } + + public void throwException() throws ParseException { + throw new ParseException( "you asked for it...", 0 ); + } +} diff --git a/test/org/hibernate/test/bytecode/BeanReflectionHelper.java b/test/org/hibernate/test/bytecode/BeanReflectionHelper.java new file mode 100644 index 0000000000..743b7b642a --- /dev/null +++ b/test/org/hibernate/test/bytecode/BeanReflectionHelper.java @@ -0,0 +1,78 @@ +package org.hibernate.test.bytecode; + +import org.hibernate.property.BasicPropertyAccessor; +import org.hibernate.property.Getter; +import org.hibernate.property.Setter; + +import java.util.Date; + +/** + * @author Steve Ebersole + */ +public class BeanReflectionHelper { + + public static final Object[] TEST_VALUES = new Object[] { + "hello", new Long(1), new Integer(1), new Date(), new Long(1), new Integer(1), new Object() + }; + + private static final String[] getterNames = new String[7]; + private static final String[] setterNames = new String[7]; + private static final Class[] types = new Class[7]; + + static { + BasicPropertyAccessor propertyAccessor = new BasicPropertyAccessor(); + Getter getter = propertyAccessor.getGetter( Bean.class, "someString" ); + Setter setter = propertyAccessor.getSetter( Bean.class, "someString" ); + getterNames[0] = getter.getMethodName(); + types[0] = getter.getReturnType(); + setterNames[0] = setter.getMethodName(); + + getter = propertyAccessor.getGetter( Bean.class, "someLong" ); + setter = propertyAccessor.getSetter( Bean.class, "someLong" ); + getterNames[1] = getter.getMethodName(); + types[1] = getter.getReturnType(); + setterNames[1] = setter.getMethodName(); + + getter = propertyAccessor.getGetter( Bean.class, "someInteger" ); + setter = propertyAccessor.getSetter( Bean.class, "someInteger" ); + getterNames[2] = getter.getMethodName(); + types[2] = getter.getReturnType(); + setterNames[2] = setter.getMethodName(); + + getter = propertyAccessor.getGetter( Bean.class, "someDate" ); + setter = propertyAccessor.getSetter( Bean.class, "someDate" ); + getterNames[3] = getter.getMethodName(); + types[3] = getter.getReturnType(); + setterNames[3] = setter.getMethodName(); + + getter = propertyAccessor.getGetter( Bean.class, "somelong" ); + setter = propertyAccessor.getSetter( Bean.class, "somelong" ); + getterNames[4] = getter.getMethodName(); + types[4] = getter.getReturnType(); + setterNames[4] = setter.getMethodName(); + + getter = propertyAccessor.getGetter( Bean.class, "someint" ); + setter = propertyAccessor.getSetter( Bean.class, "someint" ); + getterNames[5] = getter.getMethodName(); + types[5] = getter.getReturnType(); + setterNames[5] = setter.getMethodName(); + + getter = propertyAccessor.getGetter( Bean.class, "someObject" ); + setter = propertyAccessor.getSetter( Bean.class, "someObject" ); + getterNames[6] = getter.getMethodName(); + types[6] = getter.getReturnType(); + setterNames[6] = setter.getMethodName(); + } + + public static String[] getGetterNames() { + return getterNames; + } + + public static String[] getSetterNames() { + return setterNames; + } + + public static Class[] getTypes() { + return types; + } +} diff --git a/test/org/hibernate/test/bytecode/BytecodeSuite.java b/test/org/hibernate/test/bytecode/BytecodeSuite.java new file mode 100644 index 0000000000..532acbb698 --- /dev/null +++ b/test/org/hibernate/test/bytecode/BytecodeSuite.java @@ -0,0 +1,21 @@ +package org.hibernate.test.bytecode; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * todo: describe BytecodeSuite + * + * @author Steve Ebersole + */ +public class BytecodeSuite { + public static Test suite() { + TestSuite suite = new TestSuite( "BytecodeProvider tests" ); + suite.addTest( org.hibernate.test.bytecode.cglib.ReflectionOptimizerTest.suite() ); + suite.addTest( org.hibernate.test.bytecode.cglib.InvocationTargetExceptionTest.suite() ); + suite.addTest( org.hibernate.test.bytecode.cglib.CGLIBThreadLocalTest.suite() ); + suite.addTest( org.hibernate.test.bytecode.javassist.ReflectionOptimizerTest.suite() ); + suite.addTest( org.hibernate.test.bytecode.javassist.InvocationTargetExceptionTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/bytecode/ProxyBean.java b/test/org/hibernate/test/bytecode/ProxyBean.java new file mode 100644 index 0000000000..cc4c08ac77 --- /dev/null +++ b/test/org/hibernate/test/bytecode/ProxyBean.java @@ -0,0 +1,31 @@ +package org.hibernate.test.bytecode; + +/** + * Created by IntelliJ IDEA. + * User: Paul + * Date: Mar 9, 2007 + * Time: 11:31:40 AM + * To change this template use File | Settings | File Templates. + */ +public class ProxyBean { + private String someString; + private long someLong; + + + public String getSomeString() { + return someString; + } + + public void setSomeString(String someString) { + this.someString = someString; + } + + + public long getSomeLong() { + return someLong; + } + + public void setSomeLong(long someLong) { + this.someLong = someLong; + } +} diff --git a/test/org/hibernate/test/bytecode/cglib/CGLIBThreadLocalTest.java b/test/org/hibernate/test/bytecode/cglib/CGLIBThreadLocalTest.java new file mode 100644 index 0000000000..6e1168c51d --- /dev/null +++ b/test/org/hibernate/test/bytecode/cglib/CGLIBThreadLocalTest.java @@ -0,0 +1,73 @@ +package org.hibernate.test.bytecode.cglib; + +import org.hibernate.junit.functional.*; +import org.hibernate.cfg.*; +import org.hibernate.*; +import org.hibernate.proxy.*; +import org.hibernate.test.bytecode.*; +import junit.framework.*; + +import java.text.*; +import java.lang.reflect.*; + +import net.sf.cglib.proxy.*; + +/** + * Test that the static thread local callback object is cleared out of the proxy class after instantiated. + * This tests that the memory leak reported by HHH-2481 hasn't been re-introduced. + * + * @author Paul Malolepsy + */ +public class CGLIBThreadLocalTest extends FunctionalTestCase { + public CGLIBThreadLocalTest(String name) { + super(name); + } + + public String[] getMappings() { + return new String[]{"bytecode/Bean.hbm.xml"}; + } + + public static TestSuite suite() { + return new FunctionalTestClassTestSuite(CGLIBThreadLocalTest.class); + } + + public void testCglibClearing() { + if (!(Environment.getBytecodeProvider() instanceof org.hibernate.bytecode.cglib.BytecodeProviderImpl)) { + // because of the scoping :( + reportSkip("env not configured for cglib provider", "cglib thread local callback clearing"); + return; + } + + //create the object for the test + Session s = openSession(); + s.beginTransaction(); + ProxyBean proxyBean = new ProxyBean(); + proxyBean.setSomeString("my-bean"); + proxyBean.setSomeLong(1234); + s.save(proxyBean); + s.getTransaction().commit(); + s.close(); + + // read the object as a proxy + s = openSession(); + s.beginTransaction(); + proxyBean = (ProxyBean) s.load(ProxyBean.class, proxyBean.getSomeString()); + assertTrue(proxyBean instanceof HibernateProxy); + try { + //check that the static thread callbacks thread local has been cleared out + Field field = proxyBean.getClass().getDeclaredField("CGLIB$THREAD_CALLBACKS"); + field.setAccessible(true); + ThreadLocal threadCallbacksThreadLocal = (ThreadLocal) field.get(null); + assertTrue(threadCallbacksThreadLocal.get() == null); + } catch (NoSuchFieldException e1) { + fail("unable to find CGLIB$THREAD_CALLBACKS field in proxy."); + } catch (Throwable t) { + fail("unexpected exception type : " + t); + } finally { + //clean up + s.delete(proxyBean); + s.getTransaction().commit(); + s.close(); + } + } +} diff --git a/test/org/hibernate/test/bytecode/cglib/InvocationTargetExceptionTest.java b/test/org/hibernate/test/bytecode/cglib/InvocationTargetExceptionTest.java new file mode 100644 index 0000000000..c2a0847641 --- /dev/null +++ b/test/org/hibernate/test/bytecode/cglib/InvocationTargetExceptionTest.java @@ -0,0 +1,67 @@ +package org.hibernate.test.bytecode.cglib; + +import org.hibernate.test.TestCase; +import org.hibernate.test.bytecode.Bean; +import org.hibernate.Session; +import org.hibernate.Hibernate; +import org.hibernate.dialect.Dialect; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.cfg.Environment; +import junit.framework.TestSuite; + +import java.text.ParseException; + +/** + * Test that the Javassist-based lazy initializer properly handles + * InvocationTargetExceptions + * + * @author Steve Ebersole + */ +public class InvocationTargetExceptionTest extends FunctionalTestCase { + public InvocationTargetExceptionTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "bytecode/Bean.hbm.xml" }; + } + + public static TestSuite suite() { + return new FunctionalTestClassTestSuite( InvocationTargetExceptionTest.class ); + } + + public void testProxiedInvocationException() { + if ( ! ( Environment.getBytecodeProvider() instanceof org.hibernate.bytecode.cglib.BytecodeProviderImpl ) ) { + // because of the scoping :( + reportSkip( "env not configured for cglib provider", "bytecode-provider InvocationTargetException handling" ); + return; + } + Session s = openSession(); + s.beginTransaction(); + Bean bean = new Bean(); + bean.setSomeString( "my-bean" ); + s.save( bean ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + bean = ( Bean ) s.load( Bean.class, bean.getSomeString() ); + assertFalse( Hibernate.isInitialized( bean ) ); + try { + bean.throwException(); + fail( "exception not thrown" ); + } + catch ( ParseException e ) { + // expected behavior + } + catch( Throwable t ) { + fail( "unexpected exception type : " + t ); + } + + s.delete( bean ); + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/bytecode/cglib/ReflectionOptimizerTest.java b/test/org/hibernate/test/bytecode/cglib/ReflectionOptimizerTest.java new file mode 100644 index 0000000000..39c9cb18d9 --- /dev/null +++ b/test/org/hibernate/test/bytecode/cglib/ReflectionOptimizerTest.java @@ -0,0 +1,52 @@ +package org.hibernate.test.bytecode.cglib; + +import junit.framework.TestSuite; + +import org.hibernate.bytecode.ReflectionOptimizer; +import org.hibernate.bytecode.cglib.BytecodeProviderImpl; +import org.hibernate.junit.UnitTestCase; +import org.hibernate.test.bytecode.Bean; +import org.hibernate.test.bytecode.BeanReflectionHelper; + +/** + * @author Steve Ebersole + */ +public class ReflectionOptimizerTest extends UnitTestCase { + + public ReflectionOptimizerTest(String string) { + super( string ); + } + + public void testReflectionOptimization() { + BytecodeProviderImpl provider = new BytecodeProviderImpl(); + ReflectionOptimizer optimizer = provider.getReflectionOptimizer( + Bean.class, + BeanReflectionHelper.getGetterNames(), + BeanReflectionHelper.getSetterNames(), + BeanReflectionHelper.getTypes() + ); + assertNotNull( optimizer ); + assertNotNull( optimizer.getInstantiationOptimizer() ); + assertNotNull( optimizer.getAccessOptimizer() ); + + Object instance = optimizer.getInstantiationOptimizer().newInstance(); + assertEquals( instance.getClass(), Bean.class ); + Bean bean = ( Bean ) instance; + + optimizer.getAccessOptimizer().setPropertyValues( bean, BeanReflectionHelper.TEST_VALUES ); + assertEquals( bean.getSomeString(), BeanReflectionHelper.TEST_VALUES[0] ); + Object[] values = optimizer.getAccessOptimizer().getPropertyValues( bean ); + assertEquivalent( values, BeanReflectionHelper.TEST_VALUES ); + } + + private void assertEquivalent(Object[] checkValues, Object[] values) { + assertEquals( "Different lengths", checkValues.length, values.length ); + for ( int i = 0; i < checkValues.length; i++ ) { + assertEquals( "different values at index [" + i + "]", checkValues[i], values[i] ); + } + } + + public static TestSuite suite() { + return new TestSuite( ReflectionOptimizerTest.class ); + } +} diff --git a/test/org/hibernate/test/bytecode/javassist/InvocationTargetExceptionTest.java b/test/org/hibernate/test/bytecode/javassist/InvocationTargetExceptionTest.java new file mode 100644 index 0000000000..eb87342ac9 --- /dev/null +++ b/test/org/hibernate/test/bytecode/javassist/InvocationTargetExceptionTest.java @@ -0,0 +1,68 @@ +package org.hibernate.test.bytecode.javassist; + +import java.text.ParseException; + +import junit.framework.TestSuite; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.bytecode.Bean; + +/** + * Test that the Javassist-based lazy initializer properly handles + * InvocationTargetExceptions + * + * @author Steve Ebersole + */ +public class InvocationTargetExceptionTest extends FunctionalTestCase { + public InvocationTargetExceptionTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "bytecode/Bean.hbm.xml" }; + } + + public static TestSuite suite() { + return new FunctionalTestClassTestSuite( InvocationTargetExceptionTest.class ); + } + + public void testProxiedInvocationException() { + if ( !( Environment.getBytecodeProvider() instanceof org.hibernate.bytecode.javassist.BytecodeProviderImpl ) ) { + // because of the scoping :( + reportSkip( + "env not configured for javassist provider", "bytecode-provider InvocationTargetException handling" + ); + return; + } + Session s = openSession(); + s.beginTransaction(); + Bean bean = new Bean(); + bean.setSomeString( "my-bean" ); + s.save( bean ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + bean = ( Bean ) s.load( Bean.class, bean.getSomeString() ); + assertFalse( Hibernate.isInitialized( bean ) ); + try { + bean.throwException(); + fail( "exception not thrown" ); + } + catch ( ParseException e ) { + // expected behavior + } + catch ( Throwable t ) { + fail( "unexpected exception type : " + t ); + } + + s.delete( bean ); + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/bytecode/javassist/ReflectionOptimizerTest.java b/test/org/hibernate/test/bytecode/javassist/ReflectionOptimizerTest.java new file mode 100644 index 0000000000..0b106dfc6d --- /dev/null +++ b/test/org/hibernate/test/bytecode/javassist/ReflectionOptimizerTest.java @@ -0,0 +1,52 @@ +package org.hibernate.test.bytecode.javassist; + +import junit.framework.TestSuite; + +import org.hibernate.bytecode.ReflectionOptimizer; +import org.hibernate.bytecode.javassist.BytecodeProviderImpl; +import org.hibernate.junit.UnitTestCase; +import org.hibernate.test.bytecode.Bean; +import org.hibernate.test.bytecode.BeanReflectionHelper; + +/** + * @author Steve Ebersole + */ +public class ReflectionOptimizerTest extends UnitTestCase { + + public ReflectionOptimizerTest(String string) { + super( string ); + } + + public void testReflectionOptimization() { + BytecodeProviderImpl provider = new BytecodeProviderImpl(); + ReflectionOptimizer optimizer = provider.getReflectionOptimizer( + Bean.class, + BeanReflectionHelper.getGetterNames(), + BeanReflectionHelper.getSetterNames(), + BeanReflectionHelper.getTypes() + ); + assertNotNull( optimizer ); + assertNotNull( optimizer.getInstantiationOptimizer() ); + assertNotNull( optimizer.getAccessOptimizer() ); + + Object instance = optimizer.getInstantiationOptimizer().newInstance(); + assertEquals( instance.getClass(), Bean.class ); + Bean bean = ( Bean ) instance; + + optimizer.getAccessOptimizer().setPropertyValues( bean, BeanReflectionHelper.TEST_VALUES ); + assertEquals( bean.getSomeString(), BeanReflectionHelper.TEST_VALUES[0] ); + Object[] values = optimizer.getAccessOptimizer().getPropertyValues( bean ); + assertEquivalent( values, BeanReflectionHelper.TEST_VALUES ); + } + + private void assertEquivalent(Object[] checkValues, Object[] values) { + assertEquals( "Different lengths", checkValues.length, values.length ); + for ( int i = 0; i < checkValues.length; i++ ) { + assertEquals( "different values at index [" + i + "]", checkValues[i], values[i] ); + } + } + + public static TestSuite suite() { + return new TestSuite( ReflectionOptimizerTest.class ); + } +} diff --git a/test/org/hibernate/test/cache/BaseCacheProviderTestCase.java b/test/org/hibernate/test/cache/BaseCacheProviderTestCase.java new file mode 100644 index 0000000000..b4bb3c2c42 --- /dev/null +++ b/test/org/hibernate/test/cache/BaseCacheProviderTestCase.java @@ -0,0 +1,217 @@ +package org.hibernate.test.cache; + +import java.util.HashMap; +import java.util.Map; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cache.ReadWriteCache; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.stat.SecondLevelCacheStatistics; +import org.hibernate.stat.Statistics; +import org.hibernate.test.tm.DummyConnectionProvider; +import org.hibernate.test.tm.DummyTransactionManagerLookup; +import org.hibernate.transaction.JDBCTransactionFactory; + +/** + * Common requirement testing for each {@link org.hibernate.cache.CacheProvider} impl. + * + * @author Steve Ebersole + */ +public abstract class BaseCacheProviderTestCase extends FunctionalTestCase { + + // note that a lot of the fucntionality here is intended to be used + // in creating specific tests for each CacheProvider that would extend + // from a base test case (this) for common requirement testing... + + public BaseCacheProviderTestCase(String x) { + super( x ); + } + + public String[] getMappings() { + return new String[] { "cache/Item.hbm.xml" }; + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.CACHE_REGION_PREFIX, "" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + cfg.setProperty( Environment.USE_STRUCTURED_CACHE, "true" ); + cfg.setProperty( Environment.CACHE_PROVIDER, getCacheProvider().getName() ); + + if ( getConfigResourceKey() != null ) { + cfg.setProperty( getConfigResourceKey(), getConfigResourceLocation() ); + } + + if ( useTransactionManager() ) { + cfg.setProperty( Environment.CONNECTION_PROVIDER, DummyConnectionProvider.class.getName() ); + cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, DummyTransactionManagerLookup.class.getName() ); + } + else { + cfg.setProperty( Environment.TRANSACTION_STRATEGY, JDBCTransactionFactory.class.getName() ); + } + } + + /** + * The cache provider to be tested. + * + * @return The cache provider. + */ + protected abstract Class getCacheProvider(); + + /** + * For provider-specific configuration, the name of the property key the + * provider expects. + * + * @return The provider-specific config key. + */ + protected abstract String getConfigResourceKey(); + + /** + * For provider-specific configuration, the resource location of that + * config resource. + * + * @return The config resource location. + */ + protected abstract String getConfigResourceLocation(); + + /** + * Should we use a transaction manager for transaction management. + * + * @return True if we should use a RM; false otherwise. + */ + protected abstract boolean useTransactionManager(); + + + public void testQueryCacheInvalidation() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Item i = new Item(); + i.setName("widget"); + i.setDescription("A really top-quality, full-featured widget."); + s.persist(i); + t.commit(); + s.close(); + + SecondLevelCacheStatistics slcs = s.getSessionFactory().getStatistics() + .getSecondLevelCacheStatistics( Item.class.getName() ); + + assertEquals( slcs.getPutCount(), 1 ); + assertEquals( slcs.getElementCountInMemory(), 1 ); + assertEquals( slcs.getEntries().size(), 1 ); + + s = openSession(); + t = s.beginTransaction(); + i = (Item) s.get( Item.class, i.getId() ); + + assertEquals( slcs.getHitCount(), 1 ); + assertEquals( slcs.getMissCount(), 0 ); + + i.setDescription("A bog standard item"); + + t.commit(); + s.close(); + + assertEquals( slcs.getPutCount(), 2 ); + + Object entry = slcs.getEntries().get( i.getId() ); + Map map; + if ( entry instanceof ReadWriteCache.Item ) { + map = new HashMap(); + map = (Map) ( (ReadWriteCache.Item) entry ).getValue(); + } + else { + map = (Map) entry; + } + assertTrue( map.get("description").equals("A bog standard item") ); + assertTrue( map.get("name").equals("widget") ); + + // cleanup + s = openSession(); + t = s.beginTransaction(); + s.delete( i ); + t.commit(); + s.close(); + } + + public void testEmptySecondLevelCacheEntry() throws Exception { + getSessions().evictEntity( Item.class.getName() ); + Statistics stats = getSessions().getStatistics(); + stats.clear(); + SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics( Item.class.getName() ); + Map cacheEntries = statistics.getEntries(); + assertEquals( 0, cacheEntries.size() ); + } + + public void testStaleWritesLeaveCacheConsistent() { + Session s = openSession(); + Transaction txn = s.beginTransaction(); + VersionedItem item = new VersionedItem(); + item.setName( "steve" ); + item.setDescription( "steve's item" ); + s.save( item ); + txn.commit(); + s.close(); + + Long initialVersion = item.getVersion(); + + // manually revert the version property + item.setVersion( new Long( item.getVersion().longValue() - 1 ) ); + + try { + s = openSession(); + txn = s.beginTransaction(); + s.update( item ); + txn.commit(); + s.close(); + fail( "expected stale write to fail" ); + } + catch( Throwable expected ) { + // expected behavior here + if ( txn != null ) { + try { + txn.rollback(); + } + catch( Throwable ignore ) { + } + } + } + finally { + if ( s != null && s.isOpen() ) { + try { + s.close(); + } + catch( Throwable ignore ) { + } + } + } + + // check the version value in the cache... + SecondLevelCacheStatistics slcs = sfi().getStatistics() + .getSecondLevelCacheStatistics( VersionedItem.class.getName() ); + + Object entry = slcs.getEntries().get( item.getId() ); + Long cachedVersionValue; + if ( entry instanceof ReadWriteCache.Lock ) { + //FIXME don't know what to test here + cachedVersionValue = new Long( ( (ReadWriteCache.Lock) entry).getUnlockTimestamp() ); + } + else { + cachedVersionValue = ( Long ) ( (Map) entry ).get( "_version" ); + assertEquals( initialVersion.longValue(), cachedVersionValue.longValue() ); + } + + + // cleanup + s = openSession(); + txn = s.beginTransaction(); + item = ( VersionedItem ) s.load( VersionedItem.class, item.getId() ); + s.delete( item ); + txn.commit(); + s.close(); + + } +} diff --git a/test/org/hibernate/test/cache/CacheSuite.java b/test/org/hibernate/test/cache/CacheSuite.java new file mode 100644 index 0000000000..9bfe63a4ce --- /dev/null +++ b/test/org/hibernate/test/cache/CacheSuite.java @@ -0,0 +1,21 @@ +package org.hibernate.test.cache; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.hibernate.test.cache.treecache.optimistic.OptimisticTreeCacheTest; +import org.hibernate.test.cache.treecache.pessimistic.TreeCacheTest; +import org.hibernate.test.cache.ehcache.EhCacheTest; + +/** + * @author Steve Ebersole + */ +public class CacheSuite { + + public static Test suite() { + TestSuite suite = new TestSuite( "CacheProvider tests"); + suite.addTest( OptimisticTreeCacheTest.suite() ); + suite.addTest( TreeCacheTest.suite() ); + suite.addTest( EhCacheTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/cache/Item.hbm.xml b/test/org/hibernate/test/cache/Item.hbm.xml new file mode 100755 index 0000000000..ca4ce5ef35 --- /dev/null +++ b/test/org/hibernate/test/cache/Item.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/cache/Item.java b/test/org/hibernate/test/cache/Item.java new file mode 100755 index 0000000000..68d35bc1a3 --- /dev/null +++ b/test/org/hibernate/test/cache/Item.java @@ -0,0 +1,31 @@ +//$Id$ +package org.hibernate.test.cache; + + +/** + * @author Gavin King + */ +public class Item { + private Long id; + private String name; + private String description; + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/cache/VersionedItem.java b/test/org/hibernate/test/cache/VersionedItem.java new file mode 100644 index 0000000000..94a476cec3 --- /dev/null +++ b/test/org/hibernate/test/cache/VersionedItem.java @@ -0,0 +1,16 @@ +package org.hibernate.test.cache; + +/** + * @author Steve Ebersole + */ +public class VersionedItem extends Item { + private Long version; + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/test/org/hibernate/test/cache/ehcache/EhCacheTest.java b/test/org/hibernate/test/cache/ehcache/EhCacheTest.java new file mode 100644 index 0000000000..477297cf37 --- /dev/null +++ b/test/org/hibernate/test/cache/ehcache/EhCacheTest.java @@ -0,0 +1,48 @@ +//$Id: $ +package org.hibernate.test.cache.ehcache; + +import junit.framework.Test; + +import org.hibernate.cache.EhCacheProvider; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.cache.BaseCacheProviderTestCase; + +/** + * @author Emmanuel Bernard + */ +public class EhCacheTest extends BaseCacheProviderTestCase { + + // note that a lot of the fucntionality here is intended to be used + // in creating specific tests for each CacheProvider that would extend + // from a base test case (this) for common requirement testing... + + public EhCacheTest(String x) { + super( x ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( EhCacheTest.class ); + } + + public String getCacheConcurrencyStrategy() { + return "read-write"; + } + + protected Class getCacheProvider() { + return EhCacheProvider.class; + } + + protected String getConfigResourceKey() { + return Environment.CACHE_PROVIDER_CONFIG; + } + + protected String getConfigResourceLocation() { + return "org/hibernate/test/cache/ehcache/ehcache.xml"; + } + + protected boolean useTransactionManager() { + return false; + } + +} diff --git a/test/org/hibernate/test/cache/ehcache/ehcache.xml b/test/org/hibernate/test/cache/ehcache/ehcache.xml new file mode 100644 index 0000000000..a4ce298050 --- /dev/null +++ b/test/org/hibernate/test/cache/ehcache/ehcache.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + --> + + + + diff --git a/test/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java b/test/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java new file mode 100644 index 0000000000..62bf9aa707 --- /dev/null +++ b/test/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java @@ -0,0 +1,112 @@ +package org.hibernate.test.cache.treecache.optimistic; + +import junit.framework.Test; +import org.jboss.cache.Fqn; +import org.jboss.cache.TreeCache; +import org.jboss.cache.config.Option; +import org.jboss.cache.optimistic.DataVersion; + +import org.hibernate.cache.OptimisticTreeCacheProvider; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.cache.BaseCacheProviderTestCase; +import org.hibernate.test.tm.DummyTransactionManager; + +/** + * @author Steve Ebersole + */ +public class OptimisticTreeCacheTest extends BaseCacheProviderTestCase { + + // note that a lot of the fucntionality here is intended to be used + // in creating specific tests for each CacheProvider that would extend + // from a base test case (this) for common requirement testing... + + public OptimisticTreeCacheTest(String x) { + super( x ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( OptimisticTreeCacheTest.class ); + } + + public String getCacheConcurrencyStrategy() { + return "transactional"; + } + + protected Class getCacheProvider() { + return OptimisticTreeCacheProvider.class; + } + + protected String getConfigResourceKey() { + return Environment.CACHE_PROVIDER_CONFIG; + } + + protected String getConfigResourceLocation() { + return "org/hibernate/test/cache/treecache/optimistic/treecache.xml"; + } + + protected boolean useTransactionManager() { + return true; + } + + public void testCacheLevelStaleWritesFail() throws Throwable { + Fqn fqn = new Fqn( "whatever" ); + TreeCache treeCache = ( ( OptimisticTreeCacheProvider ) sfi().getSettings().getCacheProvider() ).getUnderlyingCache(); + + Long long1 = new Long(1); + Long long2 = new Long(2); + + try { + System.out.println( "****************************************************************" ); + DummyTransactionManager.INSTANCE.begin(); + treeCache.put( fqn, "ITEM", long1, ManualDataVersion.gen( 1 ) ); + DummyTransactionManager.INSTANCE.commit(); + + System.out.println( "****************************************************************" ); + DummyTransactionManager.INSTANCE.begin(); + treeCache.put( fqn, "ITEM", long2, ManualDataVersion.gen( 2 ) ); + DummyTransactionManager.INSTANCE.commit(); + + try { + System.out.println( "****************************************************************" ); + DummyTransactionManager.INSTANCE.begin(); + treeCache.put( fqn, "ITEM", long1, ManualDataVersion.gen( 1 ) ); + DummyTransactionManager.INSTANCE.commit(); + fail( "stale write allowed" ); + } + catch( Throwable ignore ) { + // expected behavior + DummyTransactionManager.INSTANCE.rollback(); + } + + Long current = ( Long ) treeCache.get( fqn, "ITEM" ); + assertEquals( "unexpected current value", 2, current.longValue() ); + } + finally { + try { + treeCache.remove( fqn, "ITEM" ); + } + catch( Throwable ignore ) { + } + } + } + + private static class ManualDataVersion implements DataVersion { + private final int version; + + public ManualDataVersion(int version) { + this.version = version; + } + + public boolean newerThan(DataVersion dataVersion) { + return this.version > ( ( ManualDataVersion ) dataVersion ).version; + } + + public static Option gen(int version) { + ManualDataVersion mdv = new ManualDataVersion( version ); + Option option = new Option(); + option.setDataVersion( mdv ); + return option; + } + } +} diff --git a/test/org/hibernate/test/cache/treecache/optimistic/treecache.xml b/test/org/hibernate/test/cache/treecache/optimistic/treecache.xml new file mode 100644 index 0000000000..cbc82f35e6 --- /dev/null +++ b/test/org/hibernate/test/cache/treecache/optimistic/treecache.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + jboss:service=Naming + jboss:service=TransactionManager + + + org.jboss.cache.GenericTransactionManagerLookup + + + + OPTIMISTIC + + + REPEATABLE_READ + + + LOCAL + + + false + + + 0 + + + 0 + + + TreeCache-Cluster + + + + + + + + + + + + + + + + + + + + + + + + false + + + 20000 + + + 15000 + + + + + + + false + + + diff --git a/test/org/hibernate/test/cache/treecache/pessimistic/TreeCacheTest.java b/test/org/hibernate/test/cache/treecache/pessimistic/TreeCacheTest.java new file mode 100644 index 0000000000..3bb75f0314 --- /dev/null +++ b/test/org/hibernate/test/cache/treecache/pessimistic/TreeCacheTest.java @@ -0,0 +1,47 @@ +package org.hibernate.test.cache.treecache.pessimistic; + +import junit.framework.Test; + +import org.hibernate.cache.TreeCacheProvider; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.cache.BaseCacheProviderTestCase; + +/** + * @author Steve Ebersole + */ +public class TreeCacheTest extends BaseCacheProviderTestCase { + + // note that a lot of the fucntionality here is intended to be used + // in creating specific tests for each CacheProvider that would extend + // from a base test case (this) for common requirement testing... + + public TreeCacheTest(String x) { + super( x ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( TreeCacheTest.class ); + } + + public String getCacheConcurrencyStrategy() { + return "transactional"; + } + + protected Class getCacheProvider() { + return TreeCacheProvider.class; + } + + protected String getConfigResourceKey() { + return Environment.CACHE_PROVIDER_CONFIG; + } + + protected String getConfigResourceLocation() { + return "org/hibernate/test/cache/treecache/pessimistic/treecache.xml"; + } + + protected boolean useTransactionManager() { + return true; + } + +} diff --git a/test/org/hibernate/test/cache/treecache/pessimistic/treecache.xml b/test/org/hibernate/test/cache/treecache/pessimistic/treecache.xml new file mode 100644 index 0000000000..e469c12204 --- /dev/null +++ b/test/org/hibernate/test/cache/treecache/pessimistic/treecache.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + jboss:service=Naming + jboss:service=TransactionManager + + + + + + REPEATABLE_READ + + + LOCAL + + + TreeCache-Cluster + + + + + + + + + + + + + + + + + + + + + + + 20000 + + + 20000 + + + 10000 + + + 15000 + + + 60000 + + + + + + + diff --git a/test/org/hibernate/test/cascade/Job.hbm.xml b/test/org/hibernate/test/cascade/Job.hbm.xml new file mode 100644 index 0000000000..2828c4e6a7 --- /dev/null +++ b/test/org/hibernate/test/cascade/Job.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/cascade/Job.java b/test/org/hibernate/test/cascade/Job.java new file mode 100644 index 0000000000..873e993ca2 --- /dev/null +++ b/test/org/hibernate/test/cascade/Job.java @@ -0,0 +1,53 @@ +// $Id$ +package org.hibernate.test.cascade; + +/** + * Implementation of Job. + * + * @author Steve Ebersole + */ +public class Job { + private Long id; + private JobBatch batch; + private String processingInstructions; + private int status; + + /** GCLIB constructor */ + Job() {} + + protected Job(JobBatch batch) { + this.batch = batch; + } + + public Long getId() { + return id; + } + + /*package*/ void setId(Long id) { + this.id = id; + } + + public JobBatch getBatch() { + return batch; + } + + /*package*/ void setBatch(JobBatch batch) { + this.batch = batch; + } + + public String getProcessingInstructions() { + return processingInstructions; + } + + public void setProcessingInstructions(String processingInstructions) { + this.processingInstructions = processingInstructions; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } +} diff --git a/test/org/hibernate/test/cascade/JobBatch.hbm.xml b/test/org/hibernate/test/cascade/JobBatch.hbm.xml new file mode 100644 index 0000000000..99de62f703 --- /dev/null +++ b/test/org/hibernate/test/cascade/JobBatch.hbm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/cascade/JobBatch.java b/test/org/hibernate/test/cascade/JobBatch.java new file mode 100644 index 0000000000..662b53a0e8 --- /dev/null +++ b/test/org/hibernate/test/cascade/JobBatch.java @@ -0,0 +1,54 @@ +// $Id$ +package org.hibernate.test.cascade; + +import java.util.Date; +import java.util.Set; +import java.util.HashSet; + +/** + * Implementation of JobBatch. + * + * @author Steve Ebersole + */ +public class JobBatch { + private Long id; + private Date batchDate; + private Set jobs = new HashSet(); + + /** CGLIB constructor */ + JobBatch() {} + + public JobBatch(Date batchDate) { + this.batchDate = batchDate; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getBatchDate() { + return batchDate; + } + + public void setBatchDate(Date batchDate) { + this.batchDate = batchDate; + } + + public Set getJobs() { + return jobs; + } + + public void setJobs(Set jobs) { + this.jobs = jobs; + } + + public Job createJob() { + Job job = new Job( this ); + jobs.add( job ); + return job; + } +} diff --git a/test/org/hibernate/test/cascade/RefreshTest.java b/test/org/hibernate/test/cascade/RefreshTest.java new file mode 100644 index 0000000000..d846288dcc --- /dev/null +++ b/test/org/hibernate/test/cascade/RefreshTest.java @@ -0,0 +1,79 @@ +// $Id$ +package org.hibernate.test.cascade; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.util.Date; +import java.util.Iterator; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Implementation of RefreshTest. + * + * @author Steve Ebersole + */ +public class RefreshTest extends FunctionalTestCase { + + public RefreshTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "cascade/Job.hbm.xml", "cascade/JobBatch.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( RefreshTest.class ); + } + + public void testRefreshCascade() throws Throwable { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + + JobBatch batch = new JobBatch( new Date() ); + batch.createJob().setProcessingInstructions( "Just do it!" ); + batch.createJob().setProcessingInstructions( "I know you can do it!" ); + + // write the stuff to the database; at this stage all job.status values are zero + session.persist( batch ); + session.flush(); + + // behind the session's back, let's modify the statuses + updateStatuses( session.connection() ); + + // Now lets refresh the persistent batch, and see if the refresh cascaded to the jobs collection elements + session.refresh( batch ); + + Iterator itr = batch.getJobs().iterator(); + while( itr.hasNext() ) { + Job job = ( Job ) itr.next(); + assertEquals( "Jobs not refreshed!", 1, job.getStatus() ); + } + + txn.rollback(); + session.close(); + } + + private void updateStatuses(Connection connection) throws Throwable { + PreparedStatement stmnt = null; + try { + stmnt = connection.prepareStatement( "UPDATE T_JOB SET JOB_STATUS = 1" ); + stmnt.executeUpdate(); + } + finally { + if ( stmnt != null ) { + try { + stmnt.close(); + } + catch( Throwable ignore ) { + } + } + } + } +} diff --git a/test/org/hibernate/test/cfg/Cacheable.hbm.xml b/test/org/hibernate/test/cfg/Cacheable.hbm.xml new file mode 100644 index 0000000000..556b793c29 --- /dev/null +++ b/test/org/hibernate/test/cfg/Cacheable.hbm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/cfg/CacheableFileTest.java b/test/org/hibernate/test/cfg/CacheableFileTest.java new file mode 100644 index 0000000000..7db7e21974 --- /dev/null +++ b/test/org/hibernate/test/cfg/CacheableFileTest.java @@ -0,0 +1,44 @@ +package org.hibernate.test.cfg; + +import java.io.File; + +import org.hibernate.cfg.Configuration; +import org.hibernate.junit.UnitTestCase; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class CacheableFileTest extends UnitTestCase { + + public static final String MAPPING = "org/hibernate/test/cfg/Cacheable.hbm.xml"; + + private File mappingFile; + + public CacheableFileTest(String string) { + super( string ); + } + + protected void setUp() throws Exception { + super.setUp(); + mappingFile = new File( getClass().getClassLoader().getResource( MAPPING ).getFile() ); + assertTrue( mappingFile.exists() ); + File cached = new File( mappingFile.getParentFile(), mappingFile.getName() + ".bin" ); + if ( cached.exists() ) { + cached.delete(); + } + } + + protected void tearDown() throws Exception { + mappingFile = null; + super.tearDown(); + } + + public void testCachedFiles() { + Configuration cfg = new Configuration(); + cfg.addCacheableFile( mappingFile ); + Configuration cfg2 = new Configuration(); + cfg2.addCacheableFile( mappingFile ); + } +} diff --git a/test/org/hibernate/test/cid/CompositeIdTest.java b/test/org/hibernate/test/cid/CompositeIdTest.java new file mode 100755 index 0000000000..df0bbe3752 --- /dev/null +++ b/test/org/hibernate/test/cid/CompositeIdTest.java @@ -0,0 +1,269 @@ +//$Id$ +package org.hibernate.test.cid; + +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class CompositeIdTest extends FunctionalTestCase { + + public CompositeIdTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "cid/Customer.hbm.xml", "cid/Order.hbm.xml", "cid/LineItem.hbm.xml", "cid/Product.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite(CompositeIdTest.class); + } + + public void testQuery() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createQuery("from LineItem ol where ol.order.id.customerId = 'C111'").list(); + t.commit(); + s.close(); + } + + public void testCompositeIds() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Product p = new Product(); + p.setProductId("A123"); + p.setDescription("nipple ring"); + p.setPrice( new BigDecimal(1.0) ); + p.setNumberAvailable(1004); + s.persist(p); + + Product p2 = new Product(); + p2.setProductId("X525"); + p2.setDescription("nose stud"); + p2.setPrice( new BigDecimal(3.0) ); + p2.setNumberAvailable(105); + s.persist(p2); + + Customer c = new Customer(); + c.setAddress("St Kilda Rd, MEL, 3000"); + c.setName("Virginia"); + c.setCustomerId("C111"); + s.persist(c); + + Order o = new Order(c); + o.setOrderDate( Calendar.getInstance() ); + LineItem li = new LineItem(o, p); + li.setQuantity(2); + + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + o = (Order) s.get( Order.class, new Order.Id("C111", 0) ); + assertEquals( o.getTotal().intValue(), 2 ); + o.getCustomer().getName(); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery("from Customer c left join fetch c.orders o left join fetch o.lineItems li left join fetch li.product p").list(); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery("from Order o left join fetch o.lineItems li left join fetch li.product p").list(); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Iterator iter = s.createQuery("select o.id, li.id from Order o join o.lineItems li").list().iterator(); + while ( iter.hasNext() ) { + Object[] stuff = (Object[]) iter.next(); + assertTrue(stuff.length==2); + } + iter = s.createQuery("from Order o join o.lineItems li").iterate(); + while ( iter.hasNext() ) { + Object[] stuff = (Object[]) iter.next(); + assertTrue(stuff.length==2); + } + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Customer) s.get( Customer.class, "C111" ); + Order o2 = new Order(c); + o2.setOrderDate( Calendar.getInstance() ); + s.flush(); + LineItem li2 = new LineItem(o2, p2); + li2.setQuantity(5); + List bigOrders = s.createQuery("from Order o where o.total>10.0").list(); + assertEquals( bigOrders.size(), 1 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from LineItem").executeUpdate(); + s.createQuery("delete from Order").executeUpdate(); + s.createQuery("delete from Customer").executeUpdate(); + s.createQuery("delete from Product").executeUpdate(); + t.commit(); + s.close(); + } + + + public void testNonLazyFetch() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Product p = new Product(); + p.setProductId("A123"); + p.setDescription("nipple ring"); + p.setPrice( new BigDecimal(1.0) ); + p.setNumberAvailable(1004); + s.persist(p); + + Product p2 = new Product(); + p2.setProductId("X525"); + p2.setDescription("nose stud"); + p2.setPrice( new BigDecimal(3.0) ); + p2.setNumberAvailable(105); + s.persist(p2); + + Customer c = new Customer(); + c.setAddress("St Kilda Rd, MEL, 3000"); + c.setName("Virginia"); + c.setCustomerId("C111"); + s.persist(c); + + Order o = new Order(c); + o.setOrderDate( Calendar.getInstance() ); + LineItem li = new LineItem(o, p); + li.setQuantity(2); + + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + o = (Order) s.get( Order.class, new Order.Id("C111", 0) ); + assertEquals( o.getTotal().intValue(), 2 ); + o.getCustomer().getName(); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + o = (Order) s.createQuery("from Order o left join fetch o.lineItems li left join fetch li.product p").uniqueResult(); + assertTrue( Hibernate.isInitialized( o.getLineItems() ) ); + li = (LineItem) o.getLineItems().iterator().next(); + assertTrue( Hibernate.isInitialized( li ) ); + assertTrue( Hibernate.isInitialized( li.getProduct() ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + o = (Order) s.createQuery("from Order o").uniqueResult(); + assertTrue( Hibernate.isInitialized( o.getLineItems() ) ); + li = (LineItem) o.getLineItems().iterator().next(); + assertTrue( Hibernate.isInitialized( li ) ); + assertFalse( Hibernate.isInitialized( li.getProduct() ) ); + t.commit(); + s.close(); + + + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from LineItem").executeUpdate(); + s.createQuery("delete from Order").executeUpdate(); + s.createQuery("delete from Customer").executeUpdate(); + s.createQuery("delete from Product").executeUpdate(); + t.commit(); + s.close(); + + } + + public void testMultipleCollectionFetch() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Product p = new Product(); + p.setProductId("A123"); + p.setDescription("nipple ring"); + p.setPrice( new BigDecimal(1.0) ); + p.setNumberAvailable(1004); + s.persist(p); + + Product p2 = new Product(); + p2.setProductId("X525"); + p2.setDescription("nose stud"); + p2.setPrice( new BigDecimal(3.0) ); + p2.setNumberAvailable(105); + s.persist(p2); + + Customer c = new Customer(); + c.setAddress("St Kilda Rd, MEL, 3000"); + c.setName("Virginia"); + c.setCustomerId("C111"); + s.persist(c); + + Order o = new Order(c); + o.setOrderDate( Calendar.getInstance() ); + LineItem li = new LineItem(o, p); + li.setQuantity(2); + LineItem li2 = new LineItem(o, p2); + li2.setQuantity(3); + + Order o2 = new Order(c); + o2.setOrderDate( Calendar.getInstance() ); + LineItem li3 = new LineItem(o2, p); + li3.setQuantity(1); + LineItem li4 = new LineItem(o2, p2); + li4.setQuantity(1); + + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Customer) s.createQuery("from Customer c left join fetch c.orders o left join fetch o.lineItems li left join fetch li.product p").uniqueResult(); + assertTrue( Hibernate.isInitialized( c.getOrders() ) ); + assertEquals( c.getOrders().size(), 2 ); + assertTrue( Hibernate.isInitialized( ( (Order) c.getOrders().get(0) ).getLineItems() ) ); + assertTrue( Hibernate.isInitialized( ( (Order) c.getOrders().get(1) ).getLineItems() ) ); + assertEquals( ( (Order) c.getOrders().get(0) ).getLineItems().size(), 2 ); + assertEquals( ( (Order) c.getOrders().get(1) ).getLineItems().size(), 2 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery("delete from LineItem").executeUpdate(); + s.createQuery("delete from Order").executeUpdate(); + s.createQuery("delete from Customer").executeUpdate(); + s.createQuery("delete from Product").executeUpdate(); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/cid/Customer.hbm.xml b/test/org/hibernate/test/cid/Customer.hbm.xml new file mode 100755 index 0000000000..c785964716 --- /dev/null +++ b/test/org/hibernate/test/cid/Customer.hbm.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/cid/Customer.java b/test/org/hibernate/test/cid/Customer.java new file mode 100755 index 0000000000..16bb65c6e8 --- /dev/null +++ b/test/org/hibernate/test/cid/Customer.java @@ -0,0 +1,73 @@ +//$Id$ +package org.hibernate.test.cid; + +import java.util.ArrayList; +import java.util.List; +import java.util.GregorianCalendar; +import java.math.BigDecimal; + +/** + * @author Gavin King + */ +public class Customer { + private String customerId; + private String name; + private String address; + private List orders = new ArrayList(); + /** + * @return Returns the address. + */ + public String getAddress() { + return address; + } + /** + * @param address The address to set. + */ + public void setAddress(String address) { + this.address = address; + } + /** + * @return Returns the customerId. + */ + public String getCustomerId() { + return customerId; + } + /** + * @param customerId The customerId to set. + */ + public void setCustomerId(String customerId) { + this.customerId = customerId; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + /** + * @return Returns the orders. + */ + public List getOrders() { + return orders; + } + /** + * @param orders The orders to set. + */ + public void setOrders(List orders) { + this.orders = orders; + } + + public Order generateNewOrder(BigDecimal total) { + Order order = new Order(this); + order.setOrderDate( new GregorianCalendar() ); + order.setTotal( total ); + + return order; + } +} diff --git a/test/org/hibernate/test/cid/LineItem.hbm.xml b/test/org/hibernate/test/cid/LineItem.hbm.xml new file mode 100755 index 0000000000..36d3189345 --- /dev/null +++ b/test/org/hibernate/test/cid/LineItem.hbm.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/cid/LineItem.java b/test/org/hibernate/test/cid/LineItem.java new file mode 100755 index 0000000000..e0192ecd06 --- /dev/null +++ b/test/org/hibernate/test/cid/LineItem.java @@ -0,0 +1,137 @@ +//$Id$ +package org.hibernate.test.cid; + +import java.io.Serializable; + +/** + * @author Gavin King + */ +public class LineItem { + public static class Id implements Serializable { + private String customerId; + private int orderNumber; + private String productId; + + public Id(String customerId, int orderNumber, String productId) { + this.customerId = customerId; + this.orderNumber = orderNumber; + this.productId = productId; + } + public Id() {} + + /** + * @return Returns the customerId. + */ + public String getCustomerId() { + return customerId; + } + /** + * @param customerId The customerId to set. + */ + public void setCustomerId(String customerId) { + this.customerId = customerId; + } + /** + * @return Returns the productId. + */ + public String getProductId() { + return productId; + } + /** + * @param productId The productId to set. + */ + public void setProductId(String productId) { + this.productId = productId; + } + /** + * @return Returns the orderNumber. + */ + public int getOrderNumber() { + return orderNumber; + } + /** + * @param orderNumber The orderNumber to set. + */ + public void setOrderNumber(int orderNumber) { + this.orderNumber = orderNumber; + } + public int hashCode() { + return customerId.hashCode() + orderNumber + productId.hashCode(); + } + public boolean equals(Object other) { + if (other instanceof Id) { + Id that = (Id) other; + return that.customerId.equals(this.customerId) && + that.productId.equals(this.productId) && + that.orderNumber == this.orderNumber; + } + else { + return false; + } + } + } + + private Id id = new Id(); + private int quantity; + private Order order; + private Product product; + + public LineItem(Order o, Product p) { + this.order = o; + this.id.orderNumber = o.getId().getOrderNumber(); + this.id.customerId = o.getId().getCustomerId(); + this.id.productId = p.getProductId(); + o.getLineItems().add(this); + } + + public LineItem() {} + + /** + * @return Returns the order. + */ + public Order getOrder() { + return order; + } + /** + * @param order The order to set. + */ + public void setOrder(Order order) { + this.order = order; + } + /** + * @return Returns the product. + */ + public Product getProduct() { + return product; + } + /** + * @param product The product to set. + */ + public void setProduct(Product product) { + this.product = product; + } + /** + * @return Returns the quantity. + */ + public int getQuantity() { + return quantity; + } + /** + * @param quantity The quantity to set. + */ + public void setQuantity(int quantity) { + this.quantity = quantity; + } + /** + * @return Returns the id. + */ + public Id getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Id id) { + this.id = id; + } +} diff --git a/test/org/hibernate/test/cid/Order.hbm.xml b/test/org/hibernate/test/cid/Order.hbm.xml new file mode 100755 index 0000000000..4f283b6cf7 --- /dev/null +++ b/test/org/hibernate/test/cid/Order.hbm.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/cid/Order.java b/test/org/hibernate/test/cid/Order.java new file mode 100755 index 0000000000..951dc9a645 --- /dev/null +++ b/test/org/hibernate/test/cid/Order.java @@ -0,0 +1,145 @@ +//$Id$ +package org.hibernate.test.cid; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; + +/** + * @author Gavin King + */ +public class Order { + public static class Id implements Serializable { + private String customerId; + private int orderNumber; + + public Id(String customerId, int orderNumber) { + this.customerId = customerId; + this.orderNumber = orderNumber; + } + public Id() {} + + /** + * @return Returns the customerId. + */ + public String getCustomerId() { + return customerId; + } + /** + * @param customerId The customerId to set. + */ + public void setCustomerId(String customerId) { + this.customerId = customerId; + } + /** + * @return Returns the orderNumber. + */ + public int getOrderNumber() { + return orderNumber; + } + /** + * @param orderNumber The orderNumber to set. + */ + public void setOrderNumber(int orderNumber) { + this.orderNumber = orderNumber; + } + public int hashCode() { + return customerId.hashCode() + orderNumber; + } + public boolean equals(Object other) { + if (other instanceof Id) { + Id that = (Id) other; + return that.customerId.equals(this.customerId) && + that.orderNumber == this.orderNumber; + } + else { + return false; + } + } + } + + private Id id = new Id(); + private Calendar orderDate; + private Customer customer; + private Collection lineItems = new ArrayList(); + private BigDecimal total; + + public Order(Customer customer) { + this.customer = customer; + this.id.customerId = customer.getCustomerId(); + this.id.orderNumber = customer.getOrders().size(); + customer.getOrders().add(this); + } + + public Order() {} + + /** + * @return Returns the customer. + */ + public Customer getCustomer() { + return customer; + } + /** + * @param customer The customer to set. + */ + public void setCustomer(Customer customer) { + this.customer = customer; + } + /** + * @return Returns the lineItems. + */ + public Collection getLineItems() { + return lineItems; + } + /** + * @param lineItems The lineItems to set. + */ + public void setLineItems(Collection lineItems) { + this.lineItems = lineItems; + } + /** + * @return Returns the orderDate. + */ + public Calendar getOrderDate() { + return orderDate; + } + /** + * @param orderDate The orderDate to set. + */ + public void setOrderDate(Calendar orderDate) { + this.orderDate = orderDate; + } + /** + * @return Returns the total. + */ + public BigDecimal getTotal() { + return total; + } + /** + * @param total The total to set. + */ + public void setTotal(BigDecimal total) { + this.total = total; + } + /** + * @return Returns the id. + */ + public Id getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Id id) { + this.id = id; + } + + public LineItem generateLineItem( Product product, int quantity ) { + LineItem li = new LineItem( this, product ); + li.setQuantity( quantity ); + lineItems.add( li ); + return li; + } +} diff --git a/test/org/hibernate/test/cid/Product.hbm.xml b/test/org/hibernate/test/cid/Product.hbm.xml new file mode 100755 index 0000000000..8b25befd4d --- /dev/null +++ b/test/org/hibernate/test/cid/Product.hbm.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/cid/Product.java b/test/org/hibernate/test/cid/Product.java new file mode 100755 index 0000000000..7949b3723f --- /dev/null +++ b/test/org/hibernate/test/cid/Product.java @@ -0,0 +1,75 @@ +//$Id$ +package org.hibernate.test.cid; + +import java.math.BigDecimal; + +/** + * @author Gavin King + */ +public class Product { + private String productId; + private String description; + private BigDecimal price; + private int numberAvailable; + private int numberOrdered; + /** + * @return Returns the description. + */ + public String getDescription() { + return description; + } + /** + * @param description The description to set. + */ + public void setDescription(String description) { + this.description = description; + } + /** + * @return Returns the numberAvailable. + */ + public int getNumberAvailable() { + return numberAvailable; + } + /** + * @param numberAvailable The numberAvailable to set. + */ + public void setNumberAvailable(int numberAvailable) { + this.numberAvailable = numberAvailable; + } + /** + * @return Returns the numberOrdered. + */ + public int getNumberOrdered() { + return numberOrdered; + } + /** + * @param numberOrdered The numberOrdered to set. + */ + public void setNumberOrdered(int numberOrdered) { + this.numberOrdered = numberOrdered; + } + /** + * @return Returns the productId. + */ + public String getProductId() { + return productId; + } + /** + * @param productId The productId to set. + */ + public void setProductId(String productId) { + this.productId = productId; + } + /** + * @return Returns the price. + */ + public BigDecimal getPrice() { + return price; + } + /** + * @param price The price to set. + */ + public void setPrice(BigDecimal price) { + this.price = price; + } +} diff --git a/test/org/hibernate/test/collection/CollectionSuite.java b/test/org/hibernate/test/collection/CollectionSuite.java new file mode 100644 index 0000000000..8d3a8bea68 --- /dev/null +++ b/test/org/hibernate/test/collection/CollectionSuite.java @@ -0,0 +1,31 @@ +package org.hibernate.test.collection; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.test.collection.bag.PersistentBagTest; +import org.hibernate.test.collection.idbag.PersistentIdBagTest; +import org.hibernate.test.collection.list.PersistentListTest; +import org.hibernate.test.collection.map.PersistentMapTest; +import org.hibernate.test.collection.original.CollectionTest; +import org.hibernate.test.collection.set.PersistentSetTest; + +/** + * Suite of collection (i.e. PersistentCollection) related tests + * + * @author Steve Ebersole + */ +public class CollectionSuite { + + public static Test suite() { + TestSuite suite = new TestSuite( "Collection-related tests" ); + suite.addTest( PersistentBagTest.suite() ); + suite.addTest( PersistentIdBagTest.suite() ); + suite.addTest( PersistentListTest.suite() ); + suite.addTest( PersistentMapTest.suite() ); + suite.addTest( CollectionTest.suite() ); + suite.addTest( PersistentSetTest.suite() ); + return suite; + } + +} diff --git a/test/org/hibernate/test/collection/bag/BagOwner.java b/test/org/hibernate/test/collection/bag/BagOwner.java new file mode 100644 index 0000000000..aff7e10aa3 --- /dev/null +++ b/test/org/hibernate/test/collection/bag/BagOwner.java @@ -0,0 +1,46 @@ +package org.hibernate.test.collection.bag; + +import java.util.List; +import java.util.ArrayList; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class BagOwner { + private String name; + private BagOwner parent; + private List children = new ArrayList(); + + public BagOwner() { + } + + public BagOwner(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public BagOwner getParent() { + return parent; + } + + public void setParent(BagOwner parent) { + this.parent = parent; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } +} diff --git a/test/org/hibernate/test/collection/bag/Mappings.hbm.xml b/test/org/hibernate/test/collection/bag/Mappings.hbm.xml new file mode 100644 index 0000000000..c76b1ea27b --- /dev/null +++ b/test/org/hibernate/test/collection/bag/Mappings.hbm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/collection/bag/PersistentBagTest.java b/test/org/hibernate/test/collection/bag/PersistentBagTest.java new file mode 100644 index 0000000000..c8fdebb47a --- /dev/null +++ b/test/org/hibernate/test/collection/bag/PersistentBagTest.java @@ -0,0 +1,70 @@ +package org.hibernate.test.collection.bag; + +import java.util.ArrayList; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.collection.PersistentBag; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Tests related to operations on a PersistentBag. + * + * @author Steve Ebersole + */ +public class PersistentBagTest extends FunctionalTestCase { + public PersistentBagTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "collection/bag/Mappings.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PersistentBagTest.class ); + } + + public void testWriteMethodDirtying() { + BagOwner parent = new BagOwner( "root" ); + BagOwner child = new BagOwner( "c1" ); + parent.getChildren().add( child ); + child.setParent( parent ); + BagOwner otherChild = new BagOwner( "c2" ); + + Session session = openSession(); + session.beginTransaction(); + session.save( parent ); + session.flush(); + // at this point, the list on parent has now been replaced with a PersistentBag... + PersistentBag children = ( PersistentBag ) parent.getChildren(); + + assertFalse( children.remove( otherChild ) ); + assertFalse( children.isDirty() ); + + ArrayList otherCollection = new ArrayList(); + otherCollection.add( child ); + assertFalse( children.retainAll( otherCollection ) ); + assertFalse( children.isDirty() ); + + otherCollection = new ArrayList(); + otherCollection.add( otherChild ); + assertFalse( children.removeAll( otherCollection ) ); + assertFalse( children.isDirty() ); + + children.clear(); + session.delete( child ); + assertTrue( children.isDirty() ); + + session.flush(); + + children.clear(); + assertFalse( children.isDirty() ); + + session.delete( parent ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/collection/idbag/IdbagOwner.java b/test/org/hibernate/test/collection/idbag/IdbagOwner.java new file mode 100644 index 0000000000..1dc4cc5bd7 --- /dev/null +++ b/test/org/hibernate/test/collection/idbag/IdbagOwner.java @@ -0,0 +1,37 @@ +package org.hibernate.test.collection.idbag; + +import java.util.List; +import java.util.ArrayList; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class IdbagOwner { + private String name; + private List children = new ArrayList(); + + public IdbagOwner() { + } + + public IdbagOwner(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } +} diff --git a/test/org/hibernate/test/collection/idbag/Mappings.hbm.xml b/test/org/hibernate/test/collection/idbag/Mappings.hbm.xml new file mode 100644 index 0000000000..ebef25c54c --- /dev/null +++ b/test/org/hibernate/test/collection/idbag/Mappings.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/collection/idbag/PersistentIdBagTest.java b/test/org/hibernate/test/collection/idbag/PersistentIdBagTest.java new file mode 100644 index 0000000000..198fc399d6 --- /dev/null +++ b/test/org/hibernate/test/collection/idbag/PersistentIdBagTest.java @@ -0,0 +1,69 @@ +package org.hibernate.test.collection.idbag; + +import java.util.ArrayList; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.collection.PersistentIdentifierBag; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Tests related to operations on a PersistentIdentifierBag + * + * @author Steve Ebersole + */ +public class PersistentIdBagTest extends FunctionalTestCase { + public PersistentIdBagTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "collection/idbag/Mappings.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PersistentIdBagTest.class ); + } + + public void testWriteMethodDirtying() { + IdbagOwner parent = new IdbagOwner( "root" ); + IdbagOwner child = new IdbagOwner( "c1" ); + parent.getChildren().add( child ); + IdbagOwner otherChild = new IdbagOwner( "c2" ); + + Session session = openSession(); + session.beginTransaction(); + session.save( parent ); + session.flush(); + // at this point, the list on parent has now been replaced with a PersistentBag... + PersistentIdentifierBag children = ( PersistentIdentifierBag ) parent.getChildren(); + + assertFalse( children.remove( otherChild ) ); + assertFalse( children.isDirty() ); + + ArrayList otherCollection = new ArrayList(); + otherCollection.add( child ); + assertFalse( children.retainAll( otherCollection ) ); + assertFalse( children.isDirty() ); + + otherCollection = new ArrayList(); + otherCollection.add( otherChild ); + assertFalse( children.removeAll( otherCollection ) ); + assertFalse( children.isDirty() ); + + children.clear(); + session.delete( child ); + assertTrue( children.isDirty() ); + + session.flush(); + + children.clear(); + assertFalse( children.isDirty() ); + + session.delete( parent ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/collection/list/ListOwner.java b/test/org/hibernate/test/collection/list/ListOwner.java new file mode 100644 index 0000000000..016a9590bd --- /dev/null +++ b/test/org/hibernate/test/collection/list/ListOwner.java @@ -0,0 +1,46 @@ +package org.hibernate.test.collection.list; + +import java.util.List; +import java.util.ArrayList; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class ListOwner { + private String name; + private ListOwner parent; + private List children = new ArrayList(); + + public ListOwner() { + } + + public ListOwner(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ListOwner getParent() { + return parent; + } + + public void setParent(ListOwner parent) { + this.parent = parent; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } +} diff --git a/test/org/hibernate/test/collection/list/Mappings.hbm.xml b/test/org/hibernate/test/collection/list/Mappings.hbm.xml new file mode 100644 index 0000000000..013c08cd85 --- /dev/null +++ b/test/org/hibernate/test/collection/list/Mappings.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/collection/list/PersistentListTest.java b/test/org/hibernate/test/collection/list/PersistentListTest.java new file mode 100644 index 0000000000..a188f3d737 --- /dev/null +++ b/test/org/hibernate/test/collection/list/PersistentListTest.java @@ -0,0 +1,70 @@ +package org.hibernate.test.collection.list; + +import java.util.ArrayList; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.collection.PersistentList; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Tests related to operations on a PersistentList + * + * @author Steve Ebersole + */ +public class PersistentListTest extends FunctionalTestCase { + public PersistentListTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "collection/list/Mappings.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PersistentListTest.class ); + } + + public void testWriteMethodDirtying() { + ListOwner parent = new ListOwner( "root" ); + ListOwner child = new ListOwner( "c1" ); + parent.getChildren().add( child ); + child.setParent( parent ); + ListOwner otherChild = new ListOwner( "c2" ); + + Session session = openSession(); + session.beginTransaction(); + session.save( parent ); + session.flush(); + // at this point, the list on parent has now been replaced with a PersistentList... + PersistentList children = ( PersistentList ) parent.getChildren(); + + assertFalse( children.remove( otherChild ) ); + assertFalse( children.isDirty() ); + + ArrayList otherCollection = new ArrayList(); + otherCollection.add( child ); + assertFalse( children.retainAll( otherCollection ) ); + assertFalse( children.isDirty() ); + + otherCollection = new ArrayList(); + otherCollection.add( otherChild ); + assertFalse( children.removeAll( otherCollection ) ); + assertFalse( children.isDirty() ); + + children.clear(); + session.delete( child ); + assertTrue( children.isDirty() ); + + session.flush(); + + children.clear(); + assertFalse( children.isDirty() ); + + session.delete( parent ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/collection/map/Child.java b/test/org/hibernate/test/collection/map/Child.java new file mode 100644 index 0000000000..a0a57b7172 --- /dev/null +++ b/test/org/hibernate/test/collection/map/Child.java @@ -0,0 +1,34 @@ +package org.hibernate.test.collection.map; + +/** + * todo: describe Child + * + * @author Steve Ebersole + */ +public class Child { + private String name; + private Parent parent; + + public Child() { + } + + public Child(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } +} diff --git a/test/org/hibernate/test/collection/map/Mappings.hbm.xml b/test/org/hibernate/test/collection/map/Mappings.hbm.xml new file mode 100644 index 0000000000..97c6472bc1 --- /dev/null +++ b/test/org/hibernate/test/collection/map/Mappings.hbm.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/collection/map/Parent.java b/test/org/hibernate/test/collection/map/Parent.java new file mode 100644 index 0000000000..0e82afce28 --- /dev/null +++ b/test/org/hibernate/test/collection/map/Parent.java @@ -0,0 +1,48 @@ +package org.hibernate.test.collection.map; + +import java.util.Map; +import java.util.HashMap; + +/** + * todo: describe Parent + * + * @author Steve Ebersole + */ +public class Parent { + private String name; + private Map children = new HashMap(); + + public Parent() { + } + + public Parent(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getChildren() { + return children; + } + + public void setChildren(Map children) { + this.children = children; + } + + public Child addChild(String name) { + Child child = new Child( name ); + addChild( child ); + return child; + } + + public void addChild(Child child) { + child.setParent( this ); + getChildren().put( child.getName(), child ); + } +} diff --git a/test/org/hibernate/test/collection/map/PersistentMapTest.java b/test/org/hibernate/test/collection/map/PersistentMapTest.java new file mode 100644 index 0000000000..03a4583290 --- /dev/null +++ b/test/org/hibernate/test/collection/map/PersistentMapTest.java @@ -0,0 +1,102 @@ +package org.hibernate.test.collection.map; + +import java.util.HashMap; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.collection.PersistentMap; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * todo: describe PersistentMapTest + * + * @author Steve Ebersole + */ +public class PersistentMapTest extends FunctionalTestCase { + public PersistentMapTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "collection/map/Mappings.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PersistentMapTest.class ); + } + + public void testWriteMethodDirtying() { + Parent parent = new Parent( "p1" ); + Child child = new Child( "c1" ); + parent.getChildren().put( child.getName(), child ); + child.setParent( parent ); + Child otherChild = new Child( "c2" ); + + Session session = openSession(); + session.beginTransaction(); + session.save( parent ); + session.flush(); + // at this point, the set on parent has now been replaced with a PersistentSet... + PersistentMap children = ( PersistentMap ) parent.getChildren(); + + Object old = children.put( child.getName(), child ); + assertTrue( old == child ); + assertFalse( children.isDirty() ); + + old = children.remove( otherChild.getName() ); + assertNull( old ); + assertFalse( children.isDirty() ); + + HashMap otherMap = new HashMap(); + otherMap.put( child.getName(), child ); + children.putAll( otherMap ); + assertFalse( children.isDirty() ); + + otherMap = new HashMap(); + otherMap.put( otherChild.getName(), otherChild ); + children.putAll( otherMap ); + assertTrue( children.isDirty() ); + + children.clearDirty(); + session.delete( child ); + children.clear(); + assertTrue( children.isDirty() ); + session.flush(); + + children.clear(); + assertFalse( children.isDirty() ); + + session.delete( parent ); + session.getTransaction().commit(); + session.close(); + } + + public void testPutAgainstUninitializedMap() { + // prepare map owner... + Session session = openSession(); + session.beginTransaction(); + Parent parent = new Parent( "p1" ); + session.save( parent ); + session.getTransaction().commit(); + session.close(); + + // Now, reload the parent and test adding children + session = openSession(); + session.beginTransaction(); + parent = ( Parent ) session.get( Parent.class, parent.getName() ); + parent.addChild( "c1" ); + parent.addChild( "c2" ); + session.getTransaction().commit(); + session.close(); + + assertEquals( 2, parent.getChildren().size() ); + + session = openSession(); + session.beginTransaction(); + session.delete( parent ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/collection/original/CollectionTest.java b/test/org/hibernate/test/collection/original/CollectionTest.java new file mode 100644 index 0000000000..b80048c57f --- /dev/null +++ b/test/org/hibernate/test/collection/original/CollectionTest.java @@ -0,0 +1,228 @@ +//$Id: CollectionTest.java 7628 2005-07-24 06:55:01Z oneovthafew $ +package org.hibernate.test.collection.original; + +import java.sql.SQLException; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class CollectionTest extends FunctionalTestCase { + + public CollectionTest(String str) { + super( str ); + } + + public String[] getMappings() { + return new String[] { "collection/original/UserPermissions.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CollectionTest.class ); + } + + public void testExtraLazy() throws HibernateException, SQLException { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User u = new User( "gavin" ); + u.getPermissions().add( new Permission( "obnoxiousness" ) ); + u.getPermissions().add( new Permission( "pigheadedness" ) ); + u.getSessionData().put( "foo", "foo value" ); + s.persist( u ); + t.commit(); + s.close(); + s = openSession(); + t = s.beginTransaction(); + u = ( User ) s.get( User.class, "gavin" ); + + assertFalse( Hibernate.isInitialized( u.getPermissions() ) ); + assertEquals( u.getPermissions().size(), 2 ); + assertTrue( u.getPermissions().contains( new Permission( "obnoxiousness" ) ) ); + assertFalse( u.getPermissions().contains( new Permission( "silliness" ) ) ); + assertNotNull( u.getPermissions().get( 1 ) ); + assertNull( u.getPermissions().get( 3 ) ); + assertFalse( Hibernate.isInitialized( u.getPermissions() ) ); + + assertFalse( Hibernate.isInitialized( u.getSessionData() ) ); + assertEquals( u.getSessionData().size(), 1 ); + assertTrue( u.getSessionData().containsKey( "foo" ) ); + assertFalse( u.getSessionData().containsKey( "bar" ) ); + assertTrue( u.getSessionData().containsValue( "foo value" ) ); + assertFalse( u.getSessionData().containsValue( "bar" ) ); + assertEquals( "foo value", u.getSessionData().get( "foo" ) ); + assertNull( u.getSessionData().get( "bar" ) ); + assertFalse( Hibernate.isInitialized( u.getSessionData() ) ); + + assertFalse( Hibernate.isInitialized( u.getSessionData() ) ); + u.getSessionData().put( "bar", "bar value" ); + u.getSessionAttributeNames().add( "bar" ); + assertFalse( Hibernate.isInitialized( u.getSessionAttributeNames() ) ); + assertTrue( Hibernate.isInitialized( u.getSessionData() ) ); + + s.delete( u ); + t.commit(); + s.close(); + } + + public void testMerge() throws HibernateException, SQLException { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User u = new User( "gavin" ); + u.getPermissions().add( new Permission( "obnoxiousness" ) ); + u.getPermissions().add( new Permission( "pigheadedness" ) ); + s.persist( u ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + User u2 = ( User ) s.createCriteria( User.class ).uniqueResult(); + u2.setPermissions( null ); //forces one shot delete + s.merge( u ); + t.commit(); + s.close(); + + u.getPermissions().add( new Permission( "silliness" ) ); + + s = openSession(); + t = s.beginTransaction(); + s.merge( u ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + u2 = ( User ) s.createCriteria( User.class ).uniqueResult(); + assertEquals( u2.getPermissions().size(), 3 ); + assertEquals( ( ( Permission ) u2.getPermissions().get( 0 ) ).getType(), "obnoxiousness" ); + assertEquals( ( ( Permission ) u2.getPermissions().get( 2 ) ).getType(), "silliness" ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete( u2 ); + s.flush(); + t.commit(); + s.close(); + + } + + public void testFetch() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User u = new User( "gavin" ); + u.getPermissions().add( new Permission( "obnoxiousness" ) ); + u.getPermissions().add( new Permission( "pigheadedness" ) ); + u.getEmailAddresses().add( new Email( "gavin@hibernate.org" ) ); + u.getEmailAddresses().add( new Email( "gavin.king@jboss.com" ) ); + s.persist( u ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + User u2 = ( User ) s.createCriteria( User.class ).uniqueResult(); + assertTrue( Hibernate.isInitialized( u2.getEmailAddresses() ) ); + assertFalse( Hibernate.isInitialized( u2.getPermissions() ) ); + assertEquals( u2.getEmailAddresses().size(), 2 ); + s.delete( u2 ); + t.commit(); + s.close(); + } + + public void testUpdateOrder() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User u = new User( "gavin" ); + u.getSessionData().put( "foo", "foo value" ); + u.getSessionData().put( "bar", "bar value" ); + u.getEmailAddresses().add( new Email( "gavin.king@jboss.com" ) ); + u.getEmailAddresses().add( new Email( "gavin@hibernate.org" ) ); + u.getEmailAddresses().add( new Email( "gavin@illflow.com" ) ); + u.getEmailAddresses().add( new Email( "gavin@nospam.com" ) ); + s.persist( u ); + t.commit(); + s.close(); + + u.getSessionData().clear(); + u.getSessionData().put( "baz", "baz value" ); + u.getSessionData().put( "bar", "bar value" ); + u.getEmailAddresses().remove( 0 ); + u.getEmailAddresses().remove( 2 ); + + s = openSession(); + t = s.beginTransaction(); + s.update( u ); + t.commit(); + s.close(); + + u.getSessionData().clear(); + u.getEmailAddresses().add( 0, new Email( "gavin@nospam.com" ) ); + u.getEmailAddresses().add( new Email( "gavin.king@jboss.com" ) ); + + s = openSession(); + t = s.beginTransaction(); + s.update( u ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete( u ); + t.commit(); + s.close(); + + } + + public void testValueMap() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User u = new User( "gavin" ); + u.getSessionData().put( "foo", "foo value" ); + u.getSessionData().put( "bar", null ); + u.getEmailAddresses().add( null ); + u.getEmailAddresses().add( new Email( "gavin.king@jboss.com" ) ); + u.getEmailAddresses().add( null ); + u.getEmailAddresses().add( null ); + s.persist( u ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + User u2 = ( User ) s.createCriteria( User.class ).uniqueResult(); + assertFalse( Hibernate.isInitialized( u2.getSessionData() ) ); + assertEquals( u2.getSessionData().size(), 1 ); + assertEquals( u2.getEmailAddresses().size(), 2 ); + u2.getSessionData().put( "foo", "new foo value" ); + u2.getEmailAddresses().set( 1, new Email( "gavin@hibernate.org" ) ); + //u2.getEmailAddresses().remove(3); + //u2.getEmailAddresses().remove(2); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + u2 = ( User ) s.createCriteria( User.class ).uniqueResult(); + assertFalse( Hibernate.isInitialized( u2.getSessionData() ) ); + assertEquals( u2.getSessionData().size(), 1 ); + assertEquals( u2.getEmailAddresses().size(), 2 ); + assertEquals( u2.getSessionData().get( "foo" ), "new foo value" ); + assertEquals( ( ( Email ) u2.getEmailAddresses().get( 1 ) ).getAddress(), "gavin@hibernate.org" ); + s.delete( u2 ); + t.commit(); + s.close(); + } + + +} + diff --git a/test/org/hibernate/test/collection/original/Email.java b/test/org/hibernate/test/collection/original/Email.java new file mode 100644 index 0000000000..f2d9b85eee --- /dev/null +++ b/test/org/hibernate/test/collection/original/Email.java @@ -0,0 +1,27 @@ +//$Id: Email.java 5686 2005-02-12 07:27:32Z steveebersole $ +package org.hibernate.test.collection.original; + +/** + * @author Gavin King + */ +public class Email { + private String address; + Email() {} + public String getAddress() { + return address; + } + public void setAddress(String type) { + this.address = type; + } + public Email(String type) { + this.address = type; + } + public boolean equals(Object that) { + if ( !(that instanceof Email) ) return false; + Email p = (Email) that; + return this.address.equals(p.address); + } + public int hashCode() { + return address.hashCode(); + } +} diff --git a/test/org/hibernate/test/collection/original/Permission.java b/test/org/hibernate/test/collection/original/Permission.java new file mode 100644 index 0000000000..bbaf7727a2 --- /dev/null +++ b/test/org/hibernate/test/collection/original/Permission.java @@ -0,0 +1,27 @@ +//$Id: Permission.java 5686 2005-02-12 07:27:32Z steveebersole $ +package org.hibernate.test.collection.original; + +/** + * @author Gavin King + */ +public class Permission { + private String type; + Permission() {} + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public Permission(String type) { + this.type = type; + } + public boolean equals(Object that) { + if ( !(that instanceof Permission) ) return false; + Permission p = (Permission) that; + return this.type.equals(p.type); + } + public int hashCode() { + return type.hashCode(); + } +} diff --git a/test/org/hibernate/test/collection/original/User.java b/test/org/hibernate/test/collection/original/User.java new file mode 100644 index 0000000000..938ecc08d9 --- /dev/null +++ b/test/org/hibernate/test/collection/original/User.java @@ -0,0 +1,55 @@ +//$Id: User.java 7628 2005-07-24 06:55:01Z oneovthafew $ +package org.hibernate.test.collection.original; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Gavin King + */ +public class User { + private String userName; + private List permissions = new ArrayList(); + private List emailAddresses = new ArrayList(); + private Map sessionData = new HashMap(); + private Set sessionAttributeNames = new HashSet(); + + User() {} + public User(String name) { + userName = name; + } + public List getPermissions() { + return permissions; + } + public void setPermissions(List permissions) { + this.permissions = permissions; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public List getEmailAddresses() { + return emailAddresses; + } + public void setEmailAddresses(List emailAddresses) { + this.emailAddresses = emailAddresses; + } + public Map getSessionData() { + return sessionData; + } + public void setSessionData(Map sessionData) { + this.sessionData = sessionData; + } + public Set getSessionAttributeNames() { + return sessionAttributeNames; + } + public void setSessionAttributeNames(Set sessionAttributeNames) { + this.sessionAttributeNames = sessionAttributeNames; + } +} diff --git a/test/org/hibernate/test/collection/original/UserPermissions.hbm.xml b/test/org/hibernate/test/collection/original/UserPermissions.hbm.xml new file mode 100644 index 0000000000..13b6a9b40c --- /dev/null +++ b/test/org/hibernate/test/collection/original/UserPermissions.hbm.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/collection/set/Child.java b/test/org/hibernate/test/collection/set/Child.java new file mode 100644 index 0000000000..a3570d2632 --- /dev/null +++ b/test/org/hibernate/test/collection/set/Child.java @@ -0,0 +1,34 @@ +package org.hibernate.test.collection.set; + +/** + * todo: describe Child + * + * @author Steve Ebersole + */ +public class Child { + private String name; + private Parent parent; + + public Child() { + } + + public Child(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } +} diff --git a/test/org/hibernate/test/collection/set/Mappings.hbm.xml b/test/org/hibernate/test/collection/set/Mappings.hbm.xml new file mode 100644 index 0000000000..5c716ed483 --- /dev/null +++ b/test/org/hibernate/test/collection/set/Mappings.hbm.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/collection/set/Parent.java b/test/org/hibernate/test/collection/set/Parent.java new file mode 100644 index 0000000000..44fc88a1bb --- /dev/null +++ b/test/org/hibernate/test/collection/set/Parent.java @@ -0,0 +1,37 @@ +package org.hibernate.test.collection.set; + +import java.util.Set; +import java.util.HashSet; + +/** + * todo: describe Parent + * + * @author Steve Ebersole + */ +public class Parent { + private String name; + private Set children = new HashSet(); + + public Parent() { + } + + public Parent(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getChildren() { + return children; + } + + public void setChildren(Set children) { + this.children = children; + } +} diff --git a/test/org/hibernate/test/collection/set/PersistentSetTest.java b/test/org/hibernate/test/collection/set/PersistentSetTest.java new file mode 100644 index 0000000000..808d20dc27 --- /dev/null +++ b/test/org/hibernate/test/collection/set/PersistentSetTest.java @@ -0,0 +1,80 @@ +package org.hibernate.test.collection.set; + +import java.util.HashSet; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.collection.PersistentSet; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * todo: describe PersistentSetTest + * + * @author Steve Ebersole + */ +public class PersistentSetTest extends FunctionalTestCase { + public PersistentSetTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "collection/set/Mappings.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PersistentSetTest.class ); + } + + public void testWriteMethodDirtying() { + Parent parent = new Parent( "p1" ); + Child child = new Child( "c1" ); + parent.getChildren().add( child ); + child.setParent( parent ); + Child otherChild = new Child( "c2" ); + + Session session = openSession(); + session.beginTransaction(); + session.save( parent ); + session.flush(); + // at this point, the set on parent has now been replaced with a PersistentSet... + PersistentSet children = ( PersistentSet ) parent.getChildren(); + + assertFalse( children.add( child ) ); + assertFalse( children.isDirty() ); + + assertFalse( children.remove( otherChild ) ); + assertFalse( children.isDirty() ); + + HashSet otherSet = new HashSet(); + otherSet.add( child ); + assertFalse( children.addAll( otherSet ) ); + assertFalse( children.isDirty() ); + + assertFalse( children.retainAll( otherSet ) ); + assertFalse( children.isDirty() ); + + otherSet = new HashSet(); + otherSet.add( otherChild ); + assertFalse( children.removeAll( otherSet ) ); + assertFalse( children.isDirty() ); + + assertTrue( children.retainAll( otherSet )); + assertTrue( children.isDirty() ); + assertTrue( children.isEmpty() ); + + children.clear(); + session.delete( child ); + assertTrue( children.isDirty() ); + + session.flush(); + + children.clear(); + assertFalse( children.isDirty() ); + + session.delete( parent ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/component/ComponentSuite.java b/test/org/hibernate/test/component/ComponentSuite.java new file mode 100644 index 0000000000..aeefbd3f15 --- /dev/null +++ b/test/org/hibernate/test/component/ComponentSuite.java @@ -0,0 +1,23 @@ +package org.hibernate.test.component; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.test.component.basic.ComponentTest; +import org.hibernate.test.component.cascading.collection.CascadeToComponentCollectionTest; +import org.hibernate.test.component.cascading.toone.CascadeToComponentAssociationTest; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class ComponentSuite { + public static Test suite() { + TestSuite suite = new TestSuite( "component test suite" ); + suite.addTest( ComponentTest.suite() ); + suite.addTest( CascadeToComponentCollectionTest.suite() ); + suite.addTest( CascadeToComponentAssociationTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/component/basic/ComponentTest.java b/test/org/hibernate/test/component/basic/ComponentTest.java new file mode 100755 index 0000000000..d85a385940 --- /dev/null +++ b/test/org/hibernate/test/component/basic/ComponentTest.java @@ -0,0 +1,194 @@ +//$Id$ +package org.hibernate.test.component.basic; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.cfg.Mappings; +import org.hibernate.criterion.Property; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.Formula; +import org.hibernate.mapping.PersistentClass; + +/** + * @author Gavin King + */ +public class ComponentTest extends FunctionalTestCase { + + public ComponentTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "component/basic/User.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ComponentTest.class ); + } + + public void configure(Configuration cfg) { + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + } + + public void afterConfigurationBuilt(Mappings mappings, Dialect dialect) { + super.afterConfigurationBuilt( mappings, dialect ); + // Oracle and Postgres do not have year() functions, so we need to + // redefine the 'User.person.yob' formula + // + // consider temporary until we add the capability to define + // mapping foprmulas which can use dialect-registered functions... + PersistentClass user = mappings.getClass( User.class.getName() ); + org.hibernate.mapping.Property personProperty = user.getProperty( "person" ); + Component component = ( Component ) personProperty.getValue(); + Formula f = ( Formula ) component.getProperty( "yob" ).getValue().getColumnIterator().next(); + + SQLFunction yearFunction = ( SQLFunction ) dialect.getFunctions().get( "year" ); + if ( yearFunction == null ) { + // the dialect not know to support a year() function, so rely on the + // ANSI SQL extract function + f.setFormula( "extract( year from dob )"); + } + else { + List args = new ArrayList(); + args.add( "dob" ); + f.setFormula( yearFunction.render( args, null ) ); + } + } + + public void testUpdateFalse() { + getSessions().getStatistics().clear(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + User u = new User( "gavin", "secret", new Person("Gavin King", new Date(), "Karbarook Ave") ); + s.persist(u); + s.flush(); + u.getPerson().setName("XXXXYYYYY"); + t.commit(); + s.close(); + + assertEquals( 1, getSessions().getStatistics().getEntityInsertCount() ); + assertEquals( 0, getSessions().getStatistics().getEntityUpdateCount() ); + + s = openSession(); + t = s.beginTransaction(); + u = (User) s.get(User.class, "gavin"); + assertEquals( u.getPerson().getName(), "Gavin King" ); + s.delete(u); + t.commit(); + s.close(); + + assertEquals( 1, getSessions().getStatistics().getEntityDeleteCount() ); + } + + public void testComponent() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User u = new User( "gavin", "secret", new Person("Gavin King", new Date(), "Karbarook Ave") ); + s.persist(u); + s.flush(); + u.getPerson().changeAddress("Phipps Place"); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + u = (User) s.get(User.class, "gavin"); + assertEquals( u.getPerson().getAddress(), "Phipps Place" ); + assertEquals( u.getPerson().getPreviousAddress(), "Karbarook Ave" ); + assertEquals( u.getPerson().getYob(), u.getPerson().getDob().getYear()+1900 ); + u.setPassword("$ecret"); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + u = (User) s.get(User.class, "gavin"); + assertEquals( u.getPerson().getAddress(), "Phipps Place" ); + assertEquals( u.getPerson().getPreviousAddress(), "Karbarook Ave" ); + assertEquals( u.getPassword(), "$ecret" ); + s.delete(u); + t.commit(); + s.close(); + } + + public void testComponentStateChangeAndDirtiness() { + // test for HHH-2366 + Session s = openSession(); + s.beginTransaction(); + User u = new User( "steve", "hibernater", new Person( "Steve Ebersole", new Date(), "Main St") ); + s.persist( u ); + s.flush(); + long intialUpdateCount = sfi().getStatistics().getEntityUpdateCount(); + u.getPerson().setAddress( "Austin" ); + s.flush(); + assertEquals( intialUpdateCount + 1, sfi().getStatistics().getEntityUpdateCount() ); + intialUpdateCount = sfi().getStatistics().getEntityUpdateCount(); + u.getPerson().setAddress( "Cedar Park" ); + s.flush(); + assertEquals( intialUpdateCount + 1, sfi().getStatistics().getEntityUpdateCount() ); + s.delete( u ); + s.getTransaction().commit(); + s.close(); + } + + public void testComponentQueries() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Employee emp = new Employee(); + emp.setHireDate( new Date() ); + emp.setPerson( new Person() ); + emp.getPerson().setName( "steve" ); + emp.getPerson().setDob( new Date() ); + s.save( emp ); + + s.createQuery( "from Employee e where e.person = :p and 1 = 1 and 2=2" ).setParameter( "p", emp.getPerson() ).list(); + s.createQuery( "from Employee e where :p = e.person" ).setParameter( "p", emp.getPerson() ).list(); + s.createQuery( "from Employee e where e.person = ('steve', current_timestamp)" ).list(); + + s.delete( emp ); + t.commit(); + s.close(); + } + + public void testComponentFormulaQuery() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createQuery("from User u where u.person.yob = 1999").list(); + s.createCriteria(User.class) + .add( Property.forName("person.yob").between( new Integer(1999), new Integer(2002) ) ) + .list(); + if ( getDialect().supportsRowValueConstructorSyntax() ) { + s.createQuery("from User u where u.person = ('gavin', :dob, 'Peachtree Rd', 'Karbarook Ave', 1974, 'Peachtree Rd')") + .setDate("dob", new Date("March 25, 1974")).list(); + s.createQuery("from User where person = ('gavin', :dob, 'Peachtree Rd', 'Karbarook Ave', 1974, 'Peachtree Rd')") + .setDate("dob", new Date("March 25, 1974")).list(); + } + t.commit(); + s.close(); + } + + public void testNamedQuery() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.getNamedQuery("userNameIn") + .setParameterList( "nameList", new Object[] {"1ovthafew", "turin", "xam"} ) + .list(); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/component/basic/Employee.java b/test/org/hibernate/test/component/basic/Employee.java new file mode 100644 index 0000000000..e2ad3c60d2 --- /dev/null +++ b/test/org/hibernate/test/component/basic/Employee.java @@ -0,0 +1,38 @@ +package org.hibernate.test.component.basic; + +import java.util.Date; + +/** + * todo: describe Employee + * + * @author Steve Ebersole + */ +public class Employee { + private Long id; + private Person person; + private Date hireDate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } + + public Date getHireDate() { + return hireDate; + } + + public void setHireDate(Date hireDate) { + this.hireDate = hireDate; + } +} diff --git a/test/org/hibernate/test/component/basic/Person.java b/test/org/hibernate/test/component/basic/Person.java new file mode 100755 index 0000000000..ee18748ae7 --- /dev/null +++ b/test/org/hibernate/test/component/basic/Person.java @@ -0,0 +1,63 @@ +//$Id$ +package org.hibernate.test.component.basic; + +import java.util.Date; + +/** + * @author Gavin King + */ +public class Person { + private String name; + private Date dob; + private String address; + private String currentAddress; + private String previousAddress; + private int yob; + Person() {} + public Person(String name, Date dob, String address) { + this.name = name; + this.dob = dob; + this.address = address; + this.currentAddress = address; + } + public int getYob() { + return yob; + } + public void setYob(int age) { + this.yob = age; + } + public String getAddress() { + return address; + } + public void setAddress(String address) { + this.address = address; + } + public Date getDob() { + return dob; + } + public void setDob(Date dob) { + this.dob = dob; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getPreviousAddress() { + return previousAddress; + } + public void setPreviousAddress(String previousAddress) { + this.previousAddress = previousAddress; + } + public void changeAddress(String add) { + setPreviousAddress( getAddress() ); + setAddress(add); + } + public String getCurrentAddress() { + return currentAddress; + } + public void setCurrentAddress(String currentAddress) { + this.currentAddress = currentAddress; + } +} diff --git a/test/org/hibernate/test/component/basic/User.hbm.xml b/test/org/hibernate/test/component/basic/User.hbm.xml new file mode 100755 index 0000000000..c39c777db1 --- /dev/null +++ b/test/org/hibernate/test/component/basic/User.hbm.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/component/basic/User.java b/test/org/hibernate/test/component/basic/User.java new file mode 100755 index 0000000000..4ad0ded27e --- /dev/null +++ b/test/org/hibernate/test/component/basic/User.java @@ -0,0 +1,44 @@ +//$Id$ +package org.hibernate.test.component.basic; + +import java.util.Date; + +/** + * @author Gavin King + */ +public class User { + private String userName; + private String password; + private Person person; + private Date lastModified; + User() {} + public User(String id, String pw, Person person) { + this.userName = id; + this.password = pw; + this.person = person; + } + public Date getLastModified() { + return lastModified; + } + public void setLastModified(Date lastModified) { + this.lastModified = lastModified; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public Person getPerson() { + return person; + } + public void setPerson(Person person) { + this.person = person; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } +} diff --git a/test/org/hibernate/test/component/cascading/collection/CascadeToComponentCollectionTest.java b/test/org/hibernate/test/component/cascading/collection/CascadeToComponentCollectionTest.java new file mode 100644 index 0000000000..5e95c30af5 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/collection/CascadeToComponentCollectionTest.java @@ -0,0 +1,116 @@ +package org.hibernate.test.component.cascading.collection; + +import java.util.Iterator; +import java.util.Locale; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class CascadeToComponentCollectionTest extends FunctionalTestCase { + + public CascadeToComponentCollectionTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "component/cascading/collection/Mappings.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CascadeToComponentCollectionTest.class ); + } + + public void testMerging() { + // step1, we create a definition with one value + Session session = openSession(); + session.beginTransaction(); + Definition definition = new Definition(); + Value value1 = new Value( definition ); + value1.getLocalizedStrings().addString( new Locale( "en_US" ), "hello" ); + session.persist( definition ); + session.getTransaction().commit(); + session.close(); + + // step2, we verify that the definition has one value; then we detach it + session = openSession(); + session.beginTransaction(); + definition = ( Definition ) session.get( Definition.class, definition.getId() ); + assertEquals( 1, definition.getValues().size() ); + session.getTransaction().commit(); + session.close(); + + // step3, we add a new value during detachment + Value value2 = new Value( definition ); + value2.getLocalizedStrings().addString( new Locale( "es" ), "hola" ); + + // step4 we merge the definition + session = openSession(); + session.beginTransaction(); + session.merge( definition ); + session.getTransaction().commit(); + session.close(); + + // step5, final test + session = openSession(); + session.beginTransaction(); + definition = ( Definition ) session.get( Definition.class, definition.getId() ); + assertEquals( 2, definition.getValues().size() ); + Iterator values = definition.getValues().iterator(); + while ( values.hasNext() ) { + assertEquals( 1, ( ( Value ) values.next() ).getLocalizedStrings().getStringsCopy().size() ); + } + session.getTransaction().commit(); + session.close(); + } + + public void testMergingOriginallyNullComponent() { + // step1, we create a definition with one value, but with a null component + Session session = openSession(); + session.beginTransaction(); + Definition definition = new Definition(); + Value value1 = new Value( definition ); + session.persist( definition ); + session.getTransaction().commit(); + session.close(); + + // step2, we verify that the definition has one value; then we detach it + session = openSession(); + session.beginTransaction(); + definition = ( Definition ) session.get( Definition.class, definition.getId() ); + assertEquals( 1, definition.getValues().size() ); + session.getTransaction().commit(); + session.close(); + + // step3, we add a new value during detachment + ( ( Value ) definition.getValues().iterator().next() ).getLocalizedStrings().addString( new Locale( "en_US" ), "hello" ); + Value value2 = new Value( definition ); + value2.getLocalizedStrings().addString( new Locale( "es" ), "hola" ); + + // step4 we merge the definition + session = openSession(); + session.beginTransaction(); + session.merge( definition ); + session.getTransaction().commit(); + session.close(); + + // step5, final test + session = openSession(); + session.beginTransaction(); + definition = ( Definition ) session.get( Definition.class, definition.getId() ); + assertEquals( 2, definition.getValues().size() ); + Iterator values = definition.getValues().iterator(); + while ( values.hasNext() ) { + assertEquals( 1, ( ( Value ) values.next() ).getLocalizedStrings().getStringsCopy().size() ); + } + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/component/cascading/collection/Definition.java b/test/org/hibernate/test/component/cascading/collection/Definition.java new file mode 100644 index 0000000000..05bf4e6e45 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/collection/Definition.java @@ -0,0 +1,30 @@ +package org.hibernate.test.component.cascading.collection; + +import java.util.Set; +import java.util.HashSet; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Definition { + private Long id; + private Set values = new HashSet(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Set getValues() { + return values; + } + + public void setValues(Set values) { + this.values = values; + } +} diff --git a/test/org/hibernate/test/component/cascading/collection/LocalizedStrings.java b/test/org/hibernate/test/component/cascading/collection/LocalizedStrings.java new file mode 100644 index 0000000000..ae955b7905 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/collection/LocalizedStrings.java @@ -0,0 +1,26 @@ +package org.hibernate.test.component.cascading.collection; + +import java.util.Locale; +import java.util.Map; +import java.util.HashMap; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class LocalizedStrings { + private Map strings = new HashMap(); + + public void addString(Locale locale, String value) { + strings.put( locale, value ); + } + + public String getString(Locale locale) { + return ( String ) strings.get( locale ); + } + + public Map getStringsCopy() { + return java.util.Collections.unmodifiableMap( strings ); + } +} diff --git a/test/org/hibernate/test/component/cascading/collection/Mappings.hbm.xml b/test/org/hibernate/test/component/cascading/collection/Mappings.hbm.xml new file mode 100644 index 0000000000..079f4738f0 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/collection/Mappings.hbm.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/component/cascading/collection/Value.java b/test/org/hibernate/test/component/cascading/collection/Value.java new file mode 100644 index 0000000000..8f3d5453d9 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/collection/Value.java @@ -0,0 +1,45 @@ +package org.hibernate.test.component.cascading.collection; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Value { + private Long id; + private Definition definition; + private LocalizedStrings localizedStrings = new LocalizedStrings(); + + private Value() { + } + + public Value(Definition definition) { + this(); + this.definition = definition; + definition.getValues().add( this ); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Definition getDefinition() { + return definition; + } + + public void setDefinition(Definition definition) { + this.definition = definition; + } + + public LocalizedStrings getLocalizedStrings() { + return localizedStrings; + } + + public void setLocalizedStrings(LocalizedStrings localizedStrings) { + this.localizedStrings = localizedStrings; + } +} diff --git a/test/org/hibernate/test/component/cascading/toone/Address.java b/test/org/hibernate/test/component/cascading/toone/Address.java new file mode 100644 index 0000000000..c7ac7562ca --- /dev/null +++ b/test/org/hibernate/test/component/cascading/toone/Address.java @@ -0,0 +1,63 @@ +package org.hibernate.test.component.cascading.toone; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Address { + private Long id; + private String street1; + private String street2; + private String city; + private String state; + private String zipCode; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getStreet1() { + return street1; + } + + public void setStreet1(String street1) { + this.street1 = street1; + } + + public String getStreet2() { + return street2; + } + + public void setStreet2(String street2) { + this.street2 = street2; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getZipCode() { + return zipCode; + } + + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } +} diff --git a/test/org/hibernate/test/component/cascading/toone/CascadeToComponentAssociationTest.java b/test/org/hibernate/test/component/cascading/toone/CascadeToComponentAssociationTest.java new file mode 100644 index 0000000000..8c1bccf253 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/toone/CascadeToComponentAssociationTest.java @@ -0,0 +1,71 @@ +package org.hibernate.test.component.cascading.toone; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class CascadeToComponentAssociationTest extends FunctionalTestCase { + public CascadeToComponentAssociationTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "component/cascading/toone/Mappings.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CascadeToComponentAssociationTest.class ); + } + + public void testMerging() { + // step1, we create a document with owner + Session session = openSession(); + session.beginTransaction(); + User user = new User(); + Document document = new Document(); + document.setOwner( user ); + session.persist( document ); + session.getTransaction().commit(); + session.close(); + + // step2, we verify that the document has owner and that owner has no personal-info; then we detach + session = openSession(); + session.beginTransaction(); + document = ( Document ) session.get( Document.class, document.getId() ); + assertNotNull( document.getOwner() ); + assertNull( document.getOwner().getPersonalInfo() ); + session.getTransaction().commit(); + session.close(); + + // step3, try to specify the personal-info during detachment + Address addr = new Address(); + addr.setStreet1( "123 6th St" ); + addr.setCity( "Austin" ); + addr.setState( "TX" ); + document.getOwner().setPersonalInfo( new PersonalInfo( addr ) ); + + // step4 we merge the document + session = openSession(); + session.beginTransaction(); + session.merge( document ); + session.getTransaction().commit(); + session.close(); + + // step5, final test + session = openSession(); + session.beginTransaction(); + document = ( Document ) session.get( Document.class, document.getId() ); + assertNotNull( document.getOwner() ); + assertNotNull( document.getOwner().getPersonalInfo() ); + assertNotNull( document.getOwner().getPersonalInfo().getHomeAddress() ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/component/cascading/toone/Document.java b/test/org/hibernate/test/component/cascading/toone/Document.java new file mode 100644 index 0000000000..b53414a187 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/toone/Document.java @@ -0,0 +1,36 @@ +package org.hibernate.test.component.cascading.toone; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Document { + private Long id; + private String location; + private User owner; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public User getOwner() { + return owner; + } + + public void setOwner(User owner) { + this.owner = owner; + } +} diff --git a/test/org/hibernate/test/component/cascading/toone/Mappings.hbm.xml b/test/org/hibernate/test/component/cascading/toone/Mappings.hbm.xml new file mode 100644 index 0000000000..34980363f5 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/toone/Mappings.hbm.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/component/cascading/toone/PersonalInfo.java b/test/org/hibernate/test/component/cascading/toone/PersonalInfo.java new file mode 100644 index 0000000000..af1f001eb5 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/toone/PersonalInfo.java @@ -0,0 +1,25 @@ +package org.hibernate.test.component.cascading.toone; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class PersonalInfo { + private Address homeAddress = new Address(); + + public PersonalInfo() { + } + + public PersonalInfo(Address homeAddress) { + this.homeAddress = homeAddress; + } + + public Address getHomeAddress() { + return homeAddress; + } + + public void setHomeAddress(Address homeAddress) { + this.homeAddress = homeAddress; + } +} diff --git a/test/org/hibernate/test/component/cascading/toone/User.java b/test/org/hibernate/test/component/cascading/toone/User.java new file mode 100644 index 0000000000..07a5a3bca2 --- /dev/null +++ b/test/org/hibernate/test/component/cascading/toone/User.java @@ -0,0 +1,27 @@ +package org.hibernate.test.component.cascading.toone; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class User { + private Long id; + private PersonalInfo personalInfo; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public PersonalInfo getPersonalInfo() { + return personalInfo; + } + + public void setPersonalInfo(PersonalInfo personalInfo) { + this.personalInfo = personalInfo; + } +} diff --git a/test/org/hibernate/test/compositeelement/Child.java b/test/org/hibernate/test/compositeelement/Child.java new file mode 100755 index 0000000000..7a995b07db --- /dev/null +++ b/test/org/hibernate/test/compositeelement/Child.java @@ -0,0 +1,60 @@ +//$Id$ +package org.hibernate.test.compositeelement; + +/** + * @author gavin + */ +public class Child { + private String name; + private String bio; + private Parent parent; + private int bioLength; + Child() {} + public Child(String name) { + this.name = name; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + /** + * @return Returns the parent. + */ + public Parent getParent() { + return parent; + } + /** + * @param parent The parent to set. + */ + public void setParent(Parent parent) { + this.parent = parent; + } + public String getBio() { + return bio; + } + public void setBio(String bio) { + this.bio = bio; + } + public int hashCode() { + return name.hashCode(); + } + public boolean equals(Object other) { + Child c = (Child) other; + return c.parent.getId().equals(parent.getId()) + && c.name.equals(name); + } + public int getBioLength() { + return bioLength; + } + public void setBioLength(Integer bioLength) { + this.bioLength = bioLength==null ? 0 : bioLength.intValue(); + } +} diff --git a/test/org/hibernate/test/compositeelement/CompositeElementTest.java b/test/org/hibernate/test/compositeelement/CompositeElementTest.java new file mode 100755 index 0000000000..1e0062b86b --- /dev/null +++ b/test/org/hibernate/test/compositeelement/CompositeElementTest.java @@ -0,0 +1,90 @@ +//$Id$ +package org.hibernate.test.compositeelement; + +import java.util.ArrayList; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Mappings; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.mapping.Collection; +import org.hibernate.mapping.Component; +import org.hibernate.mapping.Formula; + +/** + * @author Gavin King + */ +public class CompositeElementTest extends FunctionalTestCase { + + public CompositeElementTest(String str) { + super( str ); + } + + public String[] getMappings() { + return new String[] { "compositeelement/Parent.hbm.xml" }; + } + + public void afterConfigurationBuilt(Mappings mappings, Dialect dialect) { + super.afterConfigurationBuilt( mappings, dialect ); + Collection children = mappings.getCollection( Parent.class.getName() + ".children" ); + Component childComponents = ( Component ) children.getElement(); + Formula f = ( Formula ) childComponents.getProperty( "bioLength" ).getValue().getColumnIterator().next(); + + SQLFunction lengthFunction = ( SQLFunction ) dialect.getFunctions().get( "length" ); + if ( lengthFunction != null ) { + ArrayList args = new ArrayList(); + args.add( "bio" ); + f.setFormula( lengthFunction.render( args, null ) ); + } + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CompositeElementTest.class ); + } + + public void testHandSQL() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Child c = new Child( "Child One" ); + Parent p = new Parent( "Parent" ); + p.getChildren().add( c ); + c.setParent( p ); + s.save( p ); + s.flush(); + + p.getChildren().remove( c ); + c.setParent( null ); + s.flush(); + + p.getChildren().add( c ); + c.setParent( p ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery( "select distinct p from Parent p join p.children c where c.name like 'Child%'" ).uniqueResult(); + s.clear(); + s.createQuery( "select new Child(c.name) from Parent p left outer join p.children c where c.name like 'Child%'" ) + .uniqueResult(); + s.clear(); + //s.createQuery("select c from Parent p left outer join p.children c where c.name like 'Child%'").uniqueResult(); //we really need to be able to do this! + s.clear(); + p = ( Parent ) s.createQuery( "from Parent p left join fetch p.children" ).uniqueResult(); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete( p ); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/compositeelement/Parent.hbm.xml b/test/org/hibernate/test/compositeelement/Parent.hbm.xml new file mode 100755 index 0000000000..4dad51c247 --- /dev/null +++ b/test/org/hibernate/test/compositeelement/Parent.hbm.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/compositeelement/Parent.java b/test/org/hibernate/test/compositeelement/Parent.java new file mode 100755 index 0000000000..653484e97a --- /dev/null +++ b/test/org/hibernate/test/compositeelement/Parent.java @@ -0,0 +1,54 @@ +//$Id$ +package org.hibernate.test.compositeelement; + +import java.util.Collection; +import java.util.HashSet; + +/** + * @author gavin + */ +public class Parent { + private Long id; + private String name; + private Collection children = new HashSet(); + Parent() {} + public Parent(String name) { + this.name = name; + } + /** + * @return Returns the children. + */ + public Collection getChildren() { + return children; + } + /** + * @param children The children to set. + */ + public void setChildren(Collection children) { + this.children = children; + } + /** + * @return Returns the id. + */ + public Long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Long id) { + this.id = id; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/connections/AggressiveReleaseTest.java b/test/org/hibernate/test/connections/AggressiveReleaseTest.java new file mode 100644 index 0000000000..f303214ed6 --- /dev/null +++ b/test/org/hibernate/test/connections/AggressiveReleaseTest.java @@ -0,0 +1,249 @@ +// $Id$ +package org.hibernate.test.connections; + +import java.sql.Connection; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.ConnectionReleaseMode; +import org.hibernate.Hibernate; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.impl.SessionImpl; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.tm.DummyConnectionProvider; +import org.hibernate.test.tm.DummyTransactionManager; +import org.hibernate.test.tm.DummyTransactionManagerLookup; +import org.hibernate.transaction.CMTTransactionFactory; +import org.hibernate.util.SerializationHelper; + +/** + * Implementation of AggressiveReleaseTest. + * + * @author Steve Ebersole + */ +public class AggressiveReleaseTest extends ConnectionManagementTestCase { + + public AggressiveReleaseTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( AggressiveReleaseTest.class ); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.AFTER_STATEMENT.toString() ); + cfg.setProperty( Environment.CONNECTION_PROVIDER, DummyConnectionProvider.class.getName() ); + cfg.setProperty( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class.getName() ); + cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, DummyTransactionManagerLookup.class.getName() ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" ); + } + + protected Session getSessionUnderTest() throws Throwable { + return openSession(); + } + + protected void reconnect(Session session) { + session.reconnect(); + } + + protected void prepare() throws Throwable { + DummyTransactionManager.INSTANCE.begin(); + } + + protected void done() throws Throwable { + DummyTransactionManager.INSTANCE.commit(); + } + + // Some additional tests specifically for the aggressive-release functionality... + + public void testSerializationOnAfterStatementAggressiveRelease() throws Throwable { + prepare(); + Session s = getSessionUnderTest(); + Silly silly = new Silly( "silly" ); + s.save( silly ); + + // this should cause the CM to obtain a connection, and then release it + s.flush(); + + // We should be able to serialize the session at this point... + SerializationHelper.serialize( s ); + + s.delete( silly ); + s.flush(); + + release( s ); + done(); + } + + public void testSerializationFailsOnAfterStatementAggressiveReleaseWithOpenResources() throws Throwable { + prepare(); + Session s = getSessionUnderTest(); + + Silly silly = new Silly( "silly" ); + s.save( silly ); + + // this should cause the CM to obtain a connection, and then release it + s.flush(); + + // both scroll() and iterate() cause the batcher to hold on + // to resources, which should make aggresive-release not release + // the connection (and thus cause serialization to fail) + ScrollableResults sr = s.createQuery( "from Silly" ).scroll(); + + try { + SerializationHelper.serialize( s ); + fail( "Serialization allowed on connected session; or aggressive release released connection with open resources" ); + } + catch( IllegalStateException e ) { + // expected behavior + } + + // Closing the ScrollableResults does currently force the batcher to + // aggressively release the connection + sr.close(); + SerializationHelper.serialize( s ); + + s.delete( silly ); + s.flush(); + + release( s ); + done(); + } + + public void testQueryIteration() throws Throwable { + prepare(); + Session s = getSessionUnderTest(); + Silly silly = new Silly( "silly" ); + s.save( silly ); + s.flush(); + + Iterator itr = s.createQuery( "from Silly" ).iterate(); + assertTrue( itr.hasNext() ); + Silly silly2 = ( Silly ) itr.next(); + assertEquals( silly, silly2 ); + Hibernate.close( itr ); + + itr = s.createQuery( "from Silly" ).iterate(); + Iterator itr2 = s.createQuery( "from Silly where name = 'silly'" ).iterate(); + + assertTrue( itr.hasNext() ); + assertEquals( silly, itr.next() ); + assertTrue( itr2.hasNext() ); + assertEquals( silly, itr2.next() ); + + Hibernate.close( itr ); + Hibernate.close( itr2 ); + + s.delete( silly ); + s.flush(); + + release( s ); + done(); + } + + public void testQueryScrolling() throws Throwable { + prepare(); + Session s = getSessionUnderTest(); + Silly silly = new Silly( "silly" ); + s.save( silly ); + s.flush(); + + ScrollableResults sr = s.createQuery( "from Silly" ).scroll(); + assertTrue( sr.next() ); + Silly silly2 = ( Silly ) sr.get( 0 ); + assertEquals( silly, silly2 ); + sr.close(); + + sr = s.createQuery( "from Silly" ).scroll(); + ScrollableResults sr2 = s.createQuery( "from Silly where name = 'silly'" ).scroll(); + + assertTrue( sr.next() ); + assertEquals( silly, sr.get( 0 ) ); + assertTrue( sr2.next() ); + assertEquals( silly, sr2.get( 0 ) ); + + sr.close(); + sr2.close(); + + s.delete( silly ); + s.flush(); + + release( s ); + done(); + } + + public void testSuppliedConnection() throws Throwable { + prepare(); + + Connection originalConnection = DummyTransactionManager.INSTANCE.getCurrent().getConnection(); + Session session = getSessions().openSession( originalConnection ); + + Silly silly = new Silly( "silly" ); + session.save( silly ); + + // this will cause the connection manager to cycle through the aggressive release logic; + // it should not release the connection since we explicitly suplied it ourselves. + session.flush(); + + assertTrue( "Different connections", originalConnection == session.connection() ); + + session.delete( silly ); + session.flush(); + + release( session ); + done(); + } + + public void testBorrowedConnections() throws Throwable { + prepare(); + Session s = getSessionUnderTest(); + + Connection conn = s.connection(); + assertTrue( ( ( SessionImpl ) s ).getJDBCContext().getConnectionManager().hasBorrowedConnection() ); + conn.close(); + assertFalse( ( ( SessionImpl ) s ).getJDBCContext().getConnectionManager().hasBorrowedConnection() ); + + release( s ); + done(); + } + + public void testConnectionMaintanenceDuringFlush() throws Throwable { + prepare(); + Session s = getSessionUnderTest(); + s.beginTransaction(); + + List entities = new ArrayList(); + for ( int i = 0; i < 10; i++ ) { + Other other = new Other( "other-" + i ); + Silly silly = new Silly( "silly-" + i, other ); + entities.add( silly ); + s.save( silly ); + } + s.flush(); + + Iterator itr = entities.iterator(); + while ( itr.hasNext() ) { + Silly silly = ( Silly ) itr.next(); + silly.setName( "new-" + silly.getName() ); + silly.getOther().setName( "new-" + silly.getOther().getName() ); + } + long initialCount = getSessions().getStatistics().getConnectCount(); + s.flush(); + assertEquals( "connection not maintained through flush", initialCount + 1, getSessions().getStatistics().getConnectCount() ); + + s.createQuery( "delete from Silly" ).executeUpdate(); + s.createQuery( "delete from Other" ).executeUpdate(); + s.getTransaction().commit(); + release( s ); + done(); + } +} diff --git a/test/org/hibernate/test/connections/BasicConnectionProviderTest.java b/test/org/hibernate/test/connections/BasicConnectionProviderTest.java new file mode 100644 index 0000000000..28151692fa --- /dev/null +++ b/test/org/hibernate/test/connections/BasicConnectionProviderTest.java @@ -0,0 +1,39 @@ +// $Id$ +package org.hibernate.test.connections; + +import junit.framework.Test; + +import org.hibernate.ConnectionReleaseMode; +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Implementation of BasicConnectionProviderTest. + * + * @author Steve Ebersole + */ +public class BasicConnectionProviderTest extends ConnectionManagementTestCase { + + public BasicConnectionProviderTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BasicConnectionProviderTest.class ); + } + + protected Session getSessionUnderTest() { + return openSession(); + } + + protected void reconnect(Session session) { + session.reconnect(); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString() ); + } +} diff --git a/test/org/hibernate/test/connections/ConnectionManagementTestCase.java b/test/org/hibernate/test/connections/ConnectionManagementTestCase.java new file mode 100644 index 0000000000..775926a18e --- /dev/null +++ b/test/org/hibernate/test/connections/ConnectionManagementTestCase.java @@ -0,0 +1,307 @@ +// $Id$ +package org.hibernate.test.connections; + +import org.hibernate.test.TestCase; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.util.SerializationHelper; + +/** + * Common test cases relating to session management and how the sessions + * manages its underlying jdbc connection across different config + * scenarios. The different config scenarios are controlled by the + * individual test subclasses. + *

+ * In general, all the tests required are defined here in templated fashion. + * Subclassed then override various hook methods specific to their given + * scneario being tested. + * + * @author Steve Ebersole + */ +public abstract class ConnectionManagementTestCase extends FunctionalTestCase { + + public ConnectionManagementTestCase(String name) { + super( name ); + } + + public final String[] getMappings() { + return new String[] { "connections/Silly.hbm.xml" }; + } + + + // hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Used to prepare the environment for testing (e.g., starting a + * JTA transaction or obtaining a user-supplied connection). + * + * @throws Throwable indicates problems preparing + */ + protected void prepare() throws Throwable { + } + + /** + * Used to cleanup the environment after testing (e.g., ending a JTA + * transaction or closing a user-supplied connection). + * + * @throws Throwable indicates problems cleaning up + */ + protected void done() throws Throwable { + } + + /** + * Used to get a session configured based on the config scenario being + * tested. + * + * @return The session to be used in testing. + * @throws Throwable Indicates problems building a test session fixture. + */ + protected abstract Session getSessionUnderTest() throws Throwable; + + /** + * Used to release a {@link #getSessionUnderTest fixture session}. + * Overridden to perform session releasing/testing specific to the given + * config scenario being tested. + * + * @param session The session to be released. + */ + protected void release(Session session) { + if ( session != null && session.isOpen() ) { + try { + session.close(); + } + catch( Throwable ignore ) { + } + } + } + + /** + * Perform any steps needed to reconnect a fixture session. + * + * @param session The fixture session to be reconnected. + * @throws Throwable Indicates problems reconnecting. + */ + protected abstract void reconnect(Session session) throws Throwable; + + /** + * Check the state of a fixture session after serialization, as well + * as validate the environmental state after session serialization. + * + * @param session The fixture session that was serialized. + */ + protected void checkSerializedState(Session session) { + } + + /** + * Check the state of a fixture session after deserialization, as well + * as validate the environmental state after session deserialization. + * + * @param session The fixture session that was deserialized. + */ + protected void checkDeserializedState(Session session) { + } + + + // tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Tests to validate that a session holding JDBC resources will not + * be allowed to serialize. + * + * @throws Throwable + */ + public final void testConnectedSerialization() throws Throwable { + prepare(); + Session sessionUnderTest = getSessionUnderTest(); + + // force the connection to be retained + sessionUnderTest.createQuery( "from Silly" ).scroll(); + + try { + SerializationHelper.serialize( sessionUnderTest ); + + fail( "Serialization of connected session allowed!" ); + } + catch( IllegalStateException e ) { + // expected behaviour + } + finally { + release( sessionUnderTest ); + done(); + } + } + + /** + * Test that a session which has been manually disconnected will be allowed + * to serialize. + * + * @throws Throwable + */ + public final void testManualDisconnectedSerialization() throws Throwable { + prepare(); + Session sessionUnderTest = getSessionUnderTest(); + + sessionUnderTest.disconnect(); + + SerializationHelper.serialize( sessionUnderTest ); + checkSerializedState( sessionUnderTest ); + + release( sessionUnderTest ); + done(); + } + + /** + * Test that the legacy manual disconnect()/reconnect() chain works as + * expected in the given environment. + * + * @throws Throwable + */ + public final void testManualDisconnectChain() throws Throwable { + prepare(); + Session sessionUnderTest = getSessionUnderTest(); + + sessionUnderTest.disconnect(); + + byte[] bytes = SerializationHelper.serialize( sessionUnderTest ); + checkSerializedState( sessionUnderTest ); + Session s2 = ( Session ) SerializationHelper.deserialize( bytes ); + checkDeserializedState( s2 ); + + reconnect( s2 ); + + s2.disconnect(); + reconnect( s2 ); + + release( sessionUnderTest ); + release( s2 ); + done(); + } + + /** + * Test that the legacy manual disconnect()/reconnect() chain works as + * expected in the given environment. Similiar to {@link #testManualDisconnectChain} + * expect that here we force the session to acquire and hold JDBC resources + * prior to disconnecting. + * + * @throws Throwable + */ + public final void testManualDisconnectWithOpenResources() throws Throwable { + prepare(); + Session sessionUnderTest = getSessionUnderTest(); + + Silly silly = new Silly( "tester" ); + sessionUnderTest.save( silly ); + sessionUnderTest.flush(); + + sessionUnderTest.createQuery( "from Silly" ).iterate(); + + sessionUnderTest.disconnect(); + SerializationHelper.serialize( sessionUnderTest ); + checkSerializedState( sessionUnderTest ); + + reconnect( sessionUnderTest ); + sessionUnderTest.createQuery( "from Silly" ).scroll(); + + sessionUnderTest.disconnect(); + SerializationHelper.serialize( sessionUnderTest ); + checkSerializedState( sessionUnderTest ); + + reconnect( sessionUnderTest ); + sessionUnderTest.delete( silly ); + sessionUnderTest.flush(); + + release( sessionUnderTest ); + done(); + } + + /** + * Test that the basic session usage template works in all environment + * scenarios. + * + * @throws Throwable + */ + public void testBasicSessionUsage() throws Throwable { + prepare(); + Session s = null; + Transaction txn = null; + try { + s = getSessionUnderTest(); + txn = s.beginTransaction(); + s.createQuery( "from Silly" ).list(); + txn.commit(); + } + catch( Throwable t ) { + if ( txn != null ) { + try { + txn.rollback(); + } + catch( Throwable ignore ) { + } + } + } + finally { + if ( s != null && s.isOpen() ) { + try { + s.close(); + } + catch( Throwable ignore ) { + } + } + } + done(); + } + + /** + * Test that session-closed protections work properly in all environments. + * + * @throws Throwable + */ + public void testSessionClosedProtections() throws Throwable { + prepare(); + Session s = getSessionUnderTest(); + release( s ); + done(); + assertFalse( s.isOpen() ); + assertFalse( s.isConnected() ); + assertNotNull( s.getStatistics() ); + assertNotNull( s.toString() ); + + try { + s.createQuery( "from Silly" ).list(); + fail( "allowed to create query on closed session" ); + } + catch( Throwable ignore ) { + } + + try { + s.getTransaction(); + fail( "allowed to access transaction on closed session" ); + } + catch( Throwable ignore ) { + } + + try { + s.connection(); + fail( "allowed to access connection on closed session" ); + } + catch( Throwable ignore ) { + } + + try { + s.close(); + fail( "allowed to close already closed session" ); + } + catch( Throwable ignore ) { + } + + try { + s.isDirty(); + fail( "allowed to check dirtiness of closed session" ); + } + catch( Throwable ignore ) { + } + } +} diff --git a/test/org/hibernate/test/connections/ConnectionsSuite.java b/test/org/hibernate/test/connections/ConnectionsSuite.java new file mode 100644 index 0000000000..cc502f0f4e --- /dev/null +++ b/test/org/hibernate/test/connections/ConnectionsSuite.java @@ -0,0 +1,23 @@ +// $Id$ +package org.hibernate.test.connections; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Implementation of ConnectionsSuite. + * + * @author Steve Ebersole + */ +public class ConnectionsSuite { + + public static Test suite() { + TestSuite suite = new TestSuite( "Connection-management tests"); + suite.addTest( AggressiveReleaseTest.suite() ); + suite.addTest( BasicConnectionProviderTest.suite() ); + suite.addTest( CurrentSessionConnectionTest.suite() ); + suite.addTest( SuppliedConnectionTest.suite() ); + suite.addTest( ThreadLocalCurrentSessionTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/connections/CurrentSessionConnectionTest.java b/test/org/hibernate/test/connections/CurrentSessionConnectionTest.java new file mode 100644 index 0000000000..5eafde34ae --- /dev/null +++ b/test/org/hibernate/test/connections/CurrentSessionConnectionTest.java @@ -0,0 +1,31 @@ +// $Id$ +package org.hibernate.test.connections; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Implementation of CurrentSessionConnectionTest. + * + * @author Steve Ebersole + */ +public class CurrentSessionConnectionTest extends AggressiveReleaseTest { + + public CurrentSessionConnectionTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CurrentSessionConnectionTest.class ); + } + + protected Session getSessionUnderTest() throws Throwable { + return getSessions().getCurrentSession(); + } + + protected void release(Session session) { + // do nothing, txn synch should release session as part of current-session definition + } +} diff --git a/test/org/hibernate/test/connections/Other.java b/test/org/hibernate/test/connections/Other.java new file mode 100644 index 0000000000..212cdcce0f --- /dev/null +++ b/test/org/hibernate/test/connections/Other.java @@ -0,0 +1,32 @@ +package org.hibernate.test.connections; + +/** + * @author Steve Ebersole + */ +public class Other { + private Long id; + private String name; + + public Other() { + } + + public Other(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/connections/Silly.hbm.xml b/test/org/hibernate/test/connections/Silly.hbm.xml new file mode 100644 index 0000000000..0c0a5f22db --- /dev/null +++ b/test/org/hibernate/test/connections/Silly.hbm.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/connections/Silly.java b/test/org/hibernate/test/connections/Silly.java new file mode 100644 index 0000000000..f5974cad26 --- /dev/null +++ b/test/org/hibernate/test/connections/Silly.java @@ -0,0 +1,51 @@ +// $Id$ +package org.hibernate.test.connections; + +import java.io.Serializable; + +/** + * Implementation of Silly. + * + * @author Steve Ebersole + */ +public class Silly implements Serializable { + private Long id; + private String name; + private Other other; + + public Silly() { + } + + public Silly(String name) { + this.name = name; + } + + public Silly(String name, Other other) { + this.name = name; + this.other = other; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Other getOther() { + return other; + } + + public void setOther(Other other) { + this.other = other; + } +} diff --git a/test/org/hibernate/test/connections/SuppliedConnectionTest.java b/test/org/hibernate/test/connections/SuppliedConnectionTest.java new file mode 100644 index 0000000000..306e92f552 --- /dev/null +++ b/test/org/hibernate/test/connections/SuppliedConnectionTest.java @@ -0,0 +1,121 @@ +// $Id$ +package org.hibernate.test.connections; + +import java.sql.Connection; +import java.sql.ResultSet; + +import junit.framework.Test; + +import org.hibernate.ConnectionReleaseMode; +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.connection.ConnectionProvider; +import org.hibernate.connection.ConnectionProviderFactory; +import org.hibernate.connection.UserSuppliedConnectionProvider; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.tool.hbm2ddl.SchemaExport; + +/** + * Implementation of SuppliedConnectionTest. + * + * @author Steve Ebersole + */ +public class SuppliedConnectionTest extends ConnectionManagementTestCase { + + private ConnectionProvider cp = ConnectionProviderFactory.newConnectionProvider(); + private Connection connectionUnderTest; + + public SuppliedConnectionTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( SuppliedConnectionTest.class ); + } + + protected Session getSessionUnderTest() throws Throwable { + connectionUnderTest = cp.getConnection(); + return getSessions().openSession( connectionUnderTest ); + } + + protected void reconnect(Session session) { + session.reconnect( connectionUnderTest ); + } + + protected void done() throws Throwable { + cp.closeConnection( connectionUnderTest ); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString() ); + cfg.setProperty( Environment.CONNECTION_PROVIDER, UserSuppliedConnectionProvider.class.getName() ); + boolean supportsScroll = true; + Connection conn = null; + try { + conn = cp.getConnection(); + supportsScroll = conn.getMetaData().supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE); + } + catch( Throwable ignore ) { + } + finally { + if ( conn != null ) { + try { + conn.close(); + } + catch( Throwable ignore ) { + // ignore it... + } + } + } + cfg.setProperty( Environment.USE_SCROLLABLE_RESULTSET, "" + supportsScroll ); + } + + public boolean createSchema() { + return false; + } + + public boolean recreateSchemaAfterFailure() { + return false; + } + + protected void prepareTest() throws Exception { + super.prepareTest(); + Connection conn = cp.getConnection(); + try { + new SchemaExport( getCfg(), conn ).create( false, true ); + } + finally { + if ( conn != null ) { + try { + cp.closeConnection( conn ); + } + catch( Throwable ignore ) { + } + } + } + } + + protected void cleanupTest() throws Exception { + Connection conn = cp.getConnection(); + try { + new SchemaExport( getCfg(), conn ).drop( false, true ); + } + finally { + if ( conn != null ) { + try { + cp.closeConnection( conn ); + } + catch( Throwable ignore ) { + } + } + } + try { + cp.close(); + } + catch( Throwable ignore ) { + } + super.cleanupTest(); + } +} diff --git a/test/org/hibernate/test/connections/ThreadLocalCurrentSessionTest.java b/test/org/hibernate/test/connections/ThreadLocalCurrentSessionTest.java new file mode 100644 index 0000000000..1422a90274 --- /dev/null +++ b/test/org/hibernate/test/connections/ThreadLocalCurrentSessionTest.java @@ -0,0 +1,102 @@ +package org.hibernate.test.connections; + +import junit.framework.Test; + +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.context.ThreadLocalSessionContext; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Steve Ebersole + */ +public class ThreadLocalCurrentSessionTest extends ConnectionManagementTestCase { + + public ThreadLocalCurrentSessionTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ThreadLocalCurrentSessionTest.class ); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS, TestableThreadLocalContext.class.getName() ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + } + + protected Session getSessionUnderTest() throws Throwable { + Session session = getSessions().getCurrentSession(); + session.beginTransaction(); + return session; + } + + protected void release(Session session) { + long initialCount = getSessions().getStatistics().getSessionCloseCount(); + session.getTransaction().commit(); + long subsequentCount = getSessions().getStatistics().getSessionCloseCount(); + assertEquals( "Session still open after commit", initialCount + 1, subsequentCount ); + // also make sure it was cleaned up from the internal ThreadLocal... + assertFalse( "session still bound to internal ThreadLocal", TestableThreadLocalContext.hasBind() ); + } + + protected void reconnect(Session session) throws Throwable { +// session.reconnect(); + session.beginTransaction(); + } + + protected void checkSerializedState(Session session) { + assertFalse( "session still bound after serialize", TestableThreadLocalContext.isSessionBound( session ) ); + } + + protected void checkDeserializedState(Session session) { + assertTrue( "session not bound after deserialize", TestableThreadLocalContext.isSessionBound( session ) ); + } + + public void testTransactionProtection() { + Session session = getSessions().getCurrentSession(); + try { + session.createQuery( "from Silly" ); + fail( "method other than beginTransaction{} allowed" ); + } + catch ( HibernateException e ) { + // ok + } + } + + public void testContextCleanup() { + Session session = getSessions().getCurrentSession(); + session.beginTransaction(); + session.getTransaction().commit(); + assertFalse( "session open after txn completion", session.isOpen() ); + assertFalse( "session still bound after txn completion", TestableThreadLocalContext.isSessionBound( session ) ); + + Session session2 = getSessions().getCurrentSession(); + assertFalse( "same session returned after txn completion", session == session2 ); + session2.close(); + assertFalse( "session open after closing", session2.isOpen() ); + assertFalse( "session still bound after closing", TestableThreadLocalContext.isSessionBound( session2 ) ); + } + + public static class TestableThreadLocalContext extends ThreadLocalSessionContext { + private static TestableThreadLocalContext me; + + public TestableThreadLocalContext(SessionFactoryImplementor factory) { + super( factory ); + me = this; + } + + public static boolean isSessionBound(Session session) { + return sessionMap() != null && sessionMap().containsKey( me.factory ) + && sessionMap().get( me.factory ) == session; + } + + public static boolean hasBind() { + return sessionMap() != null && sessionMap().containsKey( me.factory ); + } + } +} diff --git a/test/org/hibernate/test/criteria/Course.java b/test/org/hibernate/test/criteria/Course.java new file mode 100755 index 0000000000..fc4fd37460 --- /dev/null +++ b/test/org/hibernate/test/criteria/Course.java @@ -0,0 +1,22 @@ +//$Id$ +package org.hibernate.test.criteria; + +/** + * @author Gavin King + */ +public class Course { + private String courseCode; + private String description; + public String getCourseCode() { + return courseCode; + } + public void setCourseCode(String courseCode) { + this.courseCode = courseCode; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } +} diff --git a/test/org/hibernate/test/criteria/CriteriaQueryTest.java b/test/org/hibernate/test/criteria/CriteriaQueryTest.java new file mode 100755 index 0000000000..ff6ba4fd01 --- /dev/null +++ b/test/org/hibernate/test/criteria/CriteriaQueryTest.java @@ -0,0 +1,800 @@ +//$Id$ +package org.hibernate.test.criteria; + +import java.util.List; +import java.util.Map; + +import junit.framework.Test; + +import org.hibernate.Criteria; +import org.hibernate.FetchMode; +import org.hibernate.Hibernate; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.criterion.DetachedCriteria; +import org.hibernate.criterion.Example; +import org.hibernate.criterion.Expression; +import org.hibernate.criterion.MatchMode; +import org.hibernate.criterion.Order; +import org.hibernate.criterion.Projection; +import org.hibernate.criterion.Projections; +import org.hibernate.criterion.Property; +import org.hibernate.criterion.Restrictions; +import org.hibernate.criterion.Subqueries; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.hql.Animal; +import org.hibernate.test.hql.Reptile; +import org.hibernate.transform.Transformers; +import org.hibernate.type.Type; +import org.hibernate.util.SerializationHelper; + +/** + * @author Gavin King + */ +public class CriteriaQueryTest extends FunctionalTestCase { + + public CriteriaQueryTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "criteria/Enrolment.hbm.xml", "hql/Animal.hbm.xml" }; + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.USE_QUERY_CACHE, "true" ); + cfg.setProperty( Environment.CACHE_REGION_PREFIX, "criteriaquerytest" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CriteriaQueryTest.class ); + } + + public void testEscapeCharacter() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Course c1 = new Course(); + c1.setCourseCode( "course-1" ); + c1.setDescription( "%1" ); + Course c2 = new Course(); + c2.setCourseCode( "course-2" ); + c2.setDescription( "%2" ); + Course c3 = new Course(); + c3.setCourseCode( "course-3" ); + c3.setDescription( "control" ); + session.persist( c1 ); + session.persist( c2 ); + session.persist( c3 ); + session.flush(); + session.clear(); + + // finds all courses which have a description equal to '%1' + Course example = new Course(); + example.setDescription( "&%1" ); + List result = session.createCriteria( Course.class ) + .add( Example.create( example ).ignoreCase().enableLike().setEscapeCharacter( new Character( '&' ) ) ) + .list(); + assertEquals( 1, result.size() ); + // finds all courses which contain '%' as the first char in the description + example.setDescription( "&%%" ); + result = session.createCriteria( Course.class ) + .add( Example.create( example ).ignoreCase().enableLike().setEscapeCharacter( new Character( '&' ) ) ) + .list(); + assertEquals( 2, result.size() ); + + session.createQuery( "delete Course" ).executeUpdate(); + t.commit(); + session.close(); + } + + public void testScrollCriteria() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + + Course course = new Course(); + course.setCourseCode("HIB"); + course.setDescription("Hibernate Training"); + session.persist(course); + session.flush(); + session.clear(); + ScrollableResults sr = session.createCriteria(Course.class).scroll(); + assertTrue( sr.next() ); + course = (Course) sr.get(0); + assertNotNull(course); + sr.close(); + session.delete(course); + + t.commit(); + session.close(); + + } + + public void testSubselect() { + + Session session = openSession(); + Transaction t = session.beginTransaction(); + + Course course = new Course(); + course.setCourseCode("HIB"); + course.setDescription("Hibernate Training"); + session.persist(course); + + Student gavin = new Student(); + gavin.setName("Gavin King"); + gavin.setStudentNumber(232); + session.persist(gavin); + + Enrolment enrolment2 = new Enrolment(); + enrolment2.setCourse(course); + enrolment2.setCourseCode(course.getCourseCode()); + enrolment2.setSemester((short) 3); + enrolment2.setYear((short) 1998); + enrolment2.setStudent(gavin); + enrolment2.setStudentNumber(gavin.getStudentNumber()); + gavin.getEnrolments().add(enrolment2); + session.persist(enrolment2); + + DetachedCriteria dc = DetachedCriteria.forClass(Student.class) + .add( Property.forName("studentNumber").eq( new Long(232) ) ) + .setProjection( Property.forName("name") ); + + session.createCriteria(Student.class) + .add( Subqueries.propertyEqAll("name", dc) ) + .list(); + + session.createCriteria(Student.class) + .add( Subqueries.exists(dc) ) + .list(); + + session.createCriteria(Student.class) + .add( Property.forName("name").eqAll(dc) ) + .list(); + + session.createCriteria(Student.class) + .add( Subqueries.in("Gavin King", dc) ) + .list(); + + DetachedCriteria dc2 = DetachedCriteria.forClass(Student.class, "st") + .add( Property.forName("st.studentNumber").eqProperty("e.studentNumber") ) + .setProjection( Property.forName("name") ); + + session.createCriteria(Enrolment.class, "e") + .add( Subqueries.eq("Gavin King", dc2) ) + .list(); + + //TODO: join in subselect: HHH-952 + /*DetachedCriteria dc3 = DetachedCriteria.forClass(Student.class, "st") + .createCriteria("enrolments") + .createCriteria("course") + .add( Property.forName("description").eq("Hibernate Training") ) + .setProjection( Property.forName("st.name") ); + + session.createCriteria(Enrolment.class, "e") + .add( Subqueries.eq("Gavin King", dc3) ) + .list();*/ + + session.delete(enrolment2); + session.delete(gavin); + session.delete(course); + t.commit(); + session.close(); + + } + + public void testDetachedCriteria() { + + DetachedCriteria dc = DetachedCriteria.forClass(Student.class) + .add( Property.forName("name").eq("Gavin King") ) + .addOrder( Order.asc("studentNumber") ) + .setProjection( Property.forName("studentNumber") ); + + byte[] bytes = SerializationHelper.serialize(dc); + + dc = (DetachedCriteria) SerializationHelper.deserialize(bytes); + + Session session = openSession(); + Transaction t = session.beginTransaction(); + + Student gavin = new Student(); + gavin.setName("Gavin King"); + gavin.setStudentNumber(232); + Student bizarroGavin = new Student(); + bizarroGavin.setName("Gavin King"); + bizarroGavin.setStudentNumber(666); + session.persist(bizarroGavin); + session.persist(gavin); + + List result = dc.getExecutableCriteria(session) + .setMaxResults(3) + .list(); + + assertEquals( result.size(), 2 ); + assertEquals( result.get(0), new Long(232) ); + assertEquals( result.get(1), new Long(666) ); + + session.delete(gavin); + session.delete(bizarroGavin); + t.commit(); + session.close(); + } + + public void testProjectionCache() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Course course = new Course(); + course.setCourseCode("HIB"); + course.setDescription("Hibernate Training"); + s.save(course); + + Student gavin = new Student(); + gavin.setName("Gavin King"); + gavin.setStudentNumber(666); + s.save(gavin); + + Student xam = new Student(); + xam.setName("Max Rydahl Andersen"); + xam.setStudentNumber(101); + s.save(xam); + + Enrolment enrolment1 = new Enrolment(); + enrolment1.setCourse(course); + enrolment1.setCourseCode(course.getCourseCode()); + enrolment1.setSemester((short) 1); + enrolment1.setYear((short) 1999); + enrolment1.setStudent(xam); + enrolment1.setStudentNumber(xam.getStudentNumber()); + xam.getEnrolments().add(enrolment1); + s.save(enrolment1); + + Enrolment enrolment2 = new Enrolment(); + enrolment2.setCourse(course); + enrolment2.setCourseCode(course.getCourseCode()); + enrolment2.setSemester((short) 3); + enrolment2.setYear((short) 1998); + enrolment2.setStudent(gavin); + enrolment2.setStudentNumber(gavin.getStudentNumber()); + gavin.getEnrolments().add(enrolment2); + s.save(enrolment2); + + List list = s.createCriteria(Enrolment.class) + .createAlias("student", "s") + .createAlias("course", "c") + .add( Restrictions.isNotEmpty("s.enrolments") ) + .setProjection( Projections.projectionList() + .add( Projections.property("s.name") ) + .add( Projections.property("c.description") ) + ) + .setCacheable(true) + .list(); + + assertEquals( list.size(), 2 ); + assertEquals( ( (Object[]) list.get(0) ).length, 2 ); + assertEquals( ( (Object[]) list.get(1) ).length, 2 ); + + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + + s.createCriteria(Enrolment.class) + .createAlias("student", "s") + .createAlias("course", "c") + .add( Restrictions.isNotEmpty("s.enrolments") ) + .setProjection( Projections.projectionList() + .add( Projections.property("s.name") ) + .add( Projections.property("c.description") ) + ) + .setCacheable(true) + .list(); + + assertEquals( list.size(), 2 ); + assertEquals( ( (Object[]) list.get(0) ).length, 2 ); + assertEquals( ( (Object[]) list.get(1) ).length, 2 ); + + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + + s.createCriteria(Enrolment.class) + .createAlias("student", "s") + .createAlias("course", "c") + .add( Restrictions.isNotEmpty("s.enrolments") ) + .setProjection( Projections.projectionList() + .add( Projections.property("s.name") ) + .add( Projections.property("c.description") ) + ) + .setCacheable(true) + .list(); + + assertEquals( list.size(), 2 ); + assertEquals( ( (Object[]) list.get(0) ).length, 2 ); + assertEquals( ( (Object[]) list.get(1) ).length, 2 ); + + s.delete(enrolment1); + s.delete(enrolment2); + s.delete(course); + s.delete(gavin); + s.delete(xam); + + t.commit(); + s.close(); + } + + public void testProjections() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Course course = new Course(); + course.setCourseCode("HIB"); + course.setDescription("Hibernate Training"); + s.save(course); + + Student gavin = new Student(); + gavin.setName("Gavin King"); + gavin.setStudentNumber(667); + s.save(gavin); + + Student xam = new Student(); + xam.setName("Max Rydahl Andersen"); + xam.setStudentNumber(101); + s.save(xam); + + Enrolment enrolment = new Enrolment(); + enrolment.setCourse(course); + enrolment.setCourseCode(course.getCourseCode()); + enrolment.setSemester((short) 1); + enrolment.setYear((short) 1999); + enrolment.setStudent(xam); + enrolment.setStudentNumber(xam.getStudentNumber()); + xam.getEnrolments().add(enrolment); + s.save(enrolment); + + enrolment = new Enrolment(); + enrolment.setCourse(course); + enrolment.setCourseCode(course.getCourseCode()); + enrolment.setSemester((short) 3); + enrolment.setYear((short) 1998); + enrolment.setStudent(gavin); + enrolment.setStudentNumber(gavin.getStudentNumber()); + gavin.getEnrolments().add(enrolment); + s.save(enrolment); + + //s.flush(); + + Integer count = (Integer) s.createCriteria(Enrolment.class) + .setProjection( Projections.count("studentNumber").setDistinct() ) + .uniqueResult(); + assertEquals(count, new Integer(2)); + + Object object = s.createCriteria(Enrolment.class) + .setProjection( Projections.projectionList() + .add( Projections.count("studentNumber") ) + .add( Projections.max("studentNumber") ) + .add( Projections.min("studentNumber") ) + .add( Projections.avg("studentNumber") ) + ) + .uniqueResult(); + Object[] result = (Object[])object; + + assertEquals(new Integer(2),result[0]); + assertEquals(new Long(667),result[1]); + assertEquals(new Long(101),result[2]); + assertEquals( 384.0, ( (Double) result[3] ).doubleValue(), 0.01 ); + + + List resultWithMaps = s.createCriteria(Enrolment.class) + .setProjection( Projections.distinct( Projections.projectionList() + .add( Projections.property("studentNumber"), "stNumber" ) + .add( Projections.property("courseCode"), "cCode" ) ) + ) + .add( Expression.gt( "studentNumber", new Long(665) ) ) + .add( Expression.lt( "studentNumber", new Long(668) ) ) + .addOrder( Order.asc("stNumber") ) + .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP) + .list(); + + assertEquals(1, resultWithMaps.size()); + Map m1 = (Map) resultWithMaps.get(0); + + assertEquals(new Long(667), m1.get("stNumber")); + assertEquals(course.getCourseCode(), m1.get("cCode")); + + resultWithMaps = s.createCriteria(Enrolment.class) + .setProjection( Projections.property("studentNumber").as("stNumber") ) + .addOrder( Order.desc("stNumber") ) + .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP) + .list(); + + assertEquals(2, resultWithMaps.size()); + Map m0 = (Map) resultWithMaps.get(0); + m1 = (Map) resultWithMaps.get(1); + + assertEquals(new Long(101), m1.get("stNumber")); + assertEquals(new Long(667), m0.get("stNumber")); + + + List resultWithAliasedBean = s.createCriteria(Enrolment.class) + .createAlias("student", "st") + .createAlias("course", "co") + .setProjection( Projections.projectionList() + .add( Projections.property("st.name"), "studentName" ) + .add( Projections.property("co.description"), "courseDescription" ) + ) + .addOrder( Order.desc("studentName") ) + .setResultTransformer( Transformers.aliasToBean(StudentDTO.class) ) + .list(); + + assertEquals(2, resultWithAliasedBean.size()); + + StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0); + assertNotNull(dto.getDescription()); + assertNotNull(dto.getName()); + + s.createCriteria(Student.class) + .add( Restrictions.like("name", "Gavin", MatchMode.START) ) + .addOrder( Order.asc("name") ) + .createCriteria("enrolments", "e") + .addOrder( Order.desc("year") ) + .addOrder( Order.desc("semester") ) + .createCriteria("course","c") + .addOrder( Order.asc("description") ) + .setProjection( Projections.projectionList() + .add( Projections.property("this.name") ) + .add( Projections.property("e.year") ) + .add( Projections.property("e.semester") ) + .add( Projections.property("c.courseCode") ) + .add( Projections.property("c.description") ) + ) + .uniqueResult(); + + Projection p1 = Projections.projectionList() + .add( Projections.count("studentNumber") ) + .add( Projections.max("studentNumber") ) + .add( Projections.rowCount() ); + + Projection p2 = Projections.projectionList() + .add( Projections.min("studentNumber") ) + .add( Projections.avg("studentNumber") ) + .add( Projections.sqlProjection( + "1 as constOne, count(*) as countStar", + new String[] { "constOne", "countStar" }, + new Type[] { Hibernate.INTEGER, Hibernate.INTEGER } + ) ); + + Object[] array = (Object[]) s.createCriteria(Enrolment.class) + .setProjection( Projections.projectionList().add(p1).add(p2) ) + .uniqueResult(); + + assertEquals( array.length, 7 ); + + List list = s.createCriteria(Enrolment.class) + .createAlias("student", "st") + .createAlias("course", "co") + .setProjection( Projections.projectionList() + .add( Projections.groupProperty("co.courseCode") ) + .add( Projections.count("st.studentNumber").setDistinct() ) + .add( Projections.groupProperty("year") ) + ) + .list(); + + assertEquals( list.size(), 2 ); + + Object g = s.createCriteria(Student.class) + .add( Restrictions.idEq( new Long(667) ) ) + .setFetchMode("enrolments", FetchMode.JOIN) + //.setFetchMode("enrolments.course", FetchMode.JOIN) //TODO: would love to make that work... + .uniqueResult(); + assertSame(g, gavin); + + s.delete(gavin); + s.delete(xam); + s.delete(course); + + t.commit(); + s.close(); + } + + public void testProjectionsUsingProperty() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Course course = new Course(); + course.setCourseCode("HIB"); + course.setDescription("Hibernate Training"); + s.save(course); + + Student gavin = new Student(); + gavin.setName("Gavin King"); + gavin.setStudentNumber(667); + s.save(gavin); + + Student xam = new Student(); + xam.setName("Max Rydahl Andersen"); + xam.setStudentNumber(101); + s.save(xam); + + Enrolment enrolment = new Enrolment(); + enrolment.setCourse(course); + enrolment.setCourseCode(course.getCourseCode()); + enrolment.setSemester((short) 1); + enrolment.setYear((short) 1999); + enrolment.setStudent(xam); + enrolment.setStudentNumber(xam.getStudentNumber()); + xam.getEnrolments().add(enrolment); + s.save(enrolment); + + enrolment = new Enrolment(); + enrolment.setCourse(course); + enrolment.setCourseCode(course.getCourseCode()); + enrolment.setSemester((short) 3); + enrolment.setYear((short) 1998); + enrolment.setStudent(gavin); + enrolment.setStudentNumber(gavin.getStudentNumber()); + gavin.getEnrolments().add(enrolment); + s.save(enrolment); + + s.flush(); + + Integer count = (Integer) s.createCriteria(Enrolment.class) + .setProjection( Property.forName("studentNumber").count().setDistinct() ) + .uniqueResult(); + assertEquals(count, new Integer(2)); + + Object object = s.createCriteria(Enrolment.class) + .setProjection( Projections.projectionList() + .add( Property.forName("studentNumber").count() ) + .add( Property.forName("studentNumber").max() ) + .add( Property.forName("studentNumber").min() ) + .add( Property.forName("studentNumber").avg() ) + ) + .uniqueResult(); + Object[] result = (Object[])object; + + assertEquals(new Integer(2),result[0]); + assertEquals(new Long(667),result[1]); + assertEquals(new Long(101),result[2]); + assertEquals(384.0, ( (Double) result[3] ).doubleValue(), 0.01); + + + s.createCriteria(Enrolment.class) + .add( Property.forName("studentNumber").gt( new Long(665) ) ) + .add( Property.forName("studentNumber").lt( new Long(668) ) ) + .add( Property.forName("courseCode").like("HIB", MatchMode.START) ) + .add( Property.forName("year").eq( new Short( (short) 1999 ) ) ) + .addOrder( Property.forName("studentNumber").asc() ) + .uniqueResult(); + + List resultWithMaps = s.createCriteria(Enrolment.class) + .setProjection( Projections.projectionList() + .add( Property.forName("studentNumber").as("stNumber") ) + .add( Property.forName("courseCode").as("cCode") ) + ) + .add( Property.forName("studentNumber").gt( new Long(665) ) ) + .add( Property.forName("studentNumber").lt( new Long(668) ) ) + .addOrder( Property.forName("studentNumber").asc() ) + .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP) + .list(); + + assertEquals(1, resultWithMaps.size()); + Map m1 = (Map) resultWithMaps.get(0); + + assertEquals(new Long(667), m1.get("stNumber")); + assertEquals(course.getCourseCode(), m1.get("cCode")); + + resultWithMaps = s.createCriteria(Enrolment.class) + .setProjection( Property.forName("studentNumber").as("stNumber") ) + .addOrder( Order.desc("stNumber") ) + .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP) + .list(); + + assertEquals(2, resultWithMaps.size()); + Map m0 = (Map) resultWithMaps.get(0); + m1 = (Map) resultWithMaps.get(1); + + assertEquals(new Long(101), m1.get("stNumber")); + assertEquals(new Long(667), m0.get("stNumber")); + + + List resultWithAliasedBean = s.createCriteria(Enrolment.class) + .createAlias("student", "st") + .createAlias("course", "co") + .setProjection( Projections.projectionList() + .add( Property.forName("st.name").as("studentName") ) + .add( Property.forName("co.description").as("courseDescription") ) + ) + .addOrder( Order.desc("studentName") ) + .setResultTransformer( Transformers.aliasToBean(StudentDTO.class) ) + .list(); + + assertEquals(2, resultWithAliasedBean.size()); + + StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0); + assertNotNull(dto.getDescription()); + assertNotNull(dto.getName()); + + s.createCriteria(Student.class) + .add( Restrictions.like("name", "Gavin", MatchMode.START) ) + .addOrder( Order.asc("name") ) + .createCriteria("enrolments", "e") + .addOrder( Order.desc("year") ) + .addOrder( Order.desc("semester") ) + .createCriteria("course","c") + .addOrder( Order.asc("description") ) + .setProjection( Projections.projectionList() + .add( Property.forName("this.name") ) + .add( Property.forName("e.year") ) + .add( Property.forName("e.semester") ) + .add( Property.forName("c.courseCode") ) + .add( Property.forName("c.description") ) + ) + .uniqueResult(); + + Projection p1 = Projections.projectionList() + .add( Property.forName("studentNumber").count() ) + .add( Property.forName("studentNumber").max() ) + .add( Projections.rowCount() ); + + Projection p2 = Projections.projectionList() + .add( Property.forName("studentNumber").min() ) + .add( Property.forName("studentNumber").avg() ) + .add( Projections.sqlProjection( + "1 as constOne, count(*) as countStar", + new String[] { "constOne", "countStar" }, + new Type[] { Hibernate.INTEGER, Hibernate.INTEGER } + ) ); + + Object[] array = (Object[]) s.createCriteria(Enrolment.class) + .setProjection( Projections.projectionList().add(p1).add(p2) ) + .uniqueResult(); + + assertEquals( array.length, 7 ); + + List list = s.createCriteria(Enrolment.class) + .createAlias("student", "st") + .createAlias("course", "co") + .setProjection( Projections.projectionList() + .add( Property.forName("co.courseCode").group() ) + .add( Property.forName("st.studentNumber").count().setDistinct() ) + .add( Property.forName("year").group() ) + ) + .list(); + + assertEquals( list.size(), 2 ); + + s.delete(gavin); + s.delete(xam); + s.delete(course); + + t.commit(); + s.close(); + } + + public void testRestrictionOnSubclassCollection() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + s.createCriteria( Reptile.class ) + .add( Restrictions.isEmpty( "offspring" ) ) + .list(); + + s.createCriteria( Reptile.class ) + .add( Restrictions.isNotEmpty( "offspring" ) ) + .list(); + + t.rollback(); + s.close(); + } + + public void testClassProperty() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + // HQL: from Animal a where a.mother.class = Reptile + Criteria c = s.createCriteria(Animal.class,"a") + .createAlias("mother","m") + .add( Property.forName("m.class").eq(Reptile.class) ); + c.list(); + t.rollback(); + s.close(); + } + + public void testProjectedId() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createCriteria(Course.class).setProjection( Projections.property("courseCode") ).list(); + s.createCriteria(Course.class).setProjection( Projections.id() ).list(); + t.rollback(); + s.close(); + } + + public void testSubcriteriaJoinTypes() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + + Course courseA = new Course(); + courseA.setCourseCode("HIB-A"); + courseA.setDescription("Hibernate Training A"); + session.persist(courseA); + + Course courseB = new Course(); + courseB.setCourseCode("HIB-B"); + courseB.setDescription("Hibernate Training B"); + session.persist(courseB); + + Student gavin = new Student(); + gavin.setName("Gavin King"); + gavin.setStudentNumber(232); + gavin.setPreferredCourse(courseA); + session.persist(gavin); + + Student leonardo = new Student(); + leonardo.setName("Leonardo Quijano"); + leonardo.setStudentNumber(233); + leonardo.setPreferredCourse(courseB); + session.persist(leonardo); + + Student johnDoe = new Student(); + johnDoe.setName("John Doe"); + johnDoe.setStudentNumber(235); + johnDoe.setPreferredCourse(null); + session.persist(johnDoe); + + List result = session.createCriteria( Student.class ) + .setProjection( Property.forName("preferredCourse.courseCode") ) + .createCriteria( "preferredCourse", Criteria.LEFT_JOIN ) + .addOrder( Order.asc( "courseCode" ) ) + .list(); + assertEquals( 3, result.size() ); + // can't be sure of NULL comparison ordering aside from they should + // either come first or last + if ( result.get( 0 ) == null ) { + assertEquals( "HIB-A", result.get(1) ); + assertEquals( "HIB-B", result.get(2) ); + } + else { + assertNull( result.get(2) ); + assertEquals( "HIB-A", result.get(0) ); + assertEquals( "HIB-B", result.get(1) ); + } + + result = session.createCriteria( Student.class ) + .setFetchMode( "preferredCourse", FetchMode.JOIN ) + .createCriteria( "preferredCourse", Criteria.LEFT_JOIN ) + .addOrder( Order.asc( "courseCode" ) ) + .list(); + assertEquals( 3, result.size() ); + assertNotNull( result.get(0) ); + assertNotNull( result.get(1) ); + assertNotNull( result.get(2) ); + + result = session.createCriteria( Student.class ) + .setFetchMode( "preferredCourse", FetchMode.JOIN ) + .createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN ) + .addOrder( Order.asc( "pc.courseCode" ) ) + .list(); + assertEquals( 3, result.size() ); + assertNotNull( result.get(0) ); + assertNotNull( result.get(1) ); + assertNotNull( result.get(2) ); + + session.delete(gavin); + session.delete(leonardo); + session.delete(johnDoe); + session.delete(courseA); + session.delete(courseB); + t.commit(); + session.close(); + } +} + diff --git a/test/org/hibernate/test/criteria/Enrolment.hbm.xml b/test/org/hibernate/test/criteria/Enrolment.hbm.xml new file mode 100755 index 0000000000..05022a49c7 --- /dev/null +++ b/test/org/hibernate/test/criteria/Enrolment.hbm.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/criteria/Enrolment.java b/test/org/hibernate/test/criteria/Enrolment.java new file mode 100755 index 0000000000..1dcd66411f --- /dev/null +++ b/test/org/hibernate/test/criteria/Enrolment.java @@ -0,0 +1,63 @@ +//$Id$ +package org.hibernate.test.criteria; + +import java.io.Serializable; + +/** + * @author Gavin King + */ +public class Enrolment implements Serializable { + private Student student; + private Course course; + private long studentNumber; + private String courseCode; + private short year; + private short semester; + public String getCourseCode() { + return courseCode; + } + public void setCourseCode(String courseId) { + this.courseCode = courseId; + } + public long getStudentNumber() { + return studentNumber; + } + public void setStudentNumber(long studentId) { + this.studentNumber = studentId; + } + public Course getCourse() { + return course; + } + public void setCourse(Course course) { + this.course = course; + } + public Student getStudent() { + return student; + } + public void setStudent(Student student) { + this.student = student; + } + public short getSemester() { + return semester; + } + public void setSemester(short semester) { + this.semester = semester; + } + public short getYear() { + return year; + } + public void setYear(short year) { + this.year = year; + } + + public boolean equals(Object other) { + if ( !(other instanceof Enrolment) ) return false; + Enrolment that = (Enrolment) other; + return studentNumber==that.studentNumber && + courseCode.equals(that.courseCode); + } + + public int hashCode() { + return courseCode.hashCode(); + } +} diff --git a/test/org/hibernate/test/criteria/Student.java b/test/org/hibernate/test/criteria/Student.java new file mode 100755 index 0000000000..5b368f99f2 --- /dev/null +++ b/test/org/hibernate/test/criteria/Student.java @@ -0,0 +1,47 @@ +//$Id$ +package org.hibernate.test.criteria; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Gavin King + */ +public class Student { + private long studentNumber; + private String name; + private Course preferredCourse; + private Set enrolments = new HashSet(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getStudentNumber() { + return studentNumber; + } + + public void setStudentNumber(long studentNumber) { + this.studentNumber = studentNumber; + } + + public Course getPreferredCourse() { + return preferredCourse; + } + + public void setPreferredCourse(Course preferredCourse) { + this.preferredCourse = preferredCourse; + } + + public Set getEnrolments() { + return enrolments; + } + + public void setEnrolments(Set employments) { + this.enrolments = employments; + } +} diff --git a/test/org/hibernate/test/criteria/StudentDTO.java b/test/org/hibernate/test/criteria/StudentDTO.java new file mode 100644 index 0000000000..73192aa59f --- /dev/null +++ b/test/org/hibernate/test/criteria/StudentDTO.java @@ -0,0 +1,26 @@ +/* + * Created on 28-Jan-2005 + * + */ +package org.hibernate.test.criteria; + +/** + * @author max + * + */ +public class StudentDTO { + + private String studentName; + private String courseDescription; + + public StudentDTO() { } + + public String getName() { + return studentName; + } + + public String getDescription() { + return courseDescription; + } + +} diff --git a/test/org/hibernate/test/cuk/Account.java b/test/org/hibernate/test/cuk/Account.java new file mode 100755 index 0000000000..ff2e1ac9de --- /dev/null +++ b/test/org/hibernate/test/cuk/Account.java @@ -0,0 +1,50 @@ +//$Id$ +package org.hibernate.test.cuk; + +import java.io.Serializable; + +/** + * @author Gavin King + */ +public class Account implements Serializable { + private String accountId; + private Person user; + private char type; + /** + * @return Returns the user. + */ + public Person getUser() { + return user; + } + /** + * @param user The user to set. + */ + public void setUser(Person user) { + this.user = user; + } + /** + * @return Returns the accountId. + */ + public String getAccountId() { + return accountId; + } + /** + * @param accountId The accountId to set. + */ + public void setAccountId(String accountId) { + this.accountId = accountId; + } + /** + * @return Returns the type. + */ + public char getType() { + return type; + } + /** + * @param type The type to set. + */ + public void setType(char type) { + this.type = type; + } + +} diff --git a/test/org/hibernate/test/cuk/Address.java b/test/org/hibernate/test/cuk/Address.java new file mode 100755 index 0000000000..804b3e1bb3 --- /dev/null +++ b/test/org/hibernate/test/cuk/Address.java @@ -0,0 +1,75 @@ +//$Id$ +package org.hibernate.test.cuk; + +import java.io.Serializable; + +/** + * @author gavin + */ +public class Address implements Serializable { + private Long id; + private String address; + private String zip; + private String country; + private Person person; + /** + * @return Returns the id. + */ + public Long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Long id) { + this.id = id; + } + /** + * @return Returns the person. + */ + public Person getPerson() { + return person; + } + /** + * @param person The person to set. + */ + public void setPerson(Person person) { + this.person = person; + } + /** + * @return Returns the address. + */ + public String getAddress() { + return address; + } + /** + * @param address The address to set. + */ + public void setAddress(String address) { + this.address = address; + } + /** + * @return Returns the country. + */ + public String getCountry() { + return country; + } + /** + * @param country The country to set. + */ + public void setCountry(String country) { + this.country = country; + } + /** + * @return Returns the zip. + */ + public String getZip() { + return zip; + } + /** + * @param zip The zip to set. + */ + public void setZip(String zip) { + this.zip = zip; + } +} diff --git a/test/org/hibernate/test/cuk/CompositePropertyRefTest.java b/test/org/hibernate/test/cuk/CompositePropertyRefTest.java new file mode 100755 index 0000000000..0d4db87267 --- /dev/null +++ b/test/org/hibernate/test/cuk/CompositePropertyRefTest.java @@ -0,0 +1,124 @@ +//$Id$ +package org.hibernate.test.cuk; + +import java.util.List; +import java.util.Set; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class CompositePropertyRefTest extends FunctionalTestCase { + + public CompositePropertyRefTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "cuk/Person.hbm.xml" }; + } + + public void configure(Configuration cfg) { + cfg.setProperty(Environment.DEFAULT_BATCH_FETCH_SIZE, "1"); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CompositePropertyRefTest.class ); + } + + public void testOneToOnePropertyRef() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Person p = new Person(); + p.setName("Steve"); + p.setUserId("steve"); + Address a = new Address(); + a.setAddress("Texas"); + a.setCountry("USA"); + p.setAddress(a); + a.setPerson(p); + s.save(p); + Person p2 = new Person(); + p2.setName("Max"); + p2.setUserId("max"); + s.save(p2); + Account act = new Account(); + act.setType('c'); + act.setUser(p2); + p2.getAccounts().add(act); + s.save(act); + s.flush(); + s.clear(); + + p = (Person) s.get( Person.class, p.getId() ); //get address reference by outer join + p2 = (Person) s.get( Person.class, p2.getId() ); //get null address reference by outer join + assertNull( p2.getAddress() ); + assertNotNull( p.getAddress() ); + List l = s.createQuery("from Person").list(); //pull address references for cache + assertEquals( l.size(), 2 ); + assertTrue( l.contains(p) && l.contains(p2) ); + s.clear(); + + l = s.createQuery("from Person p order by p.name").list(); //get address references by sequential selects + assertEquals( l.size(), 2 ); + assertNull( ( (Person) l.get(0) ).getAddress() ); + assertNotNull( ( (Person) l.get(1) ).getAddress() ); + s.clear(); + + l = s.createQuery("from Person p left join fetch p.address a order by a.country").list(); //get em by outer join + assertEquals( l.size(), 2 ); + if ( ( (Person) l.get(0) ).getName().equals("Max") ) { + assertNull( ( (Person) l.get(0) ).getAddress() ); + assertNotNull( ( (Person) l.get(1) ).getAddress() ); + } + else { + assertNull( ( (Person) l.get(1) ).getAddress() ); + assertNotNull( ( (Person) l.get(0) ).getAddress() ); + } + s.clear(); + + l = s.createQuery("from Person p left join p.accounts").list(); + for ( int i=0; i<2; i++ ) { + Object[] row = (Object[]) l.get(i); + Person px = (Person) row[0]; + Set accounts = px.getAccounts(); + assertFalse( Hibernate.isInitialized(accounts) ); + assertTrue( px.getAccounts().size()>0 || row[1]==null ); + } + s.clear(); + + l = s.createQuery("from Person p left join fetch p.accounts a order by p.name").list(); + Person p0 = (Person) l.get(0); + assertTrue( Hibernate.isInitialized( p0.getAccounts() ) ); + assertEquals( p0.getAccounts().size(), 1 ); + assertSame( ( (Account) p0.getAccounts().iterator().next() ).getUser(), p0 ); + Person p1 = (Person) l.get(1); + assertTrue( Hibernate.isInitialized( p1.getAccounts() ) ); + assertEquals( p1.getAccounts().size(), 0 ); + s.clear(); + + l = s.createQuery("from Account a join fetch a.user").list(); + + s.clear(); + + l = s.createQuery("from Person p left join fetch p.address").list(); + + s.clear(); + s.createQuery( "delete Address" ).executeUpdate(); + s.createQuery( "delete Account" ).executeUpdate(); + s.createQuery( "delete Person" ).executeUpdate(); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/cuk/Person.hbm.xml b/test/org/hibernate/test/cuk/Person.hbm.xml new file mode 100755 index 0000000000..317cb9fa9f --- /dev/null +++ b/test/org/hibernate/test/cuk/Person.hbm.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/cuk/Person.java b/test/org/hibernate/test/cuk/Person.java new file mode 100755 index 0000000000..5f0bcf86b2 --- /dev/null +++ b/test/org/hibernate/test/cuk/Person.java @@ -0,0 +1,100 @@ +//$Id$ +package org.hibernate.test.cuk; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +/** + * @author gavin + */ +public class Person implements Serializable { + private Long id; + private String name; + private Address address; + private String userId; + private boolean deleted; + private Set accounts = new HashSet(); + /** + * @return Returns the userId. + */ + public String getUserId() { + return userId; + } + /** + * @param userId The userId to set. + */ + public void setUserId(String userId) { + this.userId = userId; + } + /** + * @return Returns the address. + */ + public Address getAddress() { + return address; + } + /** + * @param address The address to set. + */ + public void setAddress(Address address) { + this.address = address; + } + /** + * @return Returns the id. + */ + public Long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Long id) { + this.id = id; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + /** + * @return Returns the accounts. + */ + public Set getAccounts() { + return accounts; + } + /** + * @param accounts The accounts to set. + */ + public void setAccounts(Set accounts) { + this.accounts = accounts; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public boolean equals(Object other) { + if (other instanceof Person) { + Person that = (Person) other; + return that.isDeleted() == deleted && that.getUserId().equals(userId); + } + else { + return false; + } + } + + public int hashCode() { + return userId.hashCode(); + } +} diff --git a/test/org/hibernate/test/cut/CompositeUserTypeTest.java b/test/org/hibernate/test/cut/CompositeUserTypeTest.java new file mode 100755 index 0000000000..39dc76426f --- /dev/null +++ b/test/org/hibernate/test/cut/CompositeUserTypeTest.java @@ -0,0 +1,63 @@ +//$Id$ +package org.hibernate.test.cut; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class CompositeUserTypeTest extends FunctionalTestCase { + + public CompositeUserTypeTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "cut/types.hbm.xml", "cut/Transaction.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CompositeUserTypeTest.class ); + } + + public void testCompositeUserType() { + Session s = openSession(); + org.hibernate.Transaction t = s.beginTransaction(); + + Transaction tran = new Transaction(); + tran.setDescription("a small transaction"); + tran.setValue( new MonetoryAmount( new BigDecimal(1.5), Currency.getInstance("USD") ) ); + s.persist(tran); + + List result = s.createQuery("from Transaction tran where tran.value.amount > 1.0 and tran.value.currency = 'USD'").list(); + assertEquals( result.size(), 1 ); + tran.getValue().setCurrency( Currency.getInstance("AUD") ); + result = s.createQuery("from Transaction tran where tran.value.amount > 1.0 and tran.value.currency = 'AUD'").list(); + assertEquals( result.size(), 1 ); + + if ( !(getDialect() instanceof HSQLDialect) && ! (getDialect() instanceof Oracle9Dialect) ) { + + result = s.createQuery("from Transaction txn where txn.value = (1.5, 'AUD')").list(); + assertEquals( result.size(), 1 ); + result = s.createQuery("from Transaction where value = (1.5, 'AUD')").list(); + assertEquals( result.size(), 1 ); + + } + + s.delete(tran); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/cut/MonetoryAmount.java b/test/org/hibernate/test/cut/MonetoryAmount.java new file mode 100755 index 0000000000..853cc88eef --- /dev/null +++ b/test/org/hibernate/test/cut/MonetoryAmount.java @@ -0,0 +1,37 @@ +//$Id$ +package org.hibernate.test.cut; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Currency; + +/** + * @author Gavin King + */ +public class MonetoryAmount implements Serializable { + + private BigDecimal amount; + private Currency currency; + + public MonetoryAmount(BigDecimal amount, Currency currency) { + this.amount = amount; + this.currency = currency; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + +} diff --git a/test/org/hibernate/test/cut/MonetoryAmountUserType.java b/test/org/hibernate/test/cut/MonetoryAmountUserType.java new file mode 100755 index 0000000000..988446f115 --- /dev/null +++ b/test/org/hibernate/test/cut/MonetoryAmountUserType.java @@ -0,0 +1,104 @@ +//$Id$ +package org.hibernate.test.cut; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Currency; + +import org.hibernate.Hibernate; +import org.hibernate.HibernateException; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.type.Type; +import org.hibernate.usertype.CompositeUserType; + +/** + * @author Gavin King + */ +public class MonetoryAmountUserType implements CompositeUserType { + + public String[] getPropertyNames() { + return new String[] { "amount", "currency" }; + } + + public Type[] getPropertyTypes() { + return new Type[] { Hibernate.BIG_DECIMAL, Hibernate.CURRENCY }; + } + + public Object getPropertyValue(Object component, int property) throws HibernateException { + MonetoryAmount ma = (MonetoryAmount) component; + return property==0 ? (Object) ma.getAmount() : (Object) ma.getCurrency(); + } + + public void setPropertyValue(Object component, int property, Object value) + throws HibernateException { + MonetoryAmount ma = (MonetoryAmount) component; + if ( property==0 ) { + ma.setAmount( (BigDecimal) value ); + } + else { + ma.setCurrency( (Currency) value ); + } + } + + public Class returnedClass() { + return MonetoryAmount.class; + } + + public boolean equals(Object x, Object y) throws HibernateException { + if (x==y) return true; + if (x==null || y==null) return false; + MonetoryAmount mx = (MonetoryAmount) x; + MonetoryAmount my = (MonetoryAmount) y; + return mx.getAmount().equals( my.getAmount() ) && + mx.getCurrency().equals( my.getCurrency() ); + } + + public int hashCode(Object x) throws HibernateException { + return ( (MonetoryAmount) x ).getAmount().hashCode(); + } + + public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) + throws HibernateException, SQLException { + BigDecimal amt = (BigDecimal) Hibernate.BIG_DECIMAL.nullSafeGet( rs, names[0] ); + Currency cur = (Currency) Hibernate.CURRENCY.nullSafeGet( rs, names[1] ); + if (amt==null) return null; + return new MonetoryAmount(amt, cur); + } + + public void nullSafeSet(PreparedStatement st, Object value, int index, + SessionImplementor session) throws HibernateException, SQLException { + MonetoryAmount ma = (MonetoryAmount) value; + BigDecimal amt = ma == null ? null : ma.getAmount(); + Currency cur = ma == null ? null : ma.getCurrency(); + Hibernate.BIG_DECIMAL.nullSafeSet(st, amt, index); + Hibernate.CURRENCY.nullSafeSet(st, cur, index+1); + } + + public Object deepCopy(Object value) throws HibernateException { + MonetoryAmount ma = (MonetoryAmount) value; + return new MonetoryAmount( ma.getAmount(), ma.getCurrency() ); + } + + public boolean isMutable() { + return true; + } + + public Serializable disassemble(Object value, SessionImplementor session) + throws HibernateException { + return (Serializable) deepCopy(value); + } + + public Object assemble(Serializable cached, SessionImplementor session, Object owner) + throws HibernateException { + return deepCopy(cached); + } + + public Object replace(Object original, Object target, SessionImplementor session, Object owner) + throws HibernateException { + return deepCopy(original); //TODO: improve + } + +} diff --git a/test/org/hibernate/test/cut/Transaction.hbm.xml b/test/org/hibernate/test/cut/Transaction.hbm.xml new file mode 100755 index 0000000000..fb24e82de2 --- /dev/null +++ b/test/org/hibernate/test/cut/Transaction.hbm.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/cut/Transaction.java b/test/org/hibernate/test/cut/Transaction.java new file mode 100755 index 0000000000..f30db7fee2 --- /dev/null +++ b/test/org/hibernate/test/cut/Transaction.java @@ -0,0 +1,37 @@ +//$Id$ +package org.hibernate.test.cut; + +/** + * @author Gavin King + */ +public class Transaction { + + private Long id; + private String description; + private MonetoryAmount value; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public MonetoryAmount getValue() { + return value; + } + + public void setValue(MonetoryAmount value) { + this.value = value; + } + +} diff --git a/test/org/hibernate/test/cut/types.hbm.xml b/test/org/hibernate/test/cut/types.hbm.xml new file mode 100644 index 0000000000..d7cc00cf9c --- /dev/null +++ b/test/org/hibernate/test/cut/types.hbm.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/deletetransient/Address.java b/test/org/hibernate/test/deletetransient/Address.java new file mode 100644 index 0000000000..fdf1e9f3f3 --- /dev/null +++ b/test/org/hibernate/test/deletetransient/Address.java @@ -0,0 +1,34 @@ +package org.hibernate.test.deletetransient; + +/** + * todo: describe Address + * + * @author Steve Ebersole + */ +public class Address { + private Long id; + private String info; + + public Address() { + } + + public Address(String info) { + this.info = info; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/deletetransient/DeleteTransientEntityTest.java b/test/org/hibernate/test/deletetransient/DeleteTransientEntityTest.java new file mode 100644 index 0000000000..354f3f75b5 --- /dev/null +++ b/test/org/hibernate/test/deletetransient/DeleteTransientEntityTest.java @@ -0,0 +1,108 @@ +package org.hibernate.test.deletetransient; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * todo: describe DeleteTransientEntityTest + * + * @author Steve Ebersole + */ +public class DeleteTransientEntityTest extends FunctionalTestCase { + public DeleteTransientEntityTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "deletetransient/Person.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( DeleteTransientEntityTest.class ); + } + + public void testTransientEntityDeletionNoCascades() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.delete( new Address() ); + t.commit(); + s.close(); + } + + public void testTransientEntityDeletionCascadingToTransientAssociation() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Person p = new Person(); + p.getAddresses().add( new Address() ); + s.delete( p ); + t.commit(); + s.close(); + } + + public void testTransientEntityDeleteCascadingToCircularity() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Person p1 = new Person(); + Person p2 = new Person(); + p1.getFriends().add( p2 ); + p2.getFriends().add( p1 ); + s.delete( p1 ); + t.commit(); + s.close(); + } + + public void testTransientEntityDeletionCascadingToDetachedAssociation() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Address address = new Address(); + address.setInfo( "123 Main St." ); + s.save( address ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Person p = new Person(); + p.getAddresses().add( address ); + s.delete( p ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Long count = ( Long ) s.createQuery( "select count(*) from Address" ).list().get( 0 ); + assertEquals( "delete not cascaded properly across transient entity", 0, count.longValue() ); + t.commit(); + s.close(); + } + + public void testTransientEntityDeletionCascadingToPersistentAssociation() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Address address = new Address(); + address.setInfo( "123 Main St." ); + s.save( address ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + address = ( Address ) s.get( Address.class, address.getId() ); + Person p = new Person(); + p.getAddresses().add( address ); + s.delete( p ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Long count = ( Long ) s.createQuery( "select count(*) from Address" ).list().get( 0 ); + assertEquals( "delete not cascaded properly across transient entity", 0, count.longValue() ); + t.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/deletetransient/Person.hbm.xml b/test/org/hibernate/test/deletetransient/Person.hbm.xml new file mode 100644 index 0000000000..6ed6f10751 --- /dev/null +++ b/test/org/hibernate/test/deletetransient/Person.hbm.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/deletetransient/Person.java b/test/org/hibernate/test/deletetransient/Person.java new file mode 100644 index 0000000000..d01ef3f5d0 --- /dev/null +++ b/test/org/hibernate/test/deletetransient/Person.java @@ -0,0 +1,57 @@ +package org.hibernate.test.deletetransient; + +import java.util.Set; +import java.util.HashSet; +import java.util.Collection; +import java.util.ArrayList; + +/** + * todo: describe Person + * + * @author Steve Ebersole + */ +public class Person { + private Long id; + private String name; + private Set addresses = new HashSet(); + private Collection friends = new ArrayList(); + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getAddresses() { + return addresses; + } + + public void setAddresses(Set addresses) { + this.addresses = addresses; + } + + public Collection getFriends() { + return friends; + } + + public void setFriends(Collection friends) { + this.friends = friends; + } +} diff --git a/test/org/hibernate/test/dialect/functional/DialectFunctionalTestsSuite.java b/test/org/hibernate/test/dialect/functional/DialectFunctionalTestsSuite.java new file mode 100644 index 0000000000..ebaae93999 --- /dev/null +++ b/test/org/hibernate/test/dialect/functional/DialectFunctionalTestsSuite.java @@ -0,0 +1,18 @@ +package org.hibernate.test.dialect.functional; + +import junit.framework.TestSuite; + +import org.hibernate.test.dialect.functional.cache.SQLFunctionsInterSystemsTest; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class DialectFunctionalTestsSuite { + public static TestSuite suite() { + TestSuite suite = new TestSuite( "Dialect tests" ); + suite.addTest( SQLFunctionsInterSystemsTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java b/test/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java new file mode 100644 index 0000000000..3d5f3e81f5 --- /dev/null +++ b/test/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java @@ -0,0 +1,740 @@ +package org.hibernate.test.dialect.functional.cache; + +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import junit.framework.Test; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.hibernate.Hibernate; +import org.hibernate.LockMode; +import org.hibernate.Query; +import org.hibernate.ScrollableResults; +import org.hibernate.Transaction; +import org.hibernate.classic.Session; +import org.hibernate.dialect.Cache71Dialect; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.dialect.InterbaseDialect; +import org.hibernate.dialect.MckoiDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.dialect.TimesTenDialect; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.legacy.Blobber; +import org.hibernate.test.legacy.Broken; +import org.hibernate.test.legacy.Fixed; +import org.hibernate.test.legacy.Simple; +import org.hibernate.test.legacy.Single; + +/** + * Tests for function support on CacheSQL... + * + * @author Jonathan Levinson + */ +public class SQLFunctionsInterSystemsTest extends DatabaseSpecificFunctionalTestCase { + + private static final Log log = LogFactory.getLog(SQLFunctionsInterSystemsTest.class); + + public SQLFunctionsInterSystemsTest(String name) { + super(name); + } + + public String[] getMappings() { + return new String[] { + "legacy/AltSimple.hbm.xml", + "legacy/Broken.hbm.xml", + "legacy/Blobber.hbm.xml", + "dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml" + }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( SQLFunctionsInterSystemsTest.class ); + } + + public boolean appliesTo(Dialect dialect) { + // all these test case apply only to testing InterSystems' CacheSQL dialect + return dialect instanceof Cache71Dialect; + } + + public void testDialectSQLFunctions() throws Exception { + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Iterator iter = s.iterate("select max(s.count) from Simple s"); + + if ( getDialect() instanceof MySQLDialect ) assertTrue( iter.hasNext() && iter.next()==null ); + + Simple simple = new Simple(); + simple.setName("Simple Dialect Function Test"); + simple.setAddress("Simple Address"); + simple.setPay(new Float(45.8)); + simple.setCount(2); + s.save(simple, new Long(10) ); + + // Test to make sure allocating an specified object operates correctly. + assertTrue( + s.find("select new org.hibernate.test.legacy.S(s.count, s.address) from Simple s").size() == 1 + ); + + // Quick check the base dialect functions operate correctly + assertTrue( + s.find("select max(s.count) from Simple s").size() == 1 + ); + assertTrue( + s.find("select count(*) from Simple s").size() == 1 + ); + + if ( getDialect() instanceof Cache71Dialect) { + // Check Oracle Dialect mix of dialect functions - no args (no parenthesis and single arg functions + java.util.List rset = s.find("select s.name, sysdate, floor(s.pay), round(s.pay,0) from Simple s"); + assertNotNull("Name string should have been returned",(((Object[])rset.get(0))[0])); + assertNotNull("Todays Date should have been returned",(((Object[])rset.get(0))[1])); + assertEquals("floor(45.8) result was incorrect ", new Integer(45), ( (Object[]) rset.get(0) )[2] ); + assertEquals("round(45.8) result was incorrect ", new Float(46), ( (Object[]) rset.get(0) )[3] ); + + simple.setPay(new Float(-45.8)); + s.update(simple); + + // Test type conversions while using nested functions (Float to Int). + rset = s.find("select abs(round(s.pay,0)) from Simple s"); + assertEquals("abs(round(-45.8)) result was incorrect ", new Float(46), rset.get(0)); + + // Test a larger depth 3 function example - Not a useful combo other than for testing + assertTrue( + s.find("select floor(round(sysdate,1)) from Simple s").size() == 1 + ); + + // Test the oracle standard NVL funtion as a test of multi-param functions... + simple.setPay(null); + s.update(simple); + Double value = (Double) s.createQuery("select mod( nvl(s.pay, 5000), 2 ) from Simple as s where s.id = 10").list().get(0); + assertTrue( 0 == value.intValue() ); + } + + if ( (getDialect() instanceof Cache71Dialect) ) { + // Test the hsql standard MOD funtion as a test of multi-param functions... + Double value = (Double) s.find("select MOD(s.count, 2) from Simple as s where s.id = 10" ).get(0); + assertTrue( 0 == value.intValue() ); + } + + /* + if ( (getDialect() instanceof Cache71Dialect) ) { + // Test the hsql standard MOD funtion as a test of multi-param functions... + Date value = (Date) s.find("select sysdate from Simple as s where nvl(cast(null as date), sysdate)=sysdate" ).get(0); + assertTrue( value.equals(new java.sql.Date(System.currentTimeMillis()))); + } + */ + + s.delete(simple); + t.commit(); + s.close(); + } + + public void testSetProperties() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Simple simple = new Simple(); + simple.setName("Simple 1"); + s.save(simple, new Long(10) ); + Query q = s.createQuery("from Simple s where s.name=:name and s.count=:count"); + q.setProperties(simple); + assertTrue( q.list().get(0)==simple ); + //misuse of "Single" as a propertyobject, but it was the first testclass i found with a collection ;) + Single single = new Single() { // trivial hack to test properties with arrays. + String[] getStuff() { return (String[]) getSeveral().toArray(new String[getSeveral().size()]); } + }; + + List l = new ArrayList(); + l.add("Simple 1"); + l.add("Slimeball"); + single.setSeveral(l); + q = s.createQuery("from Simple s where s.name in (:several)"); + q.setProperties(single); + assertTrue( q.list().get(0)==simple ); + + + q = s.createQuery("from Simple s where s.name in (:stuff)"); + q.setProperties(single); + assertTrue( q.list().get(0)==simple ); + s.delete(simple); + t.commit(); + s.close(); + } + + public void testBroken() throws Exception { + if (getDialect() instanceof Oracle9Dialect) return; + Session s = openSession(); + Transaction t = s.beginTransaction(); + Broken b = new Fixed(); + b.setId( new Long(123)); + b.setOtherId("foobar"); + s.save(b); + s.flush(); + b.setTimestamp( new Date() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.update(b); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + b = (Broken) s.load( Broken.class, b ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete(b); + t.commit(); + s.close(); + } + + public void testNothinToUpdate() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Simple simple = new Simple(); + simple.setName("Simple 1"); + s.save( simple, new Long(10) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.update( simple, new Long(10) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.update( simple, new Long(10) ); + s.delete(simple); + t.commit(); + s.close(); + } + + public void testCachedQuery() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Simple simple = new Simple(); + simple.setName("Simple 1"); + s.save( simple, new Long(10) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Query q = s.createQuery("from Simple s where s.name=?"); + q.setCacheable(true); + q.setString(0, "Simple 1"); + assertTrue( q.list().size()==1 ); + assertTrue( q.list().size()==1 ); + assertTrue( q.list().size()==1 ); + q = s.createQuery("from Simple s where s.name=:name"); + q.setCacheable(true); + q.setString("name", "Simple 1"); + assertTrue( q.list().size()==1 ); + simple = (Simple) q.list().get(0); + + q.setString("name", "Simple 2"); + assertTrue( q.list().size()==0 ); + assertTrue( q.list().size()==0 ); + simple.setName("Simple 2"); + assertTrue( q.list().size()==1 ); + assertTrue( q.list().size()==1 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + q = s.createQuery("from Simple s where s.name=:name"); + q.setString("name", "Simple 2"); + q.setCacheable(true); + assertTrue( q.list().size()==1 ); + assertTrue( q.list().size()==1 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.update( simple, new Long(10) ); + s.delete(simple); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + q = s.createQuery("from Simple s where s.name=?"); + q.setCacheable(true); + q.setString(0, "Simple 1"); + assertTrue( q.list().size()==0 ); + assertTrue( q.list().size()==0 ); + t.commit(); + s.close(); + } + + public void testCachedQueryRegion() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Simple simple = new Simple(); + simple.setName("Simple 1"); + s.save( simple, new Long(10) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Query q = s.createQuery("from Simple s where s.name=?"); + q.setCacheRegion("foo"); + q.setCacheable(true); + q.setString(0, "Simple 1"); + assertTrue( q.list().size()==1 ); + assertTrue( q.list().size()==1 ); + assertTrue( q.list().size()==1 ); + q = s.createQuery("from Simple s where s.name=:name"); + q.setCacheRegion("foo"); + q.setCacheable(true); + q.setString("name", "Simple 1"); + assertTrue( q.list().size()==1 ); + simple = (Simple) q.list().get(0); + + q.setString("name", "Simple 2"); + assertTrue( q.list().size()==0 ); + assertTrue( q.list().size()==0 ); + simple.setName("Simple 2"); + assertTrue( q.list().size()==1 ); + assertTrue( q.list().size()==1 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.update( simple, new Long(10) ); + s.delete(simple); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + q = s.createQuery("from Simple s where s.name=?"); + q.setCacheRegion("foo"); + q.setCacheable(true); + q.setString(0, "Simple 1"); + assertTrue( q.list().size()==0 ); + assertTrue( q.list().size()==0 ); + t.commit(); + s.close(); + } + + public void testSQLFunctions() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Simple simple = new Simple(); + simple.setName("Simple 1"); + s.save(simple, new Long(10) ); + + if ( getDialect() instanceof Cache71Dialect) { + s.find("from Simple s where repeat('foo', 3) = 'foofoofoo'"); + s.find("from Simple s where repeat(s.name, 3) = 'foofoofoo'"); + s.find("from Simple s where repeat( lower(s.name), (3 + (1-1)) / 2) = 'foofoofoo'"); + } + + assertTrue( + s.find("from Simple s where upper( s.name ) ='SIMPLE 1'").size()==1 + ); + if ( !(getDialect() instanceof HSQLDialect) ) { + assertTrue( + s.find("from Simple s where not( upper( s.name ) ='yada' or 1=2 or 'foo'='bar' or not('foo'='foo') or 'foo' like 'bar' )").size()==1 + ); + } + if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof SybaseDialect) && !(getDialect() instanceof MckoiDialect) && !(getDialect() instanceof InterbaseDialect) && !(getDialect() instanceof TimesTenDialect) ) { //My SQL has a funny concatenation operator + assertTrue( + s.find("from Simple s where lower( s.name || ' foo' ) ='simple 1 foo'").size()==1 + ); + } + /* + is not concat in Cache + if ( (getDialect() instanceof Cache71Dialect) ) { + assertTrue( + s.find("from Simple s where lower( cons.name ' foo' ) ='simple 1 foo'").size()==1 + ); + } + */ + if ( (getDialect() instanceof Cache71Dialect) ) { + assertTrue( + s.find("from Simple s where lower( concat(s.name, ' foo') ) ='simple 1 foo'").size()==1 + ); + } + + Simple other = new Simple(); + other.setName("Simple 2"); + other.setCount(12); + simple.setOther(other); + s.save( other, new Long(20) ); + //s.find("from Simple s where s.name ## 'cat|rat|bag'"); + assertTrue( + s.find("from Simple s where upper( s.other.name ) ='SIMPLE 2'").size()==1 + ); + assertTrue( + s.find("from Simple s where not ( upper( s.other.name ) ='SIMPLE 2' )").size()==0 + ); + assertTrue( + s.find("select distinct s from Simple s where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2").size()==1 + ); + assertTrue( + s.find("select s from Simple s where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2 order by s.other.count").size()==1 + ); + Simple min = new Simple(); + min.setCount(-1); + s.save(min, new Long(30) ); + if ( ! (getDialect() instanceof MySQLDialect) && ! (getDialect() instanceof HSQLDialect) ) { //My SQL has no subqueries + assertTrue( + s.find("from Simple s where s.count > ( select min(sim.count) from Simple sim )").size()==2 + ); + t.commit(); + t = s.beginTransaction(); + assertTrue( + s.find("from Simple s where s = some( select sim from Simple sim where sim.count>=0 ) and s.count >= 0").size()==2 + ); + assertTrue( + s.find("from Simple s where s = some( select sim from Simple sim where sim.other.count=s.other.count ) and s.other.count > 0").size()==1 + ); + } + + Iterator iter = s.iterate("select sum(s.count) from Simple s group by s.count having sum(s.count) > 10"); + assertTrue( iter.hasNext() ); + assertEquals( new Long(12), iter.next() ); + assertTrue( !iter.hasNext() ); + if ( ! (getDialect() instanceof MySQLDialect) ) { + iter = s.iterate("select s.count from Simple s group by s.count having s.count = 12"); + assertTrue( iter.hasNext() ); + } + + s.iterate("select s.id, s.count, count(t), max(t.date) from Simple s, Simple t where s.count = t.count group by s.id, s.count order by s.count"); + + Query q = s.createQuery("from Simple s"); + q.setMaxResults(10); + assertTrue( q.list().size()==3 ); + q = s.createQuery("from Simple s"); + q.setMaxResults(1); + assertTrue( q.list().size()==1 ); + q = s.createQuery("from Simple s"); + assertTrue( q.list().size()==3 ); + q = s.createQuery("from Simple s where s.name = ?"); + q.setString(0, "Simple 1"); + assertTrue( q.list().size()==1 ); + q = s.createQuery("from Simple s where s.name = ? and upper(s.name) = ?"); + q.setString(1, "SIMPLE 1"); + q.setString(0, "Simple 1"); + q.setFirstResult(0); + assertTrue( q.iterate().hasNext() ); + q = s.createQuery("from Simple s where s.name = :foo and upper(s.name) = :bar or s.count=:count or s.count=:count + 1"); + q.setParameter("bar", "SIMPLE 1"); + q.setString("foo", "Simple 1"); + q.setInteger("count", 69); + q.setFirstResult(0); + assertTrue( q.iterate().hasNext() ); + q = s.createQuery("select s.id from Simple s"); + q.setFirstResult(1); + q.setMaxResults(2); + iter = q.iterate(); + int i=0; + while ( iter.hasNext() ) { + assertTrue( iter.next() instanceof Long ); + i++; + } + assertTrue(i==2); + q = s.createQuery("select all s, s.other from Simple s where s = :s"); + q.setParameter("s", simple); + assertTrue( q.list().size()==1 ); + + + q = s.createQuery("from Simple s where s.name in (:name_list) and s.count > :count"); + HashSet set = new HashSet(); + set.add("Simple 1"); set.add("foo"); + q.setParameterList( "name_list", set ); + q.setParameter("count", new Integer(-1) ); + assertTrue( q.list().size()==1 ); + + ScrollableResults sr = s.createQuery("from Simple s").scroll(); + sr.next(); + sr.get(0); + sr.close(); + + s.delete(other); + s.delete(simple); + s.delete(min); + t.commit(); + s.close(); + + } + + public void testBlobClob() throws Exception { + + Session s = openSession(); + Blobber b = new Blobber(); + b.setBlob( Hibernate.createBlob( "foo/bar/baz".getBytes() ) ); + b.setClob( Hibernate.createClob("foo/bar/baz") ); + s.save(b); + //s.refresh(b); + //assertTrue( b.getClob() instanceof ClobImpl ); + s.flush(); + s.refresh(b); + //b.getBlob().setBytes( 2, "abc".getBytes() ); + log.debug("levinson: just bfore b.getClob()"); + b.getClob().getSubString(2, 3); + //b.getClob().setString(2, "abc"); + s.flush(); + s.connection().commit(); + s.close(); + + s = openSession(); + b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) ); + Blobber b2 = new Blobber(); + s.save(b2); + b2.setBlob( b.getBlob() ); + b.setBlob(null); + //assertTrue( b.getClob().getSubString(1, 3).equals("fab") ); + b.getClob().getSubString(1, 6); + //b.getClob().setString(1, "qwerty"); + s.flush(); + s.connection().commit(); + s.close(); + + s = openSession(); + b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) ); + b.setClob( Hibernate.createClob("xcvfxvc xcvbx cvbx cvbx cvbxcvbxcvbxcvb") ); + s.flush(); + s.connection().commit(); + s.close(); + + s = openSession(); + b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) ); + assertTrue( b.getClob().getSubString(1, 7).equals("xcvfxvc") ); + //b.getClob().setString(5, "1234567890"); + s.flush(); + s.connection().commit(); + s.close(); + + + /*InputStream is = getClass().getClassLoader().getResourceAsStream("jdbc20.pdf"); + s = sessionsopenSession(); + b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) ); + System.out.println( is.available() ); + int size = is.available(); + b.setBlob( Hibernate.createBlob( is, is.available() ) ); + s.flush(); + s.connection().commit(); + ResultSet rs = s.connection().createStatement().executeQuery("select datalength(blob_) from blobber where id=" + b.getId() ); + rs.next(); + assertTrue( size==rs.getInt(1) ); + rs.close(); + s.close(); + + s = sessionsopenSession(); + b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) ); + File f = new File("C:/foo.pdf"); + f.createNewFile(); + FileOutputStream fos = new FileOutputStream(f); + Blob blob = b.getBlob(); + byte[] bytes = blob.getBytes( 1, (int) blob.length() ); + System.out.println( bytes.length ); + fos.write(bytes); + fos.flush(); + fos.close(); + s.close();*/ + + } + + public void testSqlFunctionAsAlias() throws Exception { + String functionName = locateAppropriateDialectFunctionNameForAliasTest(); + if (functionName == null) { + log.info("Dialect does not list any no-arg functions"); + return; + } + + log.info("Using function named [" + functionName + "] for 'function as alias' test"); + String query = "select " + functionName + " from Simple as " + functionName + " where " + functionName + ".id = 10"; + + Session s = openSession(); + Transaction t = s.beginTransaction(); + Simple simple = new Simple(); + simple.setName("Simple 1"); + s.save( simple, new Long(10) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + List result = s.find(query); + assertTrue( result.size() == 1 ); + assertTrue(result.get(0) instanceof Simple); + s.delete( result.get(0) ); + t.commit(); + s.close(); + } + + private String locateAppropriateDialectFunctionNameForAliasTest() { + for (Iterator itr = getDialect().getFunctions().entrySet().iterator(); itr.hasNext(); ) { + final Map.Entry entry = (Map.Entry) itr.next(); + final SQLFunction function = (SQLFunction) entry.getValue(); + if ( !function.hasArguments() && !function.hasParenthesesIfNoArguments() ) { + return (String) entry.getKey(); + } + } + return null; + } + + public void testCachedQueryOnInsert() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Simple simple = new Simple(); + simple.setName("Simple 1"); + s.save( simple, new Long(10) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Query q = s.createQuery("from Simple s"); + List list = q.setCacheable(true).list(); + assertTrue( list.size()==1 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + q = s.createQuery("from Simple s"); + list = q.setCacheable(true).list(); + assertTrue( list.size()==1 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Simple simple2 = new Simple(); + simple2.setCount(133); + s.save( simple2, new Long(12) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + q = s.createQuery("from Simple s"); + list = q.setCacheable(true).list(); + assertTrue( list.size()==2 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + q = s.createQuery("from Simple s"); + list = q.setCacheable(true).list(); + assertTrue( list.size()==2 ); + Iterator i = list.iterator(); + while ( i.hasNext() ) s.delete( i.next() ); + t.commit(); + s.close(); + + } + + public void testInterSystemsFunctions() throws Exception { + Calendar cal = new GregorianCalendar(); + cal.set(1977,6,3,0,0,0); + java.sql.Timestamp testvalue = new java.sql.Timestamp(cal.getTimeInMillis()); + testvalue.setNanos(0); + Calendar cal3 = new GregorianCalendar(); + cal3.set(1976,2,3,0,0,0); + java.sql.Timestamp testvalue3 = new java.sql.Timestamp(cal3.getTimeInMillis()); + testvalue3.setNanos(0); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + try { + Statement stmt = s.connection().createStatement(); + stmt.executeUpdate("DROP FUNCTION spLock FROM TestInterSystemsFunctionsClass"); + t.commit(); + } + catch (Exception ex) { + System.out.println("as we expected stored procedure sp does not exist when we drop it"); + + } + t = s.beginTransaction(); + Statement stmt = s.connection().createStatement(); + String create_function = "CREATE FUNCTION SQLUser.TestInterSystemsFunctionsClass_spLock\n" + + " ( INOUT pHandle %SQLProcContext, \n" + + " ROWID INTEGER \n" + + " )\n" + + " FOR User.TestInterSystemsFunctionsClass " + + " PROCEDURE\n" + + " RETURNS INTEGER\n" + + " LANGUAGE OBJECTSCRIPT\n" + + " {\n" + + " q 0\n" + + " }"; + stmt.executeUpdate(create_function); + t.commit(); + t = s.beginTransaction(); + + TestInterSystemsFunctionsClass object = new TestInterSystemsFunctionsClass(); + object.setDateText("1977-07-03"); + object.setDate1(testvalue); + object.setDate3(testvalue3); + s.save( object, new Long(10)); + t.commit(); + s.close(); + s = openSession(); + s.clear(); + t = s.beginTransaction(); + TestInterSystemsFunctionsClass test = (TestInterSystemsFunctionsClass) s.get(TestInterSystemsFunctionsClass.class, new Long(10)); + assertTrue( test.getDate1().equals(testvalue)); + test = (TestInterSystemsFunctionsClass) s.get(TestInterSystemsFunctionsClass.class, new Long(10), LockMode.UPGRADE); + assertTrue( test.getDate1().equals(testvalue)); + Date value = (Date) s.find("select nvl(o.date,o.dateText) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue( value.equals(testvalue)); + Object nv = s.find("select nullif(o.dateText,o.dateText) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue( nv == null); + String dateText = (String) s.find("select nvl(o.dateText,o.date) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue( dateText.equals("1977-07-03")); + value = (Date) s.find("select ifnull(o.date,o.date1) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue( value.equals(testvalue)); + value = (Date) s.find("select ifnull(o.date3,o.date,o.date1) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue( value.equals(testvalue)); + Integer pos = (Integer) s.find("select position('07', o.dateText) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue(pos.intValue() == 6); + String st = (String) s.find("select convert(o.date1, SQL_TIME) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue( st.equals("00:00:00")); + java.sql.Time tm = (java.sql.Time) s.find("select cast(o.date1, time) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue( tm.toString().equals("00:00:00")); + Double diff = (Double)s.find("select timestampdiff(SQL_TSI_FRAC_SECOND, o.date3, o.date1) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue(diff.doubleValue() != 0.0); + diff = (Double)s.find("select timestampdiff(SQL_TSI_MONTH, o.date3, o.date1) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue(diff.doubleValue() == 16.0); + diff = (Double)s.find("select timestampdiff(SQL_TSI_WEEK, o.date3, o.date1) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue(diff.doubleValue() >= 16*4); + diff = (Double)s.find("select timestampdiff(SQL_TSI_YEAR, o.date3, o.date1) from TestInterSystemsFunctionsClass as o" ).get(0); + assertTrue(diff.doubleValue() == 1.0); + + t.commit(); + s.close(); + + + } + +} diff --git a/test/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml b/test/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml new file mode 100644 index 0000000000..0860abaa7f --- /dev/null +++ b/test/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.java b/test/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.java new file mode 100644 index 0000000000..15f18eb179 --- /dev/null +++ b/test/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.java @@ -0,0 +1,51 @@ +package org.hibernate.test.dialect.functional.cache; + +import java.util.Date; + +/** + * Entity for testing function support of InterSystems' CacheSQL... + * + * @author Jonathan Levinson + */ +public class TestInterSystemsFunctionsClass { + private java.util.Date date3; + private java.util.Date date1; + private java.util.Date date; + private String dateText; + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + + public String getDateText() { + return dateText; + } + + public void setDateText(String dateText) { + this.dateText = dateText; + } + + + public Date getDate1() { + return date1; + } + + public void setDate1(Date date1) { + this.date1 = date1; + } + + + public Date getDate3() { + return date3; + } + + public void setDate3(Date date3) { + this.date3 = date3; + } + +} diff --git a/test/org/hibernate/test/dialect/unit/DialectUnitTestsSuite.java b/test/org/hibernate/test/dialect/unit/DialectUnitTestsSuite.java new file mode 100644 index 0000000000..ef108da4c2 --- /dev/null +++ b/test/org/hibernate/test/dialect/unit/DialectUnitTestsSuite.java @@ -0,0 +1,20 @@ +package org.hibernate.test.dialect.unit; + +import junit.framework.TestSuite; + +import org.hibernate.test.dialect.unit.lockhint.SybaseLockHintsTest; +import org.hibernate.test.dialect.unit.lockhint.SQLServerLockHintsTest; + +/** + * Suite of all unit tests of the Dialect(s). + * + * @author Steve Ebersole + */ +public class DialectUnitTestsSuite { + public static TestSuite suite() { + TestSuite suite = new TestSuite( "Dialect unit-tests" ); + suite.addTest( SybaseLockHintsTest.suite() ); + suite.addTest( SQLServerLockHintsTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java b/test/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java new file mode 100644 index 0000000000..0374400251 --- /dev/null +++ b/test/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java @@ -0,0 +1,64 @@ +package org.hibernate.test.dialect.unit.lockhint; + +import java.util.HashMap; +import java.util.Collections; + +import org.hibernate.junit.UnitTestCase; +import org.hibernate.dialect.Dialect; +import org.hibernate.util.StringHelper; +import org.hibernate.LockMode; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public abstract class AbstractLockHintTest extends UnitTestCase { + public AbstractLockHintTest(String string) { + super( string ); + } + + private Dialect dialect; + + protected abstract String getLockHintUsed(); + protected abstract Dialect getDialectUnderTest(); + + protected void setUp() throws Exception { + super.setUp(); + this.dialect = getDialectUnderTest(); + } + + protected void tearDown() throws Exception { + this.dialect = null; + super.tearDown(); + } + + public void testBasicLocking() { + new SyntaxChecker( "select xyz from ABC $HOLDER$", "a" ).verify(); + new SyntaxChecker( "select xyz from ABC $HOLDER$ join DEF d", "a" ).verify(); + new SyntaxChecker( "select xyz from ABC $HOLDER$, DEF d", "a" ).verify(); + } + + protected class SyntaxChecker { + private final String aliasToLock; + private final String rawSql; + private final String expectedProcessedSql; + + public SyntaxChecker(String template) { + this( template, "" ); + } + + public SyntaxChecker(String template, String aliasToLock) { + this.aliasToLock = aliasToLock; + rawSql = StringHelper.replace( template, "$HOLDER$", aliasToLock ); + expectedProcessedSql = StringHelper.replace( template, "$HOLDER$", aliasToLock + " " + getLockHintUsed() ); + } + + public void verify() { + HashMap lockModes = new HashMap(); + lockModes.put( aliasToLock, LockMode.UPGRADE ); + String actualProcessedSql = dialect.applyLocksToSql( rawSql, lockModes, Collections.EMPTY_MAP ); + assertEquals( expectedProcessedSql, actualProcessedSql ); + } + } +} diff --git a/test/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java b/test/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java new file mode 100644 index 0000000000..33f73bcb1a --- /dev/null +++ b/test/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java @@ -0,0 +1,31 @@ +package org.hibernate.test.dialect.unit.lockhint; + +import junit.framework.TestSuite; + +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.SQLServerDialect; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class SQLServerLockHintsTest extends AbstractLockHintTest { + public static final Dialect DIALECT = new SQLServerDialect(); + + public SQLServerLockHintsTest(String string) { + super( string ); + } + + protected String getLockHintUsed() { + return "with (updlock, rowlock)"; + } + + protected Dialect getDialectUnderTest() { + return DIALECT; + } + + public static TestSuite suite() { + return new TestSuite( SQLServerLockHintsTest.class ); + } +} diff --git a/test/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java b/test/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java new file mode 100644 index 0000000000..0d21dc3559 --- /dev/null +++ b/test/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java @@ -0,0 +1,31 @@ +package org.hibernate.test.dialect.unit.lockhint; + +import junit.framework.TestSuite; + +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.SybaseDialect; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class SybaseLockHintsTest extends AbstractLockHintTest { + public static final Dialect DIALECT = new SybaseDialect(); + + public SybaseLockHintsTest(String string) { + super( string ); + } + + protected String getLockHintUsed() { + return "holdlock"; + } + + protected Dialect getDialectUnderTest() { + return DIALECT; + } + + public static TestSuite suite() { + return new TestSuite( SybaseLockHintsTest.class ); + } +} diff --git a/test/org/hibernate/test/discriminator/Address.java b/test/org/hibernate/test/discriminator/Address.java new file mode 100755 index 0000000000..7363ed9fba --- /dev/null +++ b/test/org/hibernate/test/discriminator/Address.java @@ -0,0 +1,11 @@ +//$Id$ +package org.hibernate.test.discriminator; + +/** + * @author Gavin King + */ +public class Address { + public String address; + public String zip; + public String country; +} diff --git a/test/org/hibernate/test/discriminator/Customer.java b/test/org/hibernate/test/discriminator/Customer.java new file mode 100755 index 0000000000..2c1bd953fe --- /dev/null +++ b/test/org/hibernate/test/discriminator/Customer.java @@ -0,0 +1,35 @@ +//$Id$ +package org.hibernate.test.discriminator; + +/** + * @author Gavin King + */ +public class Customer extends Person { + private Employee salesperson; + private String comments; + + /** + * @return Returns the salesperson. + */ + public Employee getSalesperson() { + return salesperson; + } + /** + * @param salesperson The salesperson to set. + */ + public void setSalesperson(Employee salesperson) { + this.salesperson = salesperson; + } + /** + * @return Returns the comments. + */ + public String getComments() { + return comments; + } + /** + * @param comments The comments to set. + */ + public void setComments(String comments) { + this.comments = comments; + } +} diff --git a/test/org/hibernate/test/discriminator/DiscriminatorTest.java b/test/org/hibernate/test/discriminator/DiscriminatorTest.java new file mode 100755 index 0000000000..583297c63b --- /dev/null +++ b/test/org/hibernate/test/discriminator/DiscriminatorTest.java @@ -0,0 +1,176 @@ +//$Id$ +package org.hibernate.test.discriminator; + +import java.math.BigDecimal; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.criterion.Property; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class DiscriminatorTest extends FunctionalTestCase { + + public DiscriminatorTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "discriminator/Person.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( DiscriminatorTest.class ); + } + + public void testDiscriminatorSubclass() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Employee mark = new Employee(); + mark.setName("Mark"); + mark.setTitle("internal sales"); + mark.setSex('M'); + mark.setAddress("buckhead"); + mark.setZip("30305"); + mark.setCountry("USA"); + + Customer joe = new Customer(); + joe.setName("Joe"); + joe.setAddress("San Francisco"); + joe.setZip("XXXXX"); + joe.setCountry("USA"); + joe.setComments("Very demanding"); + joe.setSex('M'); + joe.setSalesperson(mark); + + Person yomomma = new Person(); + yomomma.setName("mum"); + yomomma.setSex('F'); + + s.save(yomomma); + s.save(mark); + s.save(joe); + + assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 ); + + assertEquals( s.createQuery("from Person").list().size(), 3 ); + assertEquals( s.createQuery("from Person p where p.class = Person").list().size(), 1 ); + assertEquals( s.createQuery("from Person p where p.class = Customer").list().size(), 1 ); + s.clear(); + + List customers = s.createQuery("from Customer c left join fetch c.salesperson").list(); + for ( Iterator iter = customers.iterator(); iter.hasNext(); ) { + Customer c = (Customer) iter.next(); + assertTrue( Hibernate.isInitialized( c.getSalesperson() ) ); + assertEquals( c.getSalesperson().getName(), "Mark" ); + } + assertEquals( customers.size(), 1 ); + s.clear(); + + customers = s.createQuery("from Customer").list(); + for ( Iterator iter = customers.iterator(); iter.hasNext(); ) { + Customer c = (Customer) iter.next(); + assertFalse( Hibernate.isInitialized( c.getSalesperson() ) ); + assertEquals( c.getSalesperson().getName(), "Mark" ); + } + assertEquals( customers.size(), 1 ); + s.clear(); + + + mark = (Employee) s.get( Employee.class, new Long( mark.getId() ) ); + joe = (Customer) s.get( Customer.class, new Long( joe.getId() ) ); + + mark.setZip("30306"); + assertEquals( s.createQuery("from Person p where p.address.zip = '30306'").list().size(), 1 ); + s.delete(mark); + s.delete(joe); + s.delete(yomomma); + assertTrue( s.createQuery("from Person").list().isEmpty() ); + t.commit(); + s.close(); + } + + public void testAccessAsIncorrectSubclass() { + Session s = openSession(); + s.beginTransaction(); + Employee e = new Employee(); + e.setName( "Steve" ); + e.setSex( 'M' ); + e.setTitle( "grand poobah" ); + s.save( e ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + Customer c = ( Customer ) s.get( Customer.class, new Long( e.getId() ) ); + s.getTransaction().commit(); + s.close(); + assertNull( c ); + + s = openSession(); + s.beginTransaction(); + e = ( Employee ) s.get( Employee.class, new Long( e.getId() ) ); + c = ( Customer ) s.get( Customer.class, new Long( e.getId() ) ); + s.getTransaction().commit(); + s.close(); + assertNotNull( e ); + assertNull( c ); + + s = openSession(); + s.beginTransaction(); + s.delete( e ); + s.getTransaction().commit(); + s.close(); + } + + public void testQuerySubclassAttribute() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Person p = new Person(); + p.setName("Emmanuel"); + p.setSex('M'); + s.persist(p); + Employee q = new Employee(); + q.setName("Steve"); + q.setSex('M'); + q.setTitle("Mr"); + q.setSalary( new BigDecimal(1000) ); + s.persist(q); + + List result = s.createQuery("from Person where salary > 100").list(); + assertEquals( result.size(), 1 ); + assertSame( result.get(0), q ); + + result = s.createQuery("from Person where salary > 100 or name like 'E%'").list(); + assertEquals( result.size(), 2 ); + + result = s.createCriteria(Person.class) + .add( Property.forName("salary").gt( new BigDecimal(100) ) ) + .list(); + assertEquals( result.size(), 1 ); + assertSame( result.get(0), q ); + + //TODO: make this work: + /*result = s.createQuery("select salary from Person where salary > 100").list(); + assertEquals( result.size(), 1 ); + assertEquals( result.get(0), new BigDecimal(1000) );*/ + + s.delete(p); + s.delete(q); + t.commit(); + s.close(); + } + + +} + diff --git a/test/org/hibernate/test/discriminator/Employee.java b/test/org/hibernate/test/discriminator/Employee.java new file mode 100755 index 0000000000..8fc5b4da48 --- /dev/null +++ b/test/org/hibernate/test/discriminator/Employee.java @@ -0,0 +1,49 @@ +//$Id$ +package org.hibernate.test.discriminator; + +import java.math.BigDecimal; + +/** + * @author Gavin King + */ +public class Employee extends Person { + private String title; + private BigDecimal salary; + private Employee manager; + /** + * @return Returns the title. + */ + public String getTitle() { + return title; + } + /** + * @param title The title to set. + */ + public void setTitle(String title) { + this.title = title; + } + /** + * @return Returns the manager. + */ + public Employee getManager() { + return manager; + } + /** + * @param manager The manager to set. + */ + public void setManager(Employee manager) { + this.manager = manager; + } + /** + * @return Returns the salary. + */ + public BigDecimal getSalary() { + return salary; + } + /** + * @param salary The salary to set. + */ + public void setSalary(BigDecimal salary) { + this.salary = salary; + } +} diff --git a/test/org/hibernate/test/discriminator/Person.hbm.xml b/test/org/hibernate/test/discriminator/Person.hbm.xml new file mode 100755 index 0000000000..a0b70f6f7c --- /dev/null +++ b/test/org/hibernate/test/discriminator/Person.hbm.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/discriminator/Person.java b/test/org/hibernate/test/discriminator/Person.java new file mode 100755 index 0000000000..a00645a81a --- /dev/null +++ b/test/org/hibernate/test/discriminator/Person.java @@ -0,0 +1,70 @@ +//$Id$ +package org.hibernate.test.discriminator; + + +/** + * @author Gavin King + */ +public class Person { + private long id; + private String name; + private char sex; + private Address address = new Address(); + /** + * @return Returns the address. + */ + public Address getAddress() { + return address; + } + + public void setAddress(String string) { + this.address.address = string; + } + + public void setZip(String string) { + this.address.zip = string; + } + + public void setCountry(String string) { + this.address.country = string; + } + + + /** + * @return Returns the sex. + */ + public char getSex() { + return sex; + } + /** + * @param sex The sex to set. + */ + public void setSex(char sex) { + this.sex = sex; + } + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(long id) { + this.id = id; + } + /** + * @return Returns the identity. + */ + public String getName() { + return name; + } + /** + * @param identity The identity to set. + */ + public void setName(String identity) { + this.name = identity; + } + +} diff --git a/test/org/hibernate/test/dynamicentity/Address.java b/test/org/hibernate/test/dynamicentity/Address.java new file mode 100644 index 0000000000..2fb0eb1b74 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/Address.java @@ -0,0 +1,18 @@ +package org.hibernate.test.dynamicentity; + +/** + * @author Steve Ebersole + */ +public interface Address { + public Long getId(); + public void setId(Long id); + + public String getStreet(); + public void setStreet(String street); + + public String getCity(); + public void setCity(String city); + + public String getPostalCode(); + public void setPostalCode(String postalCode); +} diff --git a/test/org/hibernate/test/dynamicentity/Company.java b/test/org/hibernate/test/dynamicentity/Company.java new file mode 100644 index 0000000000..eaa30280bf --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/Company.java @@ -0,0 +1,11 @@ +package org.hibernate.test.dynamicentity; + +/** + * @author Steve Ebersole + */ +public interface Company { + public Long getId(); + public void setId(Long id); + public String getName(); + public void setName(String name); +} diff --git a/test/org/hibernate/test/dynamicentity/Customer.java b/test/org/hibernate/test/dynamicentity/Customer.java new file mode 100644 index 0000000000..66b41d063c --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/Customer.java @@ -0,0 +1,9 @@ +package org.hibernate.test.dynamicentity; + +/** + * @author Steve Ebersole + */ +public interface Customer extends Person { + public Company getCompany(); + public void setCompany(Company company); +} diff --git a/test/org/hibernate/test/dynamicentity/DataProxyHandler.java b/test/org/hibernate/test/dynamicentity/DataProxyHandler.java new file mode 100644 index 0000000000..1bdf55f0d4 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/DataProxyHandler.java @@ -0,0 +1,52 @@ +package org.hibernate.test.dynamicentity; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.io.Serializable; + +/** + * A simple {@link InvocationHandler} to act as the handler for our generated + * {@link java.lang.reflect.Proxy}-based entity instances. + *

+ * This is a trivial impl which simply keeps the property values into + * a Map. + * + * @author Steve Ebersole + */ +public final class DataProxyHandler implements InvocationHandler { + private String entityName; + private HashMap data = new HashMap(); + + public DataProxyHandler(String entityName, Serializable id) { + this.entityName = entityName; + data.put( "Id", id ); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.getName(); + if ( methodName.startsWith( "set" ) ) { + String propertyName = methodName.substring( 3 ); + data.put( propertyName, args[0] ); + } + else if ( methodName.startsWith( "get" ) ) { + String propertyName = methodName.substring( 3 ); + return data.get( propertyName ); + } + else if ( "toString".equals( methodName ) ) { + return entityName + "#" + data.get( "Id" ); + } + else if ( "hashCode".equals( methodName ) ) { + return new Integer( this.hashCode() ); + } + return null; + } + + public String getEntityName() { + return entityName; + } + + public HashMap getData() { + return data; + } +} diff --git a/test/org/hibernate/test/dynamicentity/DynamicEntitySuite.java b/test/org/hibernate/test/dynamicentity/DynamicEntitySuite.java new file mode 100644 index 0000000000..27c8ed8c70 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/DynamicEntitySuite.java @@ -0,0 +1,21 @@ +package org.hibernate.test.dynamicentity; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.test.dynamicentity.interceptor.InterceptorDynamicEntityTest; +import org.hibernate.test.dynamicentity.tuplizer.TuplizerDynamicEntityTest; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class DynamicEntitySuite { + public static Test suite() { + TestSuite suite = new TestSuite( "dynamic entity suite" ); + suite.addTest( InterceptorDynamicEntityTest.suite() ); + suite.addTest( TuplizerDynamicEntityTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/dynamicentity/Person.java b/test/org/hibernate/test/dynamicentity/Person.java new file mode 100644 index 0000000000..88ad64c7e1 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/Person.java @@ -0,0 +1,17 @@ +package org.hibernate.test.dynamicentity; + +import java.util.Set; + +/** + * @author Steve Ebersole + */ +public interface Person { + public Long getId(); + public void setId(Long id); + public String getName(); + public void setName(String name); + public Address getAddress(); + public void setAddress(Address address); + public Set getFamily(); + public void setFamily(Set family); +} diff --git a/test/org/hibernate/test/dynamicentity/ProxyHelper.java b/test/org/hibernate/test/dynamicentity/ProxyHelper.java new file mode 100644 index 0000000000..a392f679ac --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/ProxyHelper.java @@ -0,0 +1,73 @@ +package org.hibernate.test.dynamicentity; + +import java.io.Serializable; +import java.lang.reflect.Proxy; +import java.lang.reflect.InvocationHandler; + +/** + * @author Steve Ebersole + */ +public class ProxyHelper { + + public static Person newPersonProxy() { + return newPersonProxy( null ); + } + + public static Person newPersonProxy(Serializable id) { + return ( Person ) Proxy.newProxyInstance( + Person.class.getClassLoader(), + new Class[] {Person.class}, + new DataProxyHandler( Person.class.getName(), id ) + ); + } + + public static Customer newCustomerProxy() { + return newCustomerProxy( null ); + } + + public static Customer newCustomerProxy(Serializable id) { + return ( Customer ) Proxy.newProxyInstance( + Customer.class.getClassLoader(), + new Class[] {Customer.class}, + new DataProxyHandler( Customer.class.getName(), id ) + ); + } + + public static Company newCompanyProxy() { + return newCompanyProxy( null ); + } + + public static Company newCompanyProxy(Serializable id) { + return ( Company ) Proxy.newProxyInstance( + Company.class.getClassLoader(), + new Class[] {Company.class}, + new DataProxyHandler( Company.class.getName(), id ) + ); + } + + public static Address newAddressProxy() { + return newAddressProxy( null ); + } + + public static Address newAddressProxy(Serializable id) { + return ( Address ) Proxy.newProxyInstance( + Address.class.getClassLoader(), + new Class[] {Address.class}, + new DataProxyHandler( Address.class.getName(), id ) + ); + } + + public static String extractEntityName(Object object) { + // Our custom java.lang.reflect.Proxy instances actually bundle + // their appropriate entity name, so we simply extract it from there + // if this represents one of our proxies; otherwise, we return null + if ( Proxy.isProxyClass( object.getClass() ) ) { + InvocationHandler handler = Proxy.getInvocationHandler( object ); + if ( DataProxyHandler.class.isAssignableFrom( handler.getClass() ) ) { + DataProxyHandler myHandler = ( DataProxyHandler ) handler; + return myHandler.getEntityName(); + } + } + return null; + } +} diff --git a/test/org/hibernate/test/dynamicentity/interceptor/Customer.hbm.xml b/test/org/hibernate/test/dynamicentity/interceptor/Customer.hbm.xml new file mode 100644 index 0000000000..6f480ec837 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/interceptor/Customer.hbm.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/dynamicentity/interceptor/InterceptorDynamicEntityTest.java b/test/org/hibernate/test/dynamicentity/interceptor/InterceptorDynamicEntityTest.java new file mode 100644 index 0000000000..babdb3af5f --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/interceptor/InterceptorDynamicEntityTest.java @@ -0,0 +1,112 @@ +package org.hibernate.test.dynamicentity.interceptor; + +import junit.framework.TestSuite; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.dynamicentity.Company; +import org.hibernate.test.dynamicentity.Customer; +import org.hibernate.test.dynamicentity.ProxyHelper; + +/** + * Demonstrates custom interpretation of entity-name through + * an Interceptor. + *

+ * Here, we are generating dynamic + * {@link java.lang.reflect.Proxy proxies} on the fly to represent + * our entities. Because of this, Hibernate would not be able to + * determine the appropriate entity mapping to use given one of + * these proxies (they are named like $Proxy1, or such). Thus, we + * plug a custom Interceptor into the session to perform this + * entity-name interpretation. + * + * @see ProxyInterceptor + * + * @author Steve Ebersole + */ +public class InterceptorDynamicEntityTest extends FunctionalTestCase { + public InterceptorDynamicEntityTest(String x) { + super( x ); + } + + public String[] getMappings() { + return new String[] { "dynamicentity/interceptor/Customer.hbm.xml" }; + } + + public void configure(Configuration cfg) { + cfg.setInterceptor( new ProxyInterceptor() ); + } + + public static TestSuite suite() { + return new FunctionalTestClassTestSuite( InterceptorDynamicEntityTest.class ); + } + + public void testIt() { + // Test saving these dyna-proxies + Session session = openSession(); + session.beginTransaction(); + Company company = ProxyHelper.newCompanyProxy(); + company.setName( "acme" ); + session.save( company ); + Customer customer = ProxyHelper.newCustomerProxy(); + customer.setName( "Steve" ); + customer.setCompany( company ); + session.save( customer ); + session.getTransaction().commit(); + session.close(); + + assertNotNull( "company id not assigned", company.getId() ); + assertNotNull( "customer id not assigned", customer.getId() ); + + // Test loading these dyna-proxies, along with flush processing + session = openSession(); + session.beginTransaction(); + customer = ( Customer ) session.load( Customer.class, customer.getId() ); + assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer ) ); + + customer.setName( "other" ); + session.flush(); + assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer.getCompany() ) ); + + session.refresh( customer ); + assertEquals( "name not updated", "other", customer.getName() ); + assertEquals( "company association not correct", "acme", customer.getCompany().getName() ); + + session.getTransaction().commit(); + session.close(); + + // Test detached entity re-attachment with these dyna-proxies + customer.setName( "Steve" ); + session = openSession(); + session.beginTransaction(); + session.update( customer ); + session.flush(); + session.refresh( customer ); + assertEquals( "name not updated", "Steve", customer.getName() ); + session.getTransaction().commit(); + session.close(); + + // Test querying + session = openSession(); + session.beginTransaction(); + int count = session.createQuery( "from Customer" ).list().size(); + assertEquals( "querying dynamic entity", 1, count ); + session.clear(); + count = session.createQuery( "from Person" ).list().size(); + assertEquals( "querying dynamic entity", 1, count ); + session.getTransaction().commit(); + session.close(); + + // test deleteing + session = openSession(); + session.beginTransaction(); + session.delete( company ); + session.delete( customer ); + session.getTransaction().commit(); + session.close(); + } + +} diff --git a/test/org/hibernate/test/dynamicentity/interceptor/ProxyInterceptor.java b/test/org/hibernate/test/dynamicentity/interceptor/ProxyInterceptor.java new file mode 100644 index 0000000000..9533fec846 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/interceptor/ProxyInterceptor.java @@ -0,0 +1,61 @@ +package org.hibernate.test.dynamicentity.interceptor; + +import org.hibernate.EmptyInterceptor; +import org.hibernate.EntityMode; +import org.hibernate.test.dynamicentity.Company; +import org.hibernate.test.dynamicentity.Customer; +import org.hibernate.test.dynamicentity.ProxyHelper; +import org.hibernate.test.dynamicentity.DataProxyHandler; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; + +/** + * Our custom {@link org.hibernate.Interceptor} impl which performs the + * interpretation of entity-name -> proxy instance and vice-versa. + * + * @author Steve Ebersole + */ +public class ProxyInterceptor extends EmptyInterceptor { + + /** + * The callback from Hibernate to determine the entity name given + * a presumed entity instance. + * + * @param object The presumed entity instance. + * @return The entity name (pointing to the proper entity mapping). + */ + public String getEntityName(Object object) { + String entityName = ProxyHelper.extractEntityName( object ); + if ( entityName == null ) { + entityName = super.getEntityName( object ); + } + return entityName; + } + + /** + * The callback from Hibernate in order to build an instance of the + * entity represented by the given entity name. Here, we build a + * {@link Proxy} representing the entity. + * + * @param entityName The entity name for which to create an instance. In our setup, + * this is the interface name. + * @param entityMode The entity mode in which to create an instance. Here, we are only + * interestes in custom behavior for the POJO entity mode. + * @param id The identifier value for the given entity. + * @return The instantiated instance. + */ + public Object instantiate(String entityName, EntityMode entityMode, Serializable id) { + if ( entityMode == EntityMode.POJO ) { + if ( Customer.class.getName().equals( entityName ) ) { + return ProxyHelper.newCustomerProxy( id ); + } + else if ( Company.class.getName().equals( entityName ) ) { + return ProxyHelper.newCompanyProxy( id ); + } + } + return super.instantiate( entityName, entityMode, id ); + } + +} diff --git a/test/org/hibernate/test/dynamicentity/package.html b/test/org/hibernate/test/dynamicentity/package.html new file mode 100644 index 0000000000..c313e65c87 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/package.html @@ -0,0 +1,29 @@ + + + + +

+ Demonstration of different ways to use Hibernate to represent your domain + model as a series of JDK dynamic proxies. We map the interfaces and then + use one of two approaches to get Hibernate to recognize these proxies as + domain entities. Really this is demonstrating various "entity representation" + capabilities built in to Hibernate3. +

+

+ First we use an interceptor-based approach where we use a custom Interceptor + implementation for interpret incoming proxies (and resolve them to the correct + mappings) and to help Hibernate instantiate these proxy instances. This is the + quick-and-dirty approach. It is fully expected that this approach will + encounter certain limitations. +

+

+ Next we explore the notion of a Tuplizer and plug in custom Tuplizers to + help achieve the same results. Currently, Tuplizers do not have a chance + to influence the resolution of entity-name given a potential entity, so we + also use an Interceptor here and supply its getEntityName() impl. This is + simply so we do not need to supply the entity name explicitly to the + Hibernate Session calls. +

+ + + \ No newline at end of file diff --git a/test/org/hibernate/test/dynamicentity/tuplizer/Customer.hbm.xml b/test/org/hibernate/test/dynamicentity/tuplizer/Customer.hbm.xml new file mode 100644 index 0000000000..d85ec2ed46 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/tuplizer/Customer.hbm.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/dynamicentity/tuplizer/EntityNameInterceptor.java b/test/org/hibernate/test/dynamicentity/tuplizer/EntityNameInterceptor.java new file mode 100644 index 0000000000..3d495f1052 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/tuplizer/EntityNameInterceptor.java @@ -0,0 +1,24 @@ +package org.hibernate.test.dynamicentity.tuplizer; + +import org.hibernate.EmptyInterceptor; +import org.hibernate.test.dynamicentity.ProxyHelper; + +/** + * @author Steve Ebersole + */ +public class EntityNameInterceptor extends EmptyInterceptor { + /** + * The callback from Hibernate to determine the entity name given + * a presumed entity instance. + * + * @param object The presumed entity instance. + * @return The entity name (pointing to the proper entity mapping). + */ + public String getEntityName(Object object) { + String entityName = ProxyHelper.extractEntityName( object ); + if ( entityName == null ) { + entityName = super.getEntityName( object ); + } + return entityName; + } +} diff --git a/test/org/hibernate/test/dynamicentity/tuplizer/MyEntityInstantiator.java b/test/org/hibernate/test/dynamicentity/tuplizer/MyEntityInstantiator.java new file mode 100644 index 0000000000..e8a9a0dc3d --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/tuplizer/MyEntityInstantiator.java @@ -0,0 +1,67 @@ +package org.hibernate.test.dynamicentity.tuplizer; + +import org.hibernate.tuple.Instantiator; +import org.hibernate.test.dynamicentity.Customer; +import org.hibernate.test.dynamicentity.ProxyHelper; +import org.hibernate.test.dynamicentity.Company; +import org.hibernate.test.dynamicentity.DataProxyHandler; +import org.hibernate.test.dynamicentity.Address; +import org.hibernate.test.dynamicentity.Person; +import org.hibernate.util.ReflectHelper; +import org.hibernate.HibernateException; + +import java.io.Serializable; +import java.lang.reflect.Proxy; +import java.lang.reflect.InvocationHandler; + +/** + * @author Steve Ebersole + */ +public class MyEntityInstantiator implements Instantiator { + private final String entityName; + + public MyEntityInstantiator(String entityName) { + this.entityName = entityName; + } + + public Object instantiate(Serializable id) { + if ( Person.class.getName().equals( entityName ) ) { + return ProxyHelper.newPersonProxy( id ); + } + if ( Customer.class.getName().equals( entityName ) ) { + return ProxyHelper.newCustomerProxy( id ); + } + else if ( Company.class.getName().equals( entityName ) ) { + return ProxyHelper.newCompanyProxy( id ); + } + else if ( Address.class.getName().equals( entityName ) ) { + return ProxyHelper.newAddressProxy( id ); + } + else { + throw new IllegalArgumentException( "unknown entity for instantiation [" + entityName + "]" ); + } + } + + public Object instantiate() { + return instantiate( null ); + } + + public boolean isInstance(Object object) { + String resolvedEntityName = null; + if ( Proxy.isProxyClass( object.getClass() ) ) { + InvocationHandler handler = Proxy.getInvocationHandler( object ); + if ( DataProxyHandler.class.isAssignableFrom( handler.getClass() ) ) { + DataProxyHandler myHandler = ( DataProxyHandler ) handler; + resolvedEntityName = myHandler.getEntityName(); + } + } + try { + return ReflectHelper.classForName( entityName ).isInstance( object ); + } + catch( Throwable t ) { + throw new HibernateException( "could not get handle to entity-name as interface : " + t ); + } + +// return entityName.equals( resolvedEntityName ); + } +} diff --git a/test/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java b/test/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java new file mode 100644 index 0000000000..d01adc282a --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java @@ -0,0 +1,31 @@ +package org.hibernate.test.dynamicentity.tuplizer; + +import org.hibernate.tuple.entity.PojoEntityTuplizer; +import org.hibernate.tuple.entity.EntityMetamodel; +import org.hibernate.tuple.Instantiator; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.proxy.ProxyFactory; +import org.hibernate.property.Getter; +import org.hibernate.property.Setter; + +/** + * @author Steve Ebersole + */ +public class MyEntityTuplizer extends PojoEntityTuplizer { + + public MyEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) { + super( entityMetamodel, mappedEntity ); + } + + protected Instantiator buildInstantiator(PersistentClass persistentClass) { + return new MyEntityInstantiator( persistentClass.getEntityName() ); + } + + protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) { + // allows defining a custom proxy factory, which is responsible for + // generating lazy proxies for a given entity. + // + // Here we simply use the default... + return super.buildProxyFactory( persistentClass, idGetter, idSetter ); + } +} diff --git a/test/org/hibernate/test/dynamicentity/tuplizer/TuplizerDynamicEntityTest.java b/test/org/hibernate/test/dynamicentity/tuplizer/TuplizerDynamicEntityTest.java new file mode 100644 index 0000000000..4157c57479 --- /dev/null +++ b/test/org/hibernate/test/dynamicentity/tuplizer/TuplizerDynamicEntityTest.java @@ -0,0 +1,127 @@ +package org.hibernate.test.dynamicentity.tuplizer; + +import org.hibernate.test.TestCase; +import org.hibernate.test.dynamicentity.Company; +import org.hibernate.test.dynamicentity.ProxyHelper; +import org.hibernate.test.dynamicentity.Customer; +import org.hibernate.test.dynamicentity.Address; +import org.hibernate.test.dynamicentity.Person; +import org.hibernate.Session; +import org.hibernate.Hibernate; +import org.hibernate.cfg.Configuration; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +import junit.framework.TestSuite; + +import java.util.HashSet; + +/** + * Demonstrates use of Tuplizers to allow the use of JDK + * {@link java.lang.reflect.Proxy dynamic proxies} as our + * domain model. + *

+ * Here we plug a custom Interceptor into the session simply to + * allow us to not have to explicitly supply the appropriate entity + * name to the Session calls. + * + * @author Steve Ebersole + */ +public class TuplizerDynamicEntityTest extends FunctionalTestCase { + public TuplizerDynamicEntityTest(String x) { + super( x ); + } + + public String[] getMappings() { + return new String[] { "dynamicentity/tuplizer/Customer.hbm.xml" }; + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setInterceptor( new EntityNameInterceptor() ); + } + + public static TestSuite suite() { + return new FunctionalTestClassTestSuite( TuplizerDynamicEntityTest.class ); + } + + public void testIt() { + // Test saving these dyna-proxies + Session session = openSession(); + session.beginTransaction(); + Company company = ProxyHelper.newCompanyProxy(); + company.setName( "acme" ); + session.save( company ); + Customer customer = ProxyHelper.newCustomerProxy(); + customer.setName( "Steve" ); + customer.setCompany( company ); + Address address = ProxyHelper.newAddressProxy(); + address.setStreet( "somewhere over the rainbow" ); + address.setCity( "lawerence, kansas" ); + address.setPostalCode( "toto"); + customer.setAddress( address ); + customer.setFamily( new HashSet() ); + Person son = ProxyHelper.newPersonProxy(); + son.setName( "son" ); + customer.getFamily().add( son ); + Person wife = ProxyHelper.newPersonProxy(); + wife.setName( "wife" ); + customer.getFamily().add( wife ); + session.save( customer ); + session.getTransaction().commit(); + session.close(); + + assertNotNull( "company id not assigned", company.getId() ); + assertNotNull( "customer id not assigned", customer.getId() ); + assertNotNull( "address id not assigned", address.getId() ); + assertNotNull( "son:Person id not assigned", son.getId() ); + assertNotNull( "wife:Person id not assigned", wife.getId() ); + + // Test loading these dyna-proxies, along with flush processing + session = openSession(); + session.beginTransaction(); + customer = ( Customer ) session.load( Customer.class, customer.getId() ); + assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer ) ); + + customer.setName( "other" ); + session.flush(); + assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer.getCompany() ) ); + + session.refresh( customer ); + assertEquals( "name not updated", "other", customer.getName() ); + assertEquals( "company association not correct", "acme", customer.getCompany().getName() ); + + session.getTransaction().commit(); + session.close(); + + // Test detached entity re-attachment with these dyna-proxies + customer.setName( "Steve" ); + session = openSession(); + session.beginTransaction(); + session.update( customer ); + session.flush(); + session.refresh( customer ); + assertEquals( "name not updated", "Steve", customer.getName() ); + session.getTransaction().commit(); + session.close(); + + // Test querying + session = openSession(); + session.beginTransaction(); + int count = session.createQuery( "from Customer" ).list().size(); + assertEquals( "querying dynamic entity", 1, count ); + session.clear(); + count = session.createQuery( "from Person" ).list().size(); + assertEquals( "querying dynamic entity", 3, count ); + session.getTransaction().commit(); + session.close(); + + // test deleteing + session = openSession(); + session.beginTransaction(); + session.delete( company ); + session.delete( customer ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/ecid/Course.hbm.xml b/test/org/hibernate/test/ecid/Course.hbm.xml new file mode 100755 index 0000000000..a7ec6c570e --- /dev/null +++ b/test/org/hibernate/test/ecid/Course.hbm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/ecid/Course.java b/test/org/hibernate/test/ecid/Course.java new file mode 100755 index 0000000000..9cfe854c3b --- /dev/null +++ b/test/org/hibernate/test/ecid/Course.java @@ -0,0 +1,38 @@ +//$Id$ +package org.hibernate.test.ecid; + +import java.io.Serializable; + +/** + * @author Gavin King + */ +public class Course implements Serializable { + + private String courseCode; + private String org; + private String description; + + Course() {} + Course(String courseCode, String org, String description) { + this.courseCode = courseCode; + this.org = org; + this.description = description; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCourseCode() { + return courseCode; + } + + public String getOrg() { + return org; + } + +} diff --git a/test/org/hibernate/test/ecid/EmbeddedCompositeIdTest.java b/test/org/hibernate/test/ecid/EmbeddedCompositeIdTest.java new file mode 100755 index 0000000000..d99f44fdb3 --- /dev/null +++ b/test/org/hibernate/test/ecid/EmbeddedCompositeIdTest.java @@ -0,0 +1,162 @@ +//$Id$ +package org.hibernate.test.ecid; + +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.proxy.HibernateProxy; + +/** + * @author Gavin King + */ +public class EmbeddedCompositeIdTest extends FunctionalTestCase { + + public EmbeddedCompositeIdTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "ecid/Course.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( EmbeddedCompositeIdTest.class ); + } + + public void testMerge() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Course uc = new UniversityCourse("mat2000", "Monash", "second year maths", 0); + Course c = new Course("eng5000", "BHS", "grade 5 english"); + s.persist(uc); + s.persist(c); + t.commit(); + s.close(); + + c.setDescription("Grade 5 English"); + uc.setDescription("Second year mathematics"); + + s = openSession(); + t = s.beginTransaction(); + s.merge(c); + s.merge(uc); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete(c); + s.delete(uc); + t.commit(); + s.close(); + } + + public void testMerging() { + // Test HHH-799 + Session s = openSession(); + Transaction t = s.beginTransaction(); + Course course = new Course( "EN-101", "BA", "preparatory english" ); + s.persist( course ); + t.commit(); + s.close(); + + String newDesc = "basic preparatory english"; + course.setDescription( newDesc ); + + s = openSession(); + t = s.beginTransaction(); + Course c = (Course) s.merge( course ); + assertEquals( "description not merged", newDesc, c.getDescription() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Course cid = new Course( "EN-101", "BA", null ); + course = ( Course ) s.get( Course.class, cid ); + assertEquals( "description not merged", newDesc, course.getDescription() ); + s.delete( course ); + t.commit(); + s.close(); + } + + public void testPolymorphism() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Course uc = new UniversityCourse("mat2000", "Monash", "second year maths", 0); + Course c = new Course("eng5000", "BHS", "grade 5 english"); + s.persist(uc); + s.persist(c); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Course ucid = new Course("mat2000", "Monash", null); + Course cid = new Course("eng5000", "BHS", null); + Course luc = (Course) s.load(Course.class, ucid); + Course lc = (Course) s.load(Course.class, cid); + assertFalse( Hibernate.isInitialized(luc) ); + assertFalse( Hibernate.isInitialized(lc) ); + assertEquals( UniversityCourse.class, Hibernate.getClass(luc) ); + assertEquals( Course.class, Hibernate.getClass(lc) ); + assertSame( ( (HibernateProxy) lc ).getHibernateLazyInitializer().getImplementation(), cid ); + assertEquals( c.getCourseCode(), "eng5000" ); + assertEquals( uc.getCourseCode(), "mat2000" ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + ucid = new Course("mat2000", "Monash", null); + cid = new Course("eng5000", "BHS", null); + luc = (Course) s.get(Course.class, ucid); + lc = (Course) s.get(Course.class, cid); + assertTrue( Hibernate.isInitialized(luc) ); + assertTrue( Hibernate.isInitialized(lc) ); + assertEquals( UniversityCourse.class, Hibernate.getClass(luc) ); + assertEquals( Course.class, Hibernate.getClass(lc) ); + assertSame( lc, cid ); + assertEquals( c.getCourseCode(), "eng5000" ); + assertEquals( uc.getCourseCode(), "mat2000" ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + List list = s.createQuery("from Course order by courseCode").list(); + assertTrue( list.get(0) instanceof Course ); + assertTrue( list.get(1) instanceof UniversityCourse ); + c = (Course) list.get(0); + uc = (UniversityCourse) list.get(1); + assertEquals( c.getCourseCode(), "eng5000" ); + assertEquals( uc.getCourseCode(), "mat2000" ); + t.commit(); + s.close(); + + c.setDescription("Grade 5 English"); + uc.setDescription("Second year mathematics"); + + s = openSession(); + t = s.beginTransaction(); + s.saveOrUpdate(c); + s.saveOrUpdate(uc); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete(c); + s.delete(uc); + t.commit(); + s.close(); + + } +} + diff --git a/test/org/hibernate/test/ecid/UniversityCourse.java b/test/org/hibernate/test/ecid/UniversityCourse.java new file mode 100755 index 0000000000..00048d89a6 --- /dev/null +++ b/test/org/hibernate/test/ecid/UniversityCourse.java @@ -0,0 +1,22 @@ +//$Id$ +package org.hibernate.test.ecid; + +/** + * @author Gavin King + */ +public class UniversityCourse extends Course { + + private int semester; + + UniversityCourse() {} + + public UniversityCourse(String courseCode, String org, String description, int semester) { + super( courseCode, org, description ); + this.semester = semester; + } + + public int getSemester() { + return semester; + } + +} diff --git a/test/org/hibernate/test/entitymode/EntityModeSuite.java b/test/org/hibernate/test/entitymode/EntityModeSuite.java new file mode 100644 index 0000000000..7cb2b583a3 --- /dev/null +++ b/test/org/hibernate/test/entitymode/EntityModeSuite.java @@ -0,0 +1,23 @@ +package org.hibernate.test.entitymode; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.test.entitymode.dom4j.Dom4jSuite; +import org.hibernate.test.entitymode.map.MapSuite; +import org.hibernate.test.entitymode.multi.MultiRepresentationTest; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class EntityModeSuite { + public static Test suite() { + TestSuite suite = new TestSuite( "entity-mode tests" ); + suite.addTest( Dom4jSuite.suite() ); + suite.addTest( MapSuite.suite() ); + suite.addTest( MultiRepresentationTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/entitymode/dom4j/Dom4jSuite.java b/test/org/hibernate/test/entitymode/dom4j/Dom4jSuite.java new file mode 100644 index 0000000000..91b3390949 --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/Dom4jSuite.java @@ -0,0 +1,23 @@ +package org.hibernate.test.entitymode.dom4j; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.test.entitymode.dom4j.accessors.Dom4jAccessorTest; +import org.hibernate.test.entitymode.dom4j.basic.Dom4jTest; +import org.hibernate.test.entitymode.dom4j.many2one.Dom4jManyToOneTest; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Dom4jSuite { + public static Test suite() { + TestSuite suite = new TestSuite( "dom4j entity-mode suite" ); + suite.addTest( Dom4jAccessorTest.suite() ); + suite.addTest( Dom4jTest.suite() ); + suite.addTest( Dom4jManyToOneTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/entitymode/dom4j/accessors/Dom4jAccessorTest.java b/test/org/hibernate/test/entitymode/dom4j/accessors/Dom4jAccessorTest.java new file mode 100644 index 0000000000..32040e7b55 --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/accessors/Dom4jAccessorTest.java @@ -0,0 +1,157 @@ +// $Id: Dom4jAccessorTest.java 5821 2005-02-21 05:35:11Z oneovthafew $ +package org.hibernate.test.entitymode.dom4j.accessors; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.dom4j.DocumentFactory; +import org.dom4j.Element; +import org.dom4j.util.NodeComparator; + +import org.hibernate.EntityMode; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.SimpleValue; +import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessorFactory; +import org.hibernate.property.Setter; + +/** + * Unit test of dom4j-based accessors + * + * @author Steve Ebersole + */ +public class Dom4jAccessorTest extends TestCase { + + public static final Element DOM = generateTestElement(); + + public Dom4jAccessorTest(String name) { + super( name ); + } + + public void testStringElementExtraction() throws Throwable { + Property property = generateNameProperty(); + Getter getter = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.DOM4J ) + .getGetter( null, null ); + String name = ( String ) getter.get( DOM ); + assertEquals( "Not equals", "JBoss", name ); + } + + public void testStringTextExtraction() throws Throwable { + Property property = generateTextProperty(); + Getter getter = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.DOM4J ) + .getGetter( null, null ); + String name = ( String ) getter.get( DOM ); + assertEquals( "Not equals", "description...", name ); + } + + public void testLongAttributeExtraction() throws Throwable { + Property property = generateIdProperty(); + Getter getter = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.DOM4J ) + .getGetter( null, null ); + Long id = ( Long ) getter.get( DOM ); + assertEquals( "Not equals", new Long( 123 ), id ); + } + + public void testLongElementAttributeExtraction() throws Throwable { + Property property = generateAccountIdProperty(); + Getter getter = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.DOM4J ) + .getGetter( null, null ); + Long id = ( Long ) getter.get( DOM ); + assertEquals( "Not equals", new Long( 456 ), id ); + } + + public void testCompanyElementGeneration() throws Throwable { + Setter idSetter = PropertyAccessorFactory.getPropertyAccessor( generateIdProperty(), EntityMode.DOM4J ) + .getSetter( null, null ); + Setter nameSetter = PropertyAccessorFactory.getPropertyAccessor( generateNameProperty(), EntityMode.DOM4J ) + .getSetter( null, null ); + Setter textSetter = PropertyAccessorFactory.getPropertyAccessor( generateTextProperty(), EntityMode.DOM4J ) + .getSetter( null, null ); + Setter accountIdSetter = PropertyAccessorFactory.getPropertyAccessor( + generateAccountIdProperty(), EntityMode.DOM4J + ) + .getSetter( null, null ); + + Element root = generateRootTestElement(); + + idSetter.set( root, new Long( 123 ), getSFI() ); + textSetter.set( root, "description...", getSFI() ); + nameSetter.set( root, "JBoss", getSFI() ); + accountIdSetter.set( root, new Long( 456 ), getSFI() ); + + assertTrue( "DOMs not equal", new NodeComparator().compare( DOM, root ) == 0 ); + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + private static Element generateTestElement() { + Element company = generateRootTestElement(); + company.addAttribute( "id", "123" ); + company.setText( "description..." ); + company.addElement( "name" ).setText( "JBoss" ); + company.addElement( "account" ).addAttribute( "num", "456" ); + + return company; + } + + private static Element generateRootTestElement() { + return DocumentFactory.getInstance().createElement( "company" ); + } + + public static Test suite() { + return new TestSuite( Dom4jAccessorTest.class ); + } + + private SessionFactoryImplementor getSFI() { + return null; + } + + private Property generateIdProperty() { + SimpleValue value = new SimpleValue(); + value.setTypeName( "long" ); + + Property property = new Property(); + property.setName( "id" ); + property.setNodeName( "@id" ); + property.setValue( value ); + + return property; + } + + private Property generateTextProperty() { + SimpleValue value = new SimpleValue(); + value.setTypeName( "string" ); + + Property property = new Property(); + property.setName( "text" ); + property.setNodeName( "." ); + property.setValue( value ); + + return property; + } + + private Property generateAccountIdProperty() { + SimpleValue value = new SimpleValue(); + value.setTypeName( "long" ); + + Property property = new Property(); + property.setName( "number" ); + property.setNodeName( "account/@num" ); + property.setValue( value ); + + return property; + } + + private Property generateNameProperty() { + SimpleValue value = new SimpleValue(); + value.setTypeName( "string" ); + + Property property = new Property(); + property.setName( "name" ); + property.setNodeName( "name" ); + property.setValue( value ); + + return property; + } +} diff --git a/test/org/hibernate/test/entitymode/dom4j/basic/AB.hbm.xml b/test/org/hibernate/test/entitymode/dom4j/basic/AB.hbm.xml new file mode 100644 index 0000000000..9cffddf18f --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/basic/AB.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/entitymode/dom4j/basic/Account.hbm.xml b/test/org/hibernate/test/entitymode/dom4j/basic/Account.hbm.xml new file mode 100644 index 0000000000..40ca26fdff --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/basic/Account.hbm.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/entitymode/dom4j/basic/Dom4jTest.java b/test/org/hibernate/test/entitymode/dom4j/basic/Dom4jTest.java new file mode 100644 index 0000000000..56d81b56aa --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/basic/Dom4jTest.java @@ -0,0 +1,360 @@ +// $Id: Dom4jTest.java 9914 2006-05-09 04:37:18 -0500 (Tue, 09 May 2006) max.andersen@jboss.com $ +package org.hibernate.test.entitymode.dom4j.basic; + +import java.util.Map; + +import junit.framework.Test; +import org.dom4j.DocumentFactory; +import org.dom4j.Element; + +import org.hibernate.EntityMode; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.criterion.Example; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.transform.Transformers; +import org.hibernate.util.XMLHelper; + +/** + * @author Gavin King + */ +public class Dom4jTest extends FunctionalTestCase { + + public Dom4jTest(String str) { + super( str ); + } + + public String[] getMappings() { + return new String[] { + "entitymode/dom4j/basic/Account.hbm.xml", + "entitymode/dom4j/basic/AB.hbm.xml", + "entitymode/dom4j/basic/Employer.hbm.xml" + }; + } + + public void configure(Configuration cfg) { + cfg.setProperty( Environment.DEFAULT_ENTITY_MODE, EntityMode.DOM4J.toString() ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( Dom4jTest.class ); + } + +// TODO : still need to figure out inheritence support within the DOM4J entity-mode +// +// public void testSubtyping() throws Exception { +// Element employer = DocumentFactory.getInstance().createElement( "employer" ); +// employer.addAttribute( "name", "JBoss" ); +// Element gavin = employer.addElement( "techie" ); +// gavin.addAttribute( "name", "Gavin" ); +// Element ben = employer.addElement( "sales-dude" ); +// ben.addAttribute( "name", "Ben" ); +// print( employer ); +// +// Session s = openSession(); +// Transaction t = s.beginTransaction(); +// s.persist( "Employer", employer ); +// Long eid = new Long( employer.attributeValue( "id" ) ); +// t.commit(); +// s.close(); +// +// s = openSession(); +// t = s.beginTransaction(); +// employer = (Element) s.get( "Employer", eid ); +// print( employer ); +// s.delete( "Employer", employer ); +// t.commit(); +// s.close(); +// +// Element dept = DocumentFactory.getInstance().createElement( "department" ); +// dept.addAttribute( "name", "engineering" ); +// Element steve = dept.addElement( "manager" ).addElement( "techie" ); +// steve.addAttribute( "name", "Steve" ); +// print( dept ); +// +// s = openSession(); +// t = s.beginTransaction(); +// s.persist( "Department", dept ); +// Long did = new Long( dept.attributeValue( "id" ) ); +// t.commit(); +// s.close(); +// +// s = openSession(); +// t = s.beginTransaction(); +// dept = ( Element ) s.load( "Department", did ); +// print( dept ); +// s.delete( "Department", dept ); +// t.commit(); +// s.close(); +// } + + public void testCompositeId() throws Exception { + Element a = DocumentFactory.getInstance().createElement( "a" ); + a.addAttribute("id", "1"); + a.addElement("x").setText("foo bar"); + //Element bs = a.addElement("bs"); + Element b = a.addElement("b"); + //b.addElement("bId").setText("1"); + //b.addElement("aId").setText("1"); + b.addAttribute("bId", "1"); + b.addAttribute("aId", "1"); + b.setText("foo foo"); + b = a.addElement("b"); + //b.addElement("bId").setText("2"); + //b.addElement("aId").setText("1"); + b.addAttribute("bId", "2"); + b.addAttribute("aId", "1"); + b.setText("bar bar"); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist("A", a); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + a = (Element) s.createCriteria("A").uniqueResult(); + assertEquals( a.elements("b").size(), 2 ); + print(a); + s.delete("A", a); + t.commit(); + s.close(); + } + + public void testDom4j() throws Exception { + Element acct = DocumentFactory.getInstance().createElement( "account" ); + acct.addAttribute( "id", "abc123" ); + acct.addElement( "balance" ).setText( "123.45" ); + Element cust = acct.addElement( "customer" ); + cust.addAttribute( "id", "xyz123" ); + Element foo1 = cust.addElement( "stuff" ).addElement( "foo" ); + foo1.setText( "foo" ); + foo1.addAttribute("bar", "x"); + Element foo2 = cust.element( "stuff" ).addElement( "foo" ); + foo2.setText( "bar" ); + foo2.addAttribute("bar", "y"); + cust.addElement( "amount" ).setText( "45" ); + cust.setText( "An example customer" ); + Element name = cust.addElement( "name" ); + name.addElement( "first" ).setText( "Gavin" ); + name.addElement( "last" ).setText( "King" ); + + Element loc = DocumentFactory.getInstance().createElement( "location" ); + loc.addElement( "address" ).setText( "Karbarook Avenue" ); + + print( acct ); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist( "Location", loc ); + cust.addElement( "location" ).addAttribute( "id", loc.attributeValue( "id" ) ); + s.persist( "Account", acct ); + t.commit(); + s.close(); + + print( loc ); + + s = openSession(); + t = s.beginTransaction(); + cust = (Element) s.get( "Customer", "xyz123" ); + print( cust ); + acct = (Element) s.get( "Account", "abc123" ); + print( acct ); + assertEquals( acct.element( "customer" ), cust ); + cust.element( "name" ).element( "first" ).setText( "Gavin A" ); + Element foo3 = cust.element("stuff").addElement("foo"); + foo3.setText("baz"); + foo3.addAttribute("bar", "z"); + cust.element("amount").setText("3"); + cust.addElement("amount").setText("56"); + t.commit(); + s.close(); + + System.out.println(); + + acct.element( "balance" ).setText( "3456.12" ); + cust.addElement( "address" ).setText( "Karbarook Ave" ); + + assertEquals( acct.element( "customer" ), cust ); + + cust.setText( "Still the same example!" ); + + s = openSession(); + t = s.beginTransaction(); + s.saveOrUpdate( "Account", acct ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Element) s.get( "Customer", "xyz123" ); + print( cust ); + acct = (Element) s.get( "Account", "abc123" ); + print( acct ); + assertEquals( acct.element( "customer" ), cust ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Element) s.createCriteria( "Customer" ) + .add( Example.create( cust ) ) + .uniqueResult(); + print( cust ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + acct = (Element) s.createQuery( "from Account a left join fetch a.customer" ) + .uniqueResult(); + print( acct ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + Map m = (Map) s.createQuery( "select a as acc from Account a left join fetch a.customer" ) + .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).uniqueResult(); + acct = (Element)m.get("acc"); + print( acct ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + acct = (Element) s.createQuery( "from Account" ).uniqueResult(); + print( acct ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Element) s.createQuery( "from Customer c left join fetch c.stuff" ).uniqueResult(); + print( cust ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Element) s.createQuery( "from Customer c left join fetch c.morestuff" ).uniqueResult(); + print( cust ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Element) s.createQuery( "from Customer c left join fetch c.morestuff" ).uniqueResult(); + print( cust ); + cust = (Element) s.createQuery( "from Customer c left join fetch c.stuff" ).uniqueResult(); + print( cust ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Element) s.createQuery( "from Customer c left join fetch c.accounts" ).uniqueResult(); + Element a1 = cust.element( "accounts" ).addElement( "account" ); + a1.addElement( "balance" ).setText( "12.67" ); + a1.addAttribute( "id", "lkj345" ); + a1.addAttribute("acnum", "0"); + Element a2 = cust.element( "accounts" ).addElement( "account" ); + a2.addElement( "balance" ).setText( "10000.00" ); + a2.addAttribute( "id", "hsh987" ); + a2.addAttribute("acnum", "1"); + print( cust ); + t.commit(); + s.close(); + + System.out.println(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Element) s.createQuery( "from Customer c left join fetch c.accounts" ).uniqueResult(); + print( cust ); + t.commit(); + s.close(); + + // clean up + s = openSession(); + t = s.beginTransaction(); + s.delete( "Account", acct ); + s.delete( "Location", loc ); + s.createQuery( "delete from Account" ).executeUpdate(); + t.commit(); + s.close(); + } + + public void testMapIndexEmision() throws Throwable { + Element acct = DocumentFactory.getInstance().createElement( "account" ); + acct.addAttribute( "id", "abc123" ); + acct.addElement( "balance" ).setText( "123.45" ); + Element cust = acct.addElement( "customer" ); + cust.addAttribute( "id", "xyz123" ); + Element foo1 = cust.addElement( "stuff" ).addElement( "foo" ); + foo1.setText( "foo" ); + foo1.addAttribute("bar", "x"); + Element foo2 = cust.element( "stuff" ).addElement( "foo" ); + foo2.setText( "bar" ); + foo2.addAttribute("bar", "y"); + cust.addElement( "amount" ).setText( "45" ); + cust.setText( "An example customer" ); + Element name = cust.addElement( "name" ); + name.addElement( "first" ).setText( "Gavin" ); + name.addElement( "last" ).setText( "King" ); + + print( acct ); + + Element loc = DocumentFactory.getInstance().createElement( "location" ); + loc.addElement( "address" ).setText( "Karbarook Avenue" ); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist( "Location", loc ); + cust.addElement( "location" ).addAttribute( "id", loc.attributeValue( "id" ) ); + s.persist( "Account", acct ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + cust = ( Element ) s.get( "Customer", "xyz123" ); + print( cust ); + assertEquals( "Incorrect stuff-map size", 2, cust.element( "stuff" ).elements( "foo" ).size() ); + Element stuffElement = ( Element ) cust.element( "stuff" ).elements( "foo" ).get( 0 ); + assertNotNull( "No map-key value present", stuffElement.attribute( "bar" ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete( "Account", acct ); + s.delete( "Location", loc ); + t.commit(); + s.close(); + } + + public static void print(Element elt) throws Exception { + XMLHelper.dump( elt ); + } +} diff --git a/test/org/hibernate/test/entitymode/dom4j/basic/Employer.hbm.xml b/test/org/hibernate/test/entitymode/dom4j/basic/Employer.hbm.xml new file mode 100644 index 0000000000..bf0015e115 --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/basic/Employer.hbm.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/entitymode/dom4j/many2one/Car.hbm.xml b/test/org/hibernate/test/entitymode/dom4j/many2one/Car.hbm.xml new file mode 100644 index 0000000000..b30915a3e3 --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/many2one/Car.hbm.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/entitymode/dom4j/many2one/Car.java b/test/org/hibernate/test/entitymode/dom4j/many2one/Car.java new file mode 100644 index 0000000000..1d2bf477d2 --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/many2one/Car.java @@ -0,0 +1,58 @@ +package org.hibernate.test.entitymode.dom4j.many2one; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Paco Hernández + */ +public class Car implements java.io.Serializable { + + private long id; + private String model; + private CarType carType; + private Set carParts = new HashSet(); + + /** + * @return Returns the carType. + */ + public CarType getCarType() { + return carType; + } + /** + * @param carType The carType to set. + */ + public void setCarType(CarType carType) { + this.carType = carType; + } + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(long id) { + this.id = id; + } + /** + * @return Returns the model. + */ + public String getModel() { + return model; + } + /** + * @param model The model to set. + */ + public void setModel(String model) { + this.model = model; + } + public Set getCarParts() { + return carParts; + } + public void setCarParts(Set carParts) { + this.carParts = carParts; + } +} diff --git a/test/org/hibernate/test/entitymode/dom4j/many2one/CarPart.java b/test/org/hibernate/test/entitymode/dom4j/many2one/CarPart.java new file mode 100644 index 0000000000..dda9a5775e --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/many2one/CarPart.java @@ -0,0 +1,35 @@ +package org.hibernate.test.entitymode.dom4j.many2one; + +/** + * @author Paco Hernández + */ +public class CarPart implements java.io.Serializable { + + private long id; + private String partName; + + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(long id) { + this.id = id; + } + /** + * @return Returns the typeName. + */ + public String getPartName() { + return partName; + } + /** + * @param typeName The typeName to set. + */ + public void setPartName(String typeName) { + this.partName = typeName; + } +} diff --git a/test/org/hibernate/test/entitymode/dom4j/many2one/CarType.java b/test/org/hibernate/test/entitymode/dom4j/many2one/CarType.java new file mode 100644 index 0000000000..9368725080 --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/many2one/CarType.java @@ -0,0 +1,35 @@ +package org.hibernate.test.entitymode.dom4j.many2one; + +/** + * @author Paco Hernández + */ +public class CarType implements java.io.Serializable { + + private long id; + private String typeName; + + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(long id) { + this.id = id; + } + /** + * @return Returns the typeName. + */ + public String getTypeName() { + return typeName; + } + /** + * @param typeName The typeName to set. + */ + public void setTypeName(String typeName) { + this.typeName = typeName; + } +} diff --git a/test/org/hibernate/test/entitymode/dom4j/many2one/Dom4jManyToOneTest.java b/test/org/hibernate/test/entitymode/dom4j/many2one/Dom4jManyToOneTest.java new file mode 100644 index 0000000000..98ae043043 --- /dev/null +++ b/test/org/hibernate/test/entitymode/dom4j/many2one/Dom4jManyToOneTest.java @@ -0,0 +1,141 @@ +package org.hibernate.test.entitymode.dom4j.many2one; + +import java.util.List; + +import junit.framework.Test; +import org.dom4j.Element; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; + +import org.hibernate.EntityMode; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Paco Hernández + */ +public class Dom4jManyToOneTest extends FunctionalTestCase { + + public Dom4jManyToOneTest(String str) { + super( str ); + } + + public String[] getMappings() { + return new String[] { "entitymode/dom4j/many2one/Car.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( Dom4jManyToOneTest.class ); + } + + public void testDom4jOneToMany() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + CarType carType = new CarType(); + carType.setTypeName("Type 1"); + s.save(carType); + + Car car = new Car(); + car.setCarType(carType); + car.setModel("Model 1"); + s.save(car); + + CarPart carPart1 = new CarPart(); + carPart1.setPartName("chassis"); + car.getCarParts().add(carPart1); + + t.commit(); + s.close(); + + s = openSession(); + Session dom4jSession = s.getSession( EntityMode.DOM4J ); + t = s.beginTransaction(); + + Element element = (Element) dom4jSession.createQuery( "from Car c join fetch c.carParts" ).uniqueResult(); + + String expectedResult = "" + + carPart1.getId() + + "Model 1Type 1"; + + print(element); + assertTrue(element.asXML().equals(expectedResult)); + + s.createQuery("delete from CarPart").executeUpdate(); + s.createQuery("delete from Car").executeUpdate(); + s.createQuery("delete from CarType").executeUpdate(); + + t.commit(); + s.close(); + } + + public void testDom4jManyToOne() throws Exception { + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + CarType carType = new CarType(); + carType.setTypeName("Type 1"); + s.save(carType); + + Car car1 = new Car(); + car1.setCarType(carType); + car1.setModel("Model 1"); + s.save(car1); + + Car car2 = new Car(); + car2.setCarType(carType); + car2.setModel("Model 2"); + s.save(car2); + + t.commit(); + s.close(); + + s = openSession(); + Session dom4jSession = s.getSession( EntityMode.DOM4J ); + t = s.beginTransaction(); + + List list = dom4jSession.createQuery( "from Car c join fetch c.carType order by c.model asc" ).list(); + + String[] expectedResults = new String[] { + "Model 1Type 1", + "Model 2Type 1" + }; + + for (int i = 0; i < list.size(); i++) { + Element element = (Element) list.get(i); + + print(element); + assertTrue(element.asXML().equals(expectedResults[i])); + } + + s.createQuery("delete from Car").executeUpdate(); + s.createQuery("delete from CarType").executeUpdate(); + + t.commit(); + s.close(); + } + + public static void print(Element elt) throws Exception { + OutputFormat outformat = OutputFormat.createPrettyPrint(); + // outformat.setEncoding(aEncodingScheme); + XMLWriter writer = new XMLWriter( System.out, outformat ); + writer.write( elt ); + writer.flush(); + // System.out.println( elt.asXML() ); + } +} diff --git a/test/org/hibernate/test/entitymode/map/MapSuite.java b/test/org/hibernate/test/entitymode/map/MapSuite.java new file mode 100644 index 0000000000..f8840ebf12 --- /dev/null +++ b/test/org/hibernate/test/entitymode/map/MapSuite.java @@ -0,0 +1,19 @@ +package org.hibernate.test.entitymode.map; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.test.entitymode.map.basic.DynamicClassTest; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class MapSuite { + public static Test suite() { + TestSuite suite = new TestSuite( "map entity-mode suite"); + suite.addTest( DynamicClassTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/entitymode/map/basic/DynamicClassTest.java b/test/org/hibernate/test/entitymode/map/basic/DynamicClassTest.java new file mode 100644 index 0000000000..db109c73a7 --- /dev/null +++ b/test/org/hibernate/test/entitymode/map/basic/DynamicClassTest.java @@ -0,0 +1,109 @@ +//$Id: DynamicClassTest.java 9024 2006-01-11 22:38:24Z steveebersole $ +package org.hibernate.test.entitymode.map.basic; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import junit.framework.Test; + +import org.hibernate.EntityMode; +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class DynamicClassTest extends FunctionalTestCase { + + public DynamicClassTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "entitymode/map/basic/ProductLine.hbm.xml" }; + } + + public void configure(Configuration cfg) { + cfg.setProperty(Environment.DEFAULT_ENTITY_MODE, EntityMode.MAP.toString()); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( DynamicClassTest.class ); + } + + public void testLazyDynamicClass() { + Session s = openSession(); + assertTrue( "Incorrectly handled default_entity_mode", s.getEntityMode() == EntityMode.MAP ); + Session other = s.getSession( EntityMode.MAP ); + assertEquals( "openSession() using same entity-mode returned new session", s, other ); + + other = s.getSession( EntityMode.POJO ); + other.close(); + assertTrue( !other.isOpen() ); +// this is no longer allowed since the session does much more up-front closed checking +// assertTrue( other.isConnected() ); // because it is linked to the "root" session's connection + + s.close(); + + s = openSession(); + Transaction t = s.beginTransaction(); + + Map cars = new HashMap(); + cars.put("description", "Cars"); + Map monaro = new HashMap(); + monaro.put("productLine", cars); + monaro.put("name", "monaro"); + monaro.put("description", "Holden Monaro"); + Map hsv = new HashMap(); + hsv.put("productLine", cars); + hsv.put("name", "hsv"); + hsv.put("description", "Holden Commodore HSV"); + List models = new ArrayList(); + cars.put("models", models); + models.add(hsv); + models.add(monaro); + s.save("ProductLine", cars); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + + cars = (Map) s.createQuery("from ProductLine pl order by pl.description").uniqueResult(); + models = (List) cars.get("models"); + assertFalse( Hibernate.isInitialized(models) ); + assertEquals( models.size(), 2); + assertTrue( Hibernate.isInitialized(models) ); + + s.clear(); + + List list = s.createQuery("from Model m").list(); + for ( Iterator i=list.iterator(); i.hasNext(); ) { + assertFalse( Hibernate.isInitialized( ( (Map) i.next() ).get("productLine") ) ); + } + Map model = (Map) list.get(0); + assertTrue( ( (List) ( (Map) model.get("productLine") ).get("models") ).contains(model) ); + s.clear(); + + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + cars = (Map) s.createQuery("from ProductLine pl order by pl.description").uniqueResult(); + s.delete(cars); + t.commit(); + s.close(); + } + + +} + diff --git a/test/org/hibernate/test/entitymode/map/basic/ProductLine.hbm.xml b/test/org/hibernate/test/entitymode/map/basic/ProductLine.hbm.xml new file mode 100644 index 0000000000..063539d101 --- /dev/null +++ b/test/org/hibernate/test/entitymode/map/basic/ProductLine.hbm.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/entitymode/multi/MultiRepresentationTest.java b/test/org/hibernate/test/entitymode/multi/MultiRepresentationTest.java new file mode 100644 index 0000000000..48e0057ec4 --- /dev/null +++ b/test/org/hibernate/test/entitymode/multi/MultiRepresentationTest.java @@ -0,0 +1,194 @@ +// $Id: MultiRepresentationTest.java 6300 2005-04-03 04:24:23Z oneovthafew $ +package org.hibernate.test.entitymode.multi; + +import java.sql.Date; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.dom4j.DocumentFactory; +import org.dom4j.Element; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; + +import org.hibernate.EntityMode; +import org.hibernate.Transaction; +import org.hibernate.classic.Session; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Implementation of MultiRepresentationTest. + * + * @author Steve Ebersole + */ +public class MultiRepresentationTest extends FunctionalTestCase { + + + public MultiRepresentationTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "entitymode/multi/Stock.hbm.xml", "entitymode/multi/Valuation.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( MultiRepresentationTest.class ); + } + + public void testPojoRetreival() { + TestData testData = new TestData(); + testData.create(); + + Session session = openSession(); + Transaction txn = session.beginTransaction(); + + Stock stock = ( Stock ) session.get( Stock.class, new Long( 1 ) ); + assertEquals( "Something wrong!", new Long( 1 ), stock.getId() ); + + txn.commit(); + session.close(); + + testData.destroy(); + } + + public void testDom4jRetreival() { + TestData testData = new TestData(); + testData.create(); + + Session session = openSession(); + Transaction txn = session.beginTransaction(); + org.hibernate.Session dom4j = session.getSession( EntityMode.DOM4J ); + + Object rtn = dom4j.get( Stock.class.getName(), testData.stockId ); + Element element = ( Element ) rtn; + + assertEquals( "Something wrong!", testData.stockId, Long.valueOf( element.attributeValue( "id" ) ) ); + + System.out.println( "**** XML: ****************************************************" ); + prettyPrint( element ); + System.out.println( "**************************************************************" ); + + Element currVal = element.element( "currentValuation" ); + + System.out.println( "**** XML: ****************************************************" ); + prettyPrint( currVal ); + System.out.println( "**************************************************************" ); + + txn.rollback(); + session.close(); + + testData.destroy(); + } + + public void testDom4jSave() { + TestData testData = new TestData(); + testData.create(); + + Session pojos = openSession(); + Transaction txn = pojos.beginTransaction(); + org.hibernate.Session dom4j = pojos.getSession( EntityMode.DOM4J ); + + Element stock = DocumentFactory.getInstance().createElement( "stock" ); + stock.addElement( "tradeSymbol" ).setText( "IBM" ); + + Element val = stock.addElement( "currentValuation" ).addElement( "valuation" ); + val.appendContent( stock ); + val.addElement( "valuationDate" ).setText( new java.util.Date().toString() ); + val.addElement( "value" ).setText( "121.00" ); + + dom4j.save( Stock.class.getName(), stock ); + dom4j.flush(); + + txn.rollback(); + pojos.close(); + + assertTrue( !pojos.isOpen() ); + assertTrue( !dom4j.isOpen() ); + + prettyPrint( stock ); + + testData.destroy(); + } + + public void testDom4jHQL() { + TestData testData = new TestData(); + testData.create(); + + Session session = openSession(); + Transaction txn = session.beginTransaction(); + org.hibernate.Session dom4j = session.getSession( EntityMode.DOM4J ); + + List result = dom4j.createQuery( "from Stock" ).list(); + + assertEquals( "Incorrect result size", 1, result.size() ); + Element element = ( Element ) result.get( 0 ); + assertEquals( "Something wrong!", testData.stockId, Long.valueOf( element.attributeValue( "id" ) ) ); + + System.out.println( "**** XML: ****************************************************" ); + prettyPrint( element ); + System.out.println( "**************************************************************" ); + + txn.rollback(); + session.close(); + + testData.destroy(); + } + + private class TestData { + private Long stockId; + + private void create() { + Session session = getSessions().openSession(); + session.beginTransaction(); + Stock stock = new Stock(); + stock.setTradeSymbol( "JBOSS" ); + Valuation valuation = new Valuation(); + valuation.setStock( stock ); + valuation.setValuationDate( new Date( new java.util.Date().getTime() ) ); + valuation.setValue( new Double( 200.0 ) ); + stock.setCurrentValuation( valuation ); + stock.getValuations().add( valuation ); + + session.save( stock ); + session.save( valuation ); + + session.getTransaction().commit(); + session.close(); + + stockId = stock.getId(); + } + + private void destroy() { + Session session = getSessions().openSession(); + session.beginTransaction(); + Iterator stocks = session.createQuery( "from Stock" ).list().iterator(); + while ( stocks.hasNext() ) { + final Stock stock = ( Stock ) stocks.next(); + stock.setCurrentValuation( null ); + session.flush(); + Iterator valuations = stock.getValuations().iterator(); + while ( valuations.hasNext() ) { + session.delete( valuations.next() ); + } + session.delete( stock ); + } + session.getTransaction().commit(); + session.close(); + } + } + + private void prettyPrint(Element element) { + //System.out.println( element.asXML() ); + try { + OutputFormat format = OutputFormat.createPrettyPrint(); + new XMLWriter( System.out, format ).write( element ); + System.out.println(); + } + catch ( Throwable t ) { + System.err.println( "Unable to pretty print element : " + t ); + } + } +} diff --git a/test/org/hibernate/test/entitymode/multi/Stock.hbm.xml b/test/org/hibernate/test/entitymode/multi/Stock.hbm.xml new file mode 100644 index 0000000000..8bf583c1c8 --- /dev/null +++ b/test/org/hibernate/test/entitymode/multi/Stock.hbm.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/entitymode/multi/Stock.java b/test/org/hibernate/test/entitymode/multi/Stock.java new file mode 100644 index 0000000000..25450f2045 --- /dev/null +++ b/test/org/hibernate/test/entitymode/multi/Stock.java @@ -0,0 +1,49 @@ +// $Id: Stock.java 5686 2005-02-12 07:27:32Z steveebersole $ +package org.hibernate.test.entitymode.multi; + +import java.util.Set; +import java.util.HashSet; + +/** + * POJO implementation of Stock entity. + * + * @author Steve Ebersole + */ +public class Stock { + private Long id; + private String tradeSymbol; + private Valuation currentValuation; + private Set valuations = new HashSet(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTradeSymbol() { + return tradeSymbol; + } + + public void setTradeSymbol(String tradeSymbol) { + this.tradeSymbol = tradeSymbol; + } + + public Valuation getCurrentValuation() { + return currentValuation; + } + + public void setCurrentValuation(Valuation currentValuation) { + this.currentValuation = currentValuation; + } + + public Set getValuations() { + return valuations; + } + + public void setValuations(Set valuations) { + this.valuations = valuations; + } +} diff --git a/test/org/hibernate/test/entitymode/multi/Valuation.hbm.xml b/test/org/hibernate/test/entitymode/multi/Valuation.hbm.xml new file mode 100644 index 0000000000..c365729566 --- /dev/null +++ b/test/org/hibernate/test/entitymode/multi/Valuation.hbm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/entitymode/multi/Valuation.java b/test/org/hibernate/test/entitymode/multi/Valuation.java new file mode 100644 index 0000000000..43b1eb6f38 --- /dev/null +++ b/test/org/hibernate/test/entitymode/multi/Valuation.java @@ -0,0 +1,48 @@ +// $Id: Valuation.java 5686 2005-02-12 07:27:32Z steveebersole $ +package org.hibernate.test.entitymode.multi; + +import java.util.Date; + +/** + * Implementation of Valuation. + * + * @author Steve Ebersole + */ +public class Valuation { + private Long id; + private Stock stock; + private Date valuationDate; + private Double value; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Stock getStock() { + return stock; + } + + public void setStock(Stock stock) { + this.stock = stock; + } + + public Date getValuationDate() { + return valuationDate; + } + + public void setValuationDate(Date valuationDate) { + this.valuationDate = valuationDate; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } +} diff --git a/test/org/hibernate/test/exception/Group.hbm.xml b/test/org/hibernate/test/exception/Group.hbm.xml new file mode 100644 index 0000000000..bafa14d439 --- /dev/null +++ b/test/org/hibernate/test/exception/Group.hbm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/exception/Group.java b/test/org/hibernate/test/exception/Group.java new file mode 100644 index 0000000000..b00ddeaef7 --- /dev/null +++ b/test/org/hibernate/test/exception/Group.java @@ -0,0 +1,48 @@ +// $Id$ +package org.hibernate.test.exception; + +import java.util.Set; + +/** + * Implementation of Group. + * + * @author Steve Ebersole + */ +public class Group { + private Long id; + private String name; + private Set members; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getMembers() { + return members; + } + + public void setMembers(Set members) { + this.members = members; + } + + public void addMember(User member) { + if (member == null) { + throw new IllegalArgumentException("Member to add cannot be null"); + } + + this.members.add(member); + member.getMemberships().add(this); + } +} diff --git a/test/org/hibernate/test/exception/SQLExceptionConversionTest.java b/test/org/hibernate/test/exception/SQLExceptionConversionTest.java new file mode 100644 index 0000000000..941d2eb55b --- /dev/null +++ b/test/org/hibernate/test/exception/SQLExceptionConversionTest.java @@ -0,0 +1,114 @@ +// $Id$ +package org.hibernate.test.exception; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import junit.framework.Test; + +import org.hibernate.JDBCException; +import org.hibernate.Session; +import org.hibernate.dialect.MySQLMyISAMDialect; +import org.hibernate.exception.ConstraintViolationException; +import org.hibernate.exception.SQLExceptionConverter; +import org.hibernate.exception.SQLGrammarException; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.util.JDBCExceptionReporter; + +/** + * Implementation of SQLExceptionConversionTest. + * + * @author Steve Ebersole + */ +public class SQLExceptionConversionTest extends FunctionalTestCase { + + public SQLExceptionConversionTest(String name) { + super(name); + } + + public String[] getMappings() { + return new String[] {"exception/User.hbm.xml", "exception/Group.hbm.xml"}; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite(SQLExceptionConversionTest.class); + } + + public void testIntegrityViolation() throws Exception { + if ( getDialect() instanceof MySQLMyISAMDialect ) { + reportSkip( "MySQL (ISAM) does not support FK violation checking", "exception conversion" ); + return; + } + + SQLExceptionConverter converter = getDialect().buildSQLExceptionConverter(); + + Session session = openSession(); + session.beginTransaction(); + Connection connection = session.connection(); + + // Attempt to insert some bad values into the T_MEMBERSHIP table that should + // result in a constraint violation + PreparedStatement ps = null; + try { + ps = connection.prepareStatement("INSERT INTO T_MEMBERSHIP (user_id, group_id) VALUES (?, ?)"); + ps.setLong(1, 52134241); // Non-existent user_id + ps.setLong(2, 5342); // Non-existent group_id + ps.executeUpdate(); + + fail("INSERT should have failed"); + } + catch(SQLException sqle) { + JDBCExceptionReporter.logExceptions(sqle, "Just output!!!!"); + JDBCException jdbcException = converter.convert(sqle, null, null); + assertEquals( "Bad conversion [" + sqle.getMessage() + "]", ConstraintViolationException.class , jdbcException.getClass() ); + ConstraintViolationException ex = (ConstraintViolationException) jdbcException; + System.out.println("Violated constraint name: " + ex.getConstraintName()); + } + finally { + if ( ps != null ) { + try { + ps.close(); + } + catch( Throwable ignore ) { + // ignore... + } + } + } + + session.getTransaction().rollback(); + session.close(); + } + + public void testBadGrammar() throws Exception { + SQLExceptionConverter converter = getDialect().buildSQLExceptionConverter(); + + Session session = openSession(); + Connection connection = session.connection(); + + // prepare/execute a query against a non-existent table + PreparedStatement ps = null; + try { + ps = connection.prepareStatement("SELECT user_id, user_name FROM tbl_no_there"); + ps.executeQuery(); + + fail("SQL compilation should have failed"); + } + catch( SQLException sqle ) { + assertEquals( "Bad conversion [" + sqle.getMessage() + "]", SQLGrammarException.class, converter.convert(sqle, null, null).getClass() ); + } + finally { + if ( ps != null ) { + try { + ps.close(); + } + catch( Throwable ignore ) { + // ignore... + } + } + } + + session.close(); + } +} diff --git a/test/org/hibernate/test/exception/User.hbm.xml b/test/org/hibernate/test/exception/User.hbm.xml new file mode 100644 index 0000000000..3dab330753 --- /dev/null +++ b/test/org/hibernate/test/exception/User.hbm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/exception/User.java b/test/org/hibernate/test/exception/User.java new file mode 100644 index 0000000000..9419154ddd --- /dev/null +++ b/test/org/hibernate/test/exception/User.java @@ -0,0 +1,49 @@ +// $Id$ +package org.hibernate.test.exception; + +import java.util.Set; +import java.util.HashSet; + +/** + * Implementation of User. + * + * @author Steve Ebersole + */ +public class User { + private Long id; + private String username; + private Set memberships = new HashSet(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Set getMemberships() { + return memberships; + } + + public void setMemberships(Set memberships) { + this.memberships = memberships; + } + + public void addMembership(Group membership) { + if (membership == null) { + throw new IllegalArgumentException("Membership to add cannot be null"); + } + + this.memberships.add(membership); + membership.getMembers().add(this); + } +} diff --git a/test/org/hibernate/test/extendshbm/Customer.hbm.xml b/test/org/hibernate/test/extendshbm/Customer.hbm.xml new file mode 100644 index 0000000000..cb672f7c69 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/Customer.hbm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/extendshbm/Customer.java b/test/org/hibernate/test/extendshbm/Customer.java new file mode 100644 index 0000000000..5715b1d478 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/Customer.java @@ -0,0 +1,35 @@ +//$Id$ +package org.hibernate.test.extendshbm; + +/** + * @author Gavin King + */ +public class Customer extends Person { + private Employee salesperson; + private String comments; + + /** + * @return Returns the salesperson. + */ + public Employee getSalesperson() { + return salesperson; + } + /** + * @param salesperson The salesperson to set. + */ + public void setSalesperson(Employee salesperson) { + this.salesperson = salesperson; + } + /** + * @return Returns the comments. + */ + public String getComments() { + return comments; + } + /** + * @param comments The comments to set. + */ + public void setComments(String comments) { + this.comments = comments; + } +} diff --git a/test/org/hibernate/test/extendshbm/Employee.hbm.xml b/test/org/hibernate/test/extendshbm/Employee.hbm.xml new file mode 100644 index 0000000000..f013648923 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/Employee.hbm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/extendshbm/Employee.java b/test/org/hibernate/test/extendshbm/Employee.java new file mode 100644 index 0000000000..4e9a354ab3 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/Employee.java @@ -0,0 +1,49 @@ +//$Id$ +package org.hibernate.test.extendshbm; + +import java.math.BigDecimal; + +/** + * @author Gavin King + */ +public class Employee extends Person { + private String title; + private BigDecimal salary; + private Employee manager; + /** + * @return Returns the title. + */ + public String getTitle() { + return title; + } + /** + * @param title The title to set. + */ + public void setTitle(String title) { + this.title = title; + } + /** + * @return Returns the manager. + */ + public Employee getManager() { + return manager; + } + /** + * @param manager The manager to set. + */ + public void setManager(Employee manager) { + this.manager = manager; + } + /** + * @return Returns the salary. + */ + public BigDecimal getSalary() { + return salary; + } + /** + * @param salary The salary to set. + */ + public void setSalary(BigDecimal salary) { + this.salary = salary; + } +} diff --git a/test/org/hibernate/test/extendshbm/ExtendsTest.java b/test/org/hibernate/test/extendshbm/ExtendsTest.java new file mode 100644 index 0000000000..7d80fd9692 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/ExtendsTest.java @@ -0,0 +1,192 @@ +//$Id$ +package org.hibernate.test.extendshbm; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.HibernateException; +import org.hibernate.cfg.Configuration; +import org.hibernate.junit.UnitTestCase; + +/** + * @author Gavin King + */ +public class ExtendsTest extends UnitTestCase { + + public ExtendsTest(String str) { + super( str ); + } + + public static Test suite() { + return new TestSuite( ExtendsTest.class ); + } + + private String getBaseForMappings() { + return "org/hibernate/test/"; + } + + public void testAllInOne() { + Configuration cfg = new Configuration(); + + cfg.addResource( getBaseForMappings() + "extendshbm/allinone.hbm.xml" ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) ); + } + + public void testOutOfOrder() { + Configuration cfg = new Configuration(); + + try { + cfg.addResource( getBaseForMappings() + "extendshbm/Customer.hbm.xml" ); + assertNull( + "cannot be in the configuration yet!", + cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) + ); + cfg.addResource( getBaseForMappings() + "extendshbm/Person.hbm.xml" ); + cfg.addResource( getBaseForMappings() + "extendshbm/Employee.hbm.xml" ); + + cfg.buildSessionFactory(); + + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) ); + + } + catch ( HibernateException e ) { + fail( "should not fail with exception! " + e ); + } + + } + + public void testNwaitingForSuper() { + Configuration cfg = new Configuration(); + + try { + cfg.addResource( getBaseForMappings() + "extendshbm/Customer.hbm.xml" ); + assertNull( + "cannot be in the configuration yet!", + cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) + ); + cfg.addResource( getBaseForMappings() + "extendshbm/Employee.hbm.xml" ); + assertNull( + "cannot be in the configuration yet!", + cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) + ); + cfg.addResource( getBaseForMappings() + "extendshbm/Person.hbm.xml" ); + + cfg.buildMappings(); + + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) ); + + + } + catch ( HibernateException e ) { + e.printStackTrace(); + fail( "should not fail with exception! " + e ); + + } + + } + + public void testMissingSuper() { + Configuration cfg = new Configuration(); + + try { + cfg.addResource( getBaseForMappings() + "extendshbm/Customer.hbm.xml" ); + assertNull( + "cannot be in the configuration yet!", + cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) + ); + cfg.addResource( getBaseForMappings() + "extendshbm/Employee.hbm.xml" ); + + cfg.buildSessionFactory(); + + fail( "Should not be able to build sessionfactory without a Person" ); + } + catch ( HibernateException e ) { + + } + + } + + public void testAllSeparateInOne() { + Configuration cfg = new Configuration(); + + try { + cfg.addResource( getBaseForMappings() + "extendshbm/allseparateinone.hbm.xml" ); + + cfg.buildSessionFactory(); + + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) ); + + } + catch ( HibernateException e ) { + fail( "should not fail with exception! " + e ); + } + + } + + public void testJoinedSubclassAndEntityNamesOnly() { + Configuration cfg = new Configuration(); + + try { + cfg.addResource( getBaseForMappings() + "extendshbm/entitynames.hbm.xml" ); + + cfg.buildMappings(); + + assertNotNull( cfg.getClassMapping( "EntityHasName" ) ); + assertNotNull( cfg.getClassMapping( "EntityCompany" ) ); + + } + catch ( HibernateException e ) { + e.printStackTrace(); + fail( "should not fail with exception! " + e ); + + } + } + + public void testEntityNamesWithPackageFailureExpected() { + Configuration cfg = new Configuration(); + try { + cfg.addResource( getBaseForMappings() + "extendshbm/packageentitynames.hbm.xml" ); + + cfg.buildMappings(); + + assertNotNull( cfg.getClassMapping( "EntityHasName" ) ); + assertNotNull( cfg.getClassMapping( "EntityCompany" ) ); + + } + catch ( HibernateException e ) { + e.printStackTrace(); + fail( "should not fail with exception! " + e ); + + } + } + + + public void testUnionSubclass() { + Configuration cfg = new Configuration(); + + try { + cfg.addResource( getBaseForMappings() + "extendshbm/unionsubclass.hbm.xml" ); + + cfg.buildMappings(); + + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) ); + assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) ); + + } + catch ( HibernateException e ) { + e.printStackTrace(); + fail( "should not fail with exception! " + e ); + + } + } + +} + diff --git a/test/org/hibernate/test/extendshbm/Person.hbm.xml b/test/org/hibernate/test/extendshbm/Person.hbm.xml new file mode 100644 index 0000000000..1d260f9384 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/Person.hbm.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/extendshbm/Person.java b/test/org/hibernate/test/extendshbm/Person.java new file mode 100644 index 0000000000..36651303ec --- /dev/null +++ b/test/org/hibernate/test/extendshbm/Person.java @@ -0,0 +1,50 @@ +//$Id$ +package org.hibernate.test.extendshbm; + + +/** + * @author Gavin King + */ +public class Person { + private long id; + private String name; + private char sex; + + /** + * @return Returns the sex. + */ + public char getSex() { + return sex; + } + /** + * @param sex The sex to set. + */ + public void setSex(char sex) { + this.sex = sex; + } + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(long id) { + this.id = id; + } + /** + * @return Returns the identity. + */ + public String getName() { + return name; + } + /** + * @param identity The identity to set. + */ + public void setName(String identity) { + this.name = identity; + } + +} diff --git a/test/org/hibernate/test/extendshbm/allinone.hbm.xml b/test/org/hibernate/test/extendshbm/allinone.hbm.xml new file mode 100644 index 0000000000..e860879089 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/allinone.hbm.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/extendshbm/allseparateinone.hbm.xml b/test/org/hibernate/test/extendshbm/allseparateinone.hbm.xml new file mode 100644 index 0000000000..174d45474b --- /dev/null +++ b/test/org/hibernate/test/extendshbm/allseparateinone.hbm.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/extendshbm/entitynames.hbm.xml b/test/org/hibernate/test/extendshbm/entitynames.hbm.xml new file mode 100644 index 0000000000..3d78b4ab04 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/entitynames.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/extendshbm/packageentitynames.hbm.xml b/test/org/hibernate/test/extendshbm/packageentitynames.hbm.xml new file mode 100644 index 0000000000..7148957444 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/packageentitynames.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/extendshbm/unionsubclass.hbm.xml b/test/org/hibernate/test/extendshbm/unionsubclass.hbm.xml new file mode 100644 index 0000000000..8d1f9824b0 --- /dev/null +++ b/test/org/hibernate/test/extendshbm/unionsubclass.hbm.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/extralazy/Document.java b/test/org/hibernate/test/extralazy/Document.java new file mode 100755 index 0000000000..f79a3379c1 --- /dev/null +++ b/test/org/hibernate/test/extralazy/Document.java @@ -0,0 +1,38 @@ +//$Id$ +package org.hibernate.test.extralazy; + +public class Document { + + private String title; + private String content; + private User owner; + + Document() {} + + public Document(String title, String content, User owner) { + this.content = content; + this.owner = owner; + this.title = title; + owner.getDocuments().add(this); + } + + public String getContent() { + return content; + } + public void setContent(String content) { + this.content = content; + } + public User getOwner() { + return owner; + } + public void setOwner(User owner) { + this.owner = owner; + } + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + +} diff --git a/test/org/hibernate/test/extralazy/ExtraLazyTest.java b/test/org/hibernate/test/extralazy/ExtraLazyTest.java new file mode 100755 index 0000000000..a0b0960d6a --- /dev/null +++ b/test/org/hibernate/test/extralazy/ExtraLazyTest.java @@ -0,0 +1,221 @@ +//$Id$ +package org.hibernate.test.extralazy; + +import java.util.List; +import java.util.Map; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class ExtraLazyTest extends FunctionalTestCase { + + public ExtraLazyTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "extralazy/UserGroup.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ExtraLazyTest.class ); + } + + public void testOrphanDelete() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User gavin = new User("gavin", "secret"); + Document hia = new Document("HiA", "blah blah blah", gavin); + Document hia2 = new Document("HiA2", "blah blah blah blah", gavin); + s.persist(gavin); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + gavin = (User) s.get(User.class, "gavin"); + assertEquals( 2, gavin.getDocuments().size() ); + gavin.getDocuments().remove(hia2); + assertFalse( gavin.getDocuments().contains(hia2) ); + assertTrue( gavin.getDocuments().contains(hia) ); + assertEquals( 1, gavin.getDocuments().size() ); + assertFalse( Hibernate.isInitialized( gavin.getDocuments() ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + gavin = (User) s.get(User.class, "gavin"); + assertEquals( 1, gavin.getDocuments().size() ); + assertFalse( gavin.getDocuments().contains(hia2) ); + assertTrue( gavin.getDocuments().contains(hia) ); + assertFalse( Hibernate.isInitialized( gavin.getDocuments() ) ); + assertNull( s.get(Document.class, "HiA2") ); + gavin.getDocuments().clear(); + assertTrue( Hibernate.isInitialized( gavin.getDocuments() ) ); + s.delete(gavin); + t.commit(); + s.close(); + } + + public void testGet() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User gavin = new User("gavin", "secret"); + User turin = new User("turin", "tiger"); + Group g = new Group("developers"); + g.getUsers().put("gavin", gavin); + g.getUsers().put("turin", turin); + s.persist(g); + gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") ); + gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + g = (Group) s.get(Group.class, "developers"); + gavin = (User) g.getUsers().get("gavin"); + turin = (User) g.getUsers().get("turin"); + assertNotNull(gavin); + assertNotNull(turin); + assertNull( g.getUsers().get("emmanuel") ); + assertFalse( Hibernate.isInitialized( g.getUsers() ) ); + assertNotNull( gavin.getSession().get("foo") ); + assertNull( turin.getSession().get("foo") ); + assertFalse( Hibernate.isInitialized( gavin.getSession() ) ); + assertFalse( Hibernate.isInitialized( turin.getSession() ) ); + s.delete(gavin); + s.delete(turin); + s.delete(g); + t.commit(); + s.close(); + } + + public void testRemoveClear() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User gavin = new User("gavin", "secret"); + User turin = new User("turin", "tiger"); + Group g = new Group("developers"); + g.getUsers().put("gavin", gavin); + g.getUsers().put("turin", turin); + s.persist(g); + gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") ); + gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + g = (Group) s.get(Group.class, "developers"); + gavin = (User) g.getUsers().get("gavin"); + turin = (User) g.getUsers().get("turin"); + assertFalse( Hibernate.isInitialized( g.getUsers() ) ); + g.getUsers().clear(); + gavin.getSession().remove("foo"); + assertTrue( Hibernate.isInitialized( g.getUsers() ) ); + assertTrue( Hibernate.isInitialized( gavin.getSession() ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + g = (Group) s.get(Group.class, "developers"); + assertTrue( g.getUsers().isEmpty() ); + assertFalse( Hibernate.isInitialized( g.getUsers() ) ); + gavin = (User) s.get(User.class, "gavin"); + assertFalse( gavin.getSession().containsKey("foo") ); + assertFalse( Hibernate.isInitialized( gavin.getSession() ) ); + s.delete(gavin); + s.delete(turin); + s.delete(g); + t.commit(); + s.close(); + } + + public void testIndexFormulaMap() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User gavin = new User("gavin", "secret"); + User turin = new User("turin", "tiger"); + Group g = new Group("developers"); + g.getUsers().put("gavin", gavin); + g.getUsers().put("turin", turin); + s.persist(g); + gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") ); + gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + g = (Group) s.get(Group.class, "developers"); + assertEquals( g.getUsers().size(), 2 ); + g.getUsers().remove("turin"); + Map smap = ( (User) g.getUsers().get("gavin") ).getSession(); + assertEquals(smap.size(), 2); + smap.remove("bar"); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + g = (Group) s.get(Group.class, "developers"); + assertEquals( g.getUsers().size(), 1 ); + smap = ( (User) g.getUsers().get("gavin") ).getSession(); + assertEquals(smap.size(), 1); + gavin = (User) g.getUsers().put("gavin", turin); + s.delete(gavin); + assertEquals( s.createQuery("select count(*) from SessionAttribute").uniqueResult(), new Long(0) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + g = (Group) s.get(Group.class, "developers"); + assertEquals( g.getUsers().size(), 1 ); + turin = (User) g.getUsers().get("turin"); + smap = turin.getSession(); + assertEquals(smap.size(), 0); + assertEquals( s.createQuery("select count(*) from User").uniqueResult(), new Long(1) ); + s.delete(g); + s.delete(turin); + assertEquals( s.createQuery("select count(*) from User").uniqueResult(), new Long(0) ); + t.commit(); + s.close(); + } + + public void testSQLQuery() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User gavin = new User("gavin", "secret"); + User turin = new User("turin", "tiger"); + gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") ); + gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") ); + s.persist(gavin); + s.persist(turin); + s.flush(); + s.clear(); + List results = s.getNamedQuery("userSessionData").setParameter("uname", "%in").list(); + assertEquals( results.size(), 2 ); + gavin = (User) ( (Object[]) results.get(0) )[0]; + assertEquals( gavin.getName(), "gavin" ); + assertEquals( gavin.getSession().size(), 2 ); + s.createQuery("delete SessionAttribute").executeUpdate(); + s.createQuery("delete User").executeUpdate(); + t.commit(); + s.close(); + + } + +} + diff --git a/test/org/hibernate/test/extralazy/Group.java b/test/org/hibernate/test/extralazy/Group.java new file mode 100755 index 0000000000..16ba891c70 --- /dev/null +++ b/test/org/hibernate/test/extralazy/Group.java @@ -0,0 +1,29 @@ +//$Id$ +package org.hibernate.test.extralazy; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Gavin King + */ +public class Group { + private String name; + private Map users = new HashMap(); + Group() {} + public Group(String n) { + name = n; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public Map getUsers() { + return users; + } + public void setUsers(Map users) { + this.users = users; + } +} diff --git a/test/org/hibernate/test/extralazy/SessionAttribute.java b/test/org/hibernate/test/extralazy/SessionAttribute.java new file mode 100755 index 0000000000..ed705b9198 --- /dev/null +++ b/test/org/hibernate/test/extralazy/SessionAttribute.java @@ -0,0 +1,41 @@ +//$Id$ +package org.hibernate.test.extralazy; + +import java.io.Serializable; + +/** + * @author Gavin King + */ +public class SessionAttribute { + private Long id; + private String name; + private String stringData; + private Serializable objectData; + SessionAttribute() {} + public SessionAttribute(String name, Serializable obj) { + this.name = name; + this.objectData = obj; + } + public SessionAttribute(String name, String str) { + this.name = name; + this.stringData = str; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public Serializable getObjectData() { + return objectData; + } + public void setObjectData(Serializable objectData) { + this.objectData = objectData; + } + public String getStringData() { + return stringData; + } + public void setStringData(String stringData) { + this.stringData = stringData; + } +} diff --git a/test/org/hibernate/test/extralazy/User.java b/test/org/hibernate/test/extralazy/User.java new file mode 100755 index 0000000000..e4f8053cd4 --- /dev/null +++ b/test/org/hibernate/test/extralazy/User.java @@ -0,0 +1,46 @@ +//$Id$ +package org.hibernate.test.extralazy; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author Gavin King + */ +public class User { + private String name; + private String password; + private Map session = new HashMap(); + private Set documents = new HashSet(); + User() {} + public User(String n, String pw) { + name=n; + password = pw; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public Map getSession() { + return session; + } + public void setSession(Map session) { + this.session = session; + } + public Set getDocuments() { + return documents; + } + public void setDocuments(Set documents) { + this.documents = documents; + } +} diff --git a/test/org/hibernate/test/extralazy/UserGroup.hbm.xml b/test/org/hibernate/test/extralazy/UserGroup.hbm.xml new file mode 100755 index 0000000000..19ef001b0a --- /dev/null +++ b/test/org/hibernate/test/extralazy/UserGroup.hbm.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select + lower(u.name) as {u.name}, lower(u.password) as {u.password}, + lower(s.userName) as {s.key}, lower(s.name) as {s.index}, s.id as {s.element}, + {s.element.*} + from users u + join session_attributes s on lower(s.userName) = lower(u.name) + where u.name like :uname + + + + diff --git a/test/org/hibernate/test/filter/Category.hbm.xml b/test/org/hibernate/test/filter/Category.hbm.xml new file mode 100644 index 0000000000..422875babb --- /dev/null +++ b/test/org/hibernate/test/filter/Category.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/filter/Category.java b/test/org/hibernate/test/filter/Category.java new file mode 100644 index 0000000000..53120f3154 --- /dev/null +++ b/test/org/hibernate/test/filter/Category.java @@ -0,0 +1,104 @@ +// $Id$ +package org.hibernate.test.filter; + +import java.util.Date; +import java.util.Set; + +/** + * Implementation of Category. + * + * @author Steve Ebersole + */ +public class Category { + private Long id; + private String name; + private Date effectiveStartDate; + private Date effectiveEndDate; + private Set products; + + public Category() { + } + + public Category(String name) { + this.name = name; + } + + public Category(String name, Date effectiveStartDate, Date effectiveEndDate) { + this.name = name; + this.effectiveStartDate = effectiveStartDate; + this.effectiveEndDate = effectiveEndDate; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getEffectiveStartDate() { + return effectiveStartDate; + } + + public void setEffectiveStartDate(Date effectiveStartDate) { + this.effectiveStartDate = effectiveStartDate; + } + + public Date getEffectiveEndDate() { + return effectiveEndDate; + } + + public void setEffectiveEndDate(Date effectiveEndDate) { + this.effectiveEndDate = effectiveEndDate; + } + + public Set getProducts() { + return products; + } + + public void setProducts(Set products) { + this.products = products; + } + + public boolean equals(Object o) { + if ( this == o ) return true; + if ( !( o instanceof Category ) ) return false; + + final Category category = ( Category ) o; + + if ( !name.equals( category.name ) ) { + return false; + } + + if ( effectiveEndDate != null ? + !effectiveEndDate.equals( category.effectiveEndDate ) : + category.effectiveEndDate != null ) { + return false; + } + + if ( effectiveStartDate != null ? + !effectiveStartDate.equals( category.effectiveStartDate ) : + category.effectiveStartDate != null ) { + return false; + } + + return true; + } + + public int hashCode() { + int result; + result = name.hashCode(); + result = 29 * result + ( effectiveStartDate != null ? effectiveStartDate.hashCode() : 0 ); + result = 29 * result + ( effectiveEndDate != null ? effectiveEndDate.hashCode() : 0 ); + return result; + } +} diff --git a/test/org/hibernate/test/filter/Department.hbm.xml b/test/org/hibernate/test/filter/Department.hbm.xml new file mode 100644 index 0000000000..8299b04989 --- /dev/null +++ b/test/org/hibernate/test/filter/Department.hbm.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/filter/Department.java b/test/org/hibernate/test/filter/Department.java new file mode 100644 index 0000000000..c583b84d0e --- /dev/null +++ b/test/org/hibernate/test/filter/Department.java @@ -0,0 +1,40 @@ +// $Id$ +package org.hibernate.test.filter; + +import java.util.Set; +import java.util.HashSet; + +/** + * Implementation of Department. + * + * @author Steve + */ +public class Department { + private Long id; + private String name; + private Set salespersons = new HashSet(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getSalespersons() { + return salespersons; + } + + public void setSalespersons(Set salespersons) { + this.salespersons = salespersons; + } +} diff --git a/test/org/hibernate/test/filter/DynamicFilterTest.java b/test/org/hibernate/test/filter/DynamicFilterTest.java new file mode 100644 index 0000000000..f6fdeef154 --- /dev/null +++ b/test/org/hibernate/test/filter/DynamicFilterTest.java @@ -0,0 +1,583 @@ +// $Id$ +package org.hibernate.test.filter; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.EntityMode; +import org.hibernate.FetchMode; +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.cache.CacheKey; +import org.hibernate.cache.entry.CollectionCacheEntry; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.criterion.Expression; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.impl.SessionFactoryImpl; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.test.TestCase; +import org.hibernate.transform.DistinctRootEntityResultTransformer; + +/** + * Implementation of DynamicFilterTest. + * + * @author Steve + */ +public class DynamicFilterTest extends FunctionalTestCase { + + private Log log = LogFactory.getLog( DynamicFilterTest.class ); + + public DynamicFilterTest(String testName) { + super( testName ); + } + + public String[] getMappings() { + return new String[]{ + "filter/defs.hbm.xml", + "filter/LineItem.hbm.xml", + "filter/Order.hbm.xml", + "filter/Product.hbm.xml", + "filter/Salesperson.hbm.xml", + "filter/Department.hbm.xml", + "filter/Category.hbm.xml" + }; + } + + public void configure(Configuration cfg) { + cfg.setProperty( Environment.MAX_FETCH_DEPTH, "1" ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + cfg.setProperty( Environment.USE_QUERY_CACHE, "true" ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( DynamicFilterTest.class ); + } + + public void testSecondLevelCachedCollectionsFiltering() { + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + + // Force a collection into the second level cache, with its non-filtered elements + Salesperson sp = ( Salesperson ) session.load( Salesperson.class, testData.steveId ); + Hibernate.initialize( sp.getOrders() ); + CollectionPersister persister = ( ( SessionFactoryImpl ) getSessions() ) + .getCollectionPersister( Salesperson.class.getName() + ".orders" ); + assertTrue( "No cache for collection", persister.hasCache() ); + CollectionCacheEntry cachedData = ( CollectionCacheEntry ) persister.getCache().getCache() + .read( new CacheKey( testData.steveId, persister.getKeyType(), persister.getRole(), EntityMode.POJO, sfi() ) ); + assertNotNull( "collection was not in cache", cachedData ); + + session.close(); + + session = openSession(); + session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() ); + sp = ( Salesperson ) session.createQuery( "from Salesperson as s where s.id = :id" ) + .setLong( "id", testData.steveId.longValue() ) + .uniqueResult(); + assertEquals( "Filtered-collection not bypassing 2L-cache", 1, sp.getOrders().size() ); + + CollectionCacheEntry cachedData2 = ( CollectionCacheEntry ) persister.getCache().getCache() + .read( new CacheKey( testData.steveId, persister.getKeyType(), persister.getRole(), EntityMode.POJO, sfi() ) ); + assertNotNull( "collection no longer in cache!", cachedData2 ); + assertSame( "Different cache values!", cachedData, cachedData2 ); + + session.close(); + + session = openSession(); + session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() ); + sp = ( Salesperson ) session.load( Salesperson.class, testData.steveId ); + assertEquals( "Filtered-collection not bypassing 2L-cache", 1, sp.getOrders().size() ); + + session.close(); + + // Finally, make sure that the original cached version did not get over-written + session = openSession(); + sp = ( Salesperson ) session.load( Salesperson.class, testData.steveId ); + assertEquals( "Actual cached version got over-written", 2, sp.getOrders().size() ); + + session.close(); + testData.release(); + } + + public void testCombinedClassAndCollectionFiltersEnabled() { + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "regionlist" ).setParameterList( "regions", new String[]{"LA", "APAC"} ); + session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() ); + + // test retreival through hql with the collection as non-eager + List salespersons = session.createQuery( "select s from Salesperson as s" ).list(); + assertEquals( "Incorrect salesperson count", 1, salespersons.size() ); + Salesperson sp = ( Salesperson ) salespersons.get( 0 ); + assertEquals( "Incorrect order count", 1, sp.getOrders().size() ); + + session.clear(); + + // test retreival through hql with the collection join fetched + salespersons = session.createQuery( "select s from Salesperson as s left join fetch s.orders" ).list(); + assertEquals( "Incorrect salesperson count", 1, salespersons.size() ); + sp = ( Salesperson ) salespersons.get( 0 ); + assertEquals( "Incorrect order count", 1, sp.getOrders().size() ); + + session.close(); + testData.release(); + } + + public void testHqlFilters() { + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // HQL test + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + log.info( "Starting HQL filter tests" ); + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "region" ).setParameter( "region", "APAC" ); + + session.enableFilter( "effectiveDate" ) + .setParameter( "asOfDate", testData.lastMonth.getTime() ); + + log.info( "HQL against Salesperson..." ); + List results = session.createQuery( "select s from Salesperson as s left join fetch s.orders" ).list(); + assertTrue( "Incorrect filtered HQL result count [" + results.size() + "]", results.size() == 1 ); + Salesperson result = ( Salesperson ) results.get( 0 ); + assertTrue( "Incorrect collectionfilter count", result.getOrders().size() == 1 ); + + log.info( "HQL against Product..." ); + results = session.createQuery( "from Product as p where p.stockNumber = ?" ).setInteger( 0, 124 ).list(); + assertTrue( results.size() == 1 ); + + session.close(); + testData.release(); + } + + public void testCriteriaQueryFilters() { + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Criteria-query test + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + log.info( "Starting Criteria-query filter tests" ); + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "region" ).setParameter( "region", "APAC" ); + + session.enableFilter( "fulfilledOrders" ) + .setParameter( "asOfDate", testData.lastMonth.getTime() ); + + session.enableFilter( "effectiveDate" ) + .setParameter( "asOfDate", testData.lastMonth.getTime() ); + + log.info( "Criteria query against Salesperson..." ); + List salespersons = session.createCriteria( Salesperson.class ) + .setFetchMode( "orders", FetchMode.JOIN ) + .list(); + assertEquals( "Incorrect salesperson count", 1, salespersons.size() ); + assertEquals( "Incorrect order count", 1, ( ( Salesperson ) salespersons.get( 0 ) ).getOrders().size() ); + + log.info( "Criteria query against Product..." ); + List products = session.createCriteria( Product.class ) + .add( Expression.eq( "stockNumber", new Integer( 124 ) ) ) + .list(); + assertEquals( "Incorrect product count", 1, products.size() ); + + session.close(); + testData.release(); + } + + public void testGetFilters() { + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Get() test + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + log.info( "Starting get() filter tests (eager assoc. fetching)." ); + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "region" ).setParameter( "region", "APAC" ); + + log.info( "Performing get()..." ); + Salesperson salesperson = ( Salesperson ) session.get( Salesperson.class, testData.steveId ); + assertNotNull( salesperson ); + assertEquals( "Incorrect order count", 1, salesperson.getOrders().size() ); + + session.close(); + testData.release(); + } + + public void testOneToManyFilters() { + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // one-to-many loading tests + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + log.info( "Starting one-to-many collection loader filter tests." ); + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "seniorSalespersons" ) + .setParameter( "asOfDate", testData.lastMonth.getTime() ); + + log.info( "Performing load of Department..." ); + Department department = ( Department ) session.load( Department.class, testData.deptId ); + Set salespersons = department.getSalespersons(); + assertEquals( "Incorrect salesperson count", 1, salespersons.size() ); + + session.close(); + testData.release(); + } + + public void testInStyleFilterParameter() { + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // one-to-many loading tests + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + log.info( "Starting one-to-many collection loader filter tests." ); + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "regionlist" ) + .setParameterList( "regions", new String[]{"LA", "APAC"} ); + + log.debug( "Performing query of Salespersons" ); + List salespersons = session.createQuery( "from Salesperson" ).list(); + assertEquals( "Incorrect salesperson count", 1, salespersons.size() ); + + session.close(); + testData.release(); + } + + public void testManyToManyFilterOnCriteria() { + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "effectiveDate" ).setParameter( "asOfDate", new Date() ); + + Product prod = ( Product ) session.createCriteria( Product.class ) + .setResultTransformer( new DistinctRootEntityResultTransformer() ) + .add( Expression.eq( "id", testData.prod1Id ) ) + .uniqueResult(); + + assertNotNull( prod ); + assertEquals( "Incorrect Product.categories count for filter", 1, prod.getCategories().size() ); + + session.close(); + testData.release(); + } + + public void testManyToManyFilterOnLoad() { + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "effectiveDate" ).setParameter( "asOfDate", new Date() ); + + Product prod = ( Product ) session.get( Product.class, testData.prod1Id ); + + long initLoadCount = getSessions().getStatistics().getCollectionLoadCount(); + long initFetchCount = getSessions().getStatistics().getCollectionFetchCount(); + + // should already have been initialized... + int size = prod.getCategories().size(); + assertEquals( "Incorrect filtered collection count", 1, size ); + + long currLoadCount = getSessions().getStatistics().getCollectionLoadCount(); + long currFetchCount = getSessions().getStatistics().getCollectionFetchCount(); + + assertTrue( + "load with join fetch of many-to-many did not trigger join fetch", + ( initLoadCount == currLoadCount ) && ( initFetchCount == currFetchCount ) + ); + + // make sure we did not get back a collection of proxies + long initEntityLoadCount = getSessions().getStatistics().getEntityLoadCount(); + Iterator itr = prod.getCategories().iterator(); + while ( itr.hasNext() ) { + Category cat = ( Category ) itr.next(); + System.out.println( " ===> " + cat.getName() ); + } + long currEntityLoadCount = getSessions().getStatistics().getEntityLoadCount(); + + assertTrue( + "load with join fetch of many-to-many did not trigger *complete* join fetch", + ( initEntityLoadCount == currEntityLoadCount ) + ); + + session.close(); + testData.release(); + } + + public void testManyToManyOnCollectionLoadAfterHQL() { + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "effectiveDate" ).setParameter( "asOfDate", new Date() ); + + // Force the categories to not get initialized here + List result = session.createQuery( "from Product as p where p.id = :id" ) + .setLong( "id", testData.prod1Id.longValue() ) + .list(); + assertTrue( "No products returned from HQL", !result.isEmpty() ); + + Product prod = ( Product ) result.get( 0 ); + assertNotNull( prod ); + assertEquals( "Incorrect Product.categories count for filter on collection load", 1, prod.getCategories().size() ); + + session.close(); + testData.release(); + } + + public void testManyToManyFilterOnQuery() { + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + session.enableFilter( "effectiveDate" ).setParameter( "asOfDate", new Date() ); + + List result = session.createQuery( "from Product p inner join fetch p.categories" ).list(); + assertTrue( "No products returned from HQL many-to-many filter case", !result.isEmpty() ); + + Product prod = ( Product ) result.get( 0 ); + + assertNotNull( prod ); + assertEquals( "Incorrect Product.categories count for filter with HQL", 1, prod.getCategories().size() ); + + session.close(); + testData.release(); + } + + public void testManyToManyBase() { + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + + Product prod = ( Product ) session.get( Product.class, testData.prod1Id ); + + long initLoadCount = getSessions().getStatistics().getCollectionLoadCount(); + long initFetchCount = getSessions().getStatistics().getCollectionFetchCount(); + + // should already have been initialized... + int size = prod.getCategories().size(); + assertEquals( "Incorrect non-filtered collection count", 2, size ); + + long currLoadCount = getSessions().getStatistics().getCollectionLoadCount(); + long currFetchCount = getSessions().getStatistics().getCollectionFetchCount(); + + assertTrue( + "load with join fetch of many-to-many did not trigger join fetch", + ( initLoadCount == currLoadCount ) && ( initFetchCount == currFetchCount ) + ); + + // make sure we did not get back a collection of proxies + long initEntityLoadCount = getSessions().getStatistics().getEntityLoadCount(); + Iterator itr = prod.getCategories().iterator(); + while ( itr.hasNext() ) { + Category cat = ( Category ) itr.next(); + System.out.println( " ===> " + cat.getName() ); + } + long currEntityLoadCount = getSessions().getStatistics().getEntityLoadCount(); + + assertTrue( + "load with join fetch of many-to-many did not trigger *complete* join fetch", + ( initEntityLoadCount == currEntityLoadCount ) + ); + + session.close(); + testData.release(); + } + + public void testManyToManyBaseThruCriteria() { + TestData testData = new TestData(); + testData.prepare(); + + Session session = openSession(); + + List result = session.createCriteria( Product.class ) + .add( Expression.eq( "id", testData.prod1Id ) ) + .list(); + + Product prod = ( Product ) result.get( 0 ); + + long initLoadCount = getSessions().getStatistics().getCollectionLoadCount(); + long initFetchCount = getSessions().getStatistics().getCollectionFetchCount(); + + // should already have been initialized... + int size = prod.getCategories().size(); + assertEquals( "Incorrect non-filtered collection count", 2, size ); + + long currLoadCount = getSessions().getStatistics().getCollectionLoadCount(); + long currFetchCount = getSessions().getStatistics().getCollectionFetchCount(); + + assertTrue( + "load with join fetch of many-to-many did not trigger join fetch", + ( initLoadCount == currLoadCount ) && ( initFetchCount == currFetchCount ) + ); + + // make sure we did not get back a collection of proxies + long initEntityLoadCount = getSessions().getStatistics().getEntityLoadCount(); + Iterator itr = prod.getCategories().iterator(); + while ( itr.hasNext() ) { + Category cat = ( Category ) itr.next(); + System.out.println( " ===> " + cat.getName() ); + } + long currEntityLoadCount = getSessions().getStatistics().getEntityLoadCount(); + + assertTrue( + "load with join fetch of many-to-many did not trigger *complete* join fetch", + ( initEntityLoadCount == currEntityLoadCount ) + ); + + session.close(); + testData.release(); + } + + private class TestData { + private Long steveId; + private Long deptId; + private Long prod1Id; + private Calendar lastMonth; + private Calendar nextMonth; + private Calendar sixMonthsAgo; + private Calendar fourMonthsAgo; + + private List entitiesToCleanUp = new ArrayList(); + + private void prepare() { + Session session = openSession(); + Transaction transaction = session.beginTransaction(); + + lastMonth = new GregorianCalendar(); + lastMonth.add( Calendar.MONTH, -1 ); + + nextMonth = new GregorianCalendar(); + nextMonth.add( Calendar.MONTH, 1 ); + + sixMonthsAgo = new GregorianCalendar(); + sixMonthsAgo.add( Calendar.MONTH, -6 ); + + fourMonthsAgo = new GregorianCalendar(); + fourMonthsAgo.add( Calendar.MONTH, -4 ); + + Department dept = new Department(); + dept.setName( "Sales" ); + + session.save( dept ); + deptId = dept.getId(); + entitiesToCleanUp.add( dept ); + + Salesperson steve = new Salesperson(); + steve.setName( "steve" ); + steve.setRegion( "APAC" ); + steve.setHireDate( sixMonthsAgo.getTime() ); + + steve.setDepartment( dept ); + dept.getSalespersons().add( steve ); + + Salesperson max = new Salesperson(); + max.setName( "max" ); + max.setRegion( "EMEA" ); + max.setHireDate( nextMonth.getTime() ); + + max.setDepartment( dept ); + dept.getSalespersons().add( max ); + + session.save( steve ); + session.save( max ); + entitiesToCleanUp.add( steve ); + entitiesToCleanUp.add( max ); + + steveId = steve.getId(); + + Category cat1 = new Category( "test cat 1", lastMonth.getTime(), nextMonth.getTime() ); + Category cat2 = new Category( "test cat 2", sixMonthsAgo.getTime(), fourMonthsAgo.getTime() ); + + Product product1 = new Product(); + product1.setName( "Acme Hair Gel" ); + product1.setStockNumber( 123 ); + product1.setEffectiveStartDate( lastMonth.getTime() ); + product1.setEffectiveEndDate( nextMonth.getTime() ); + + product1.addCategory( cat1 ); + product1.addCategory( cat2 ); + + session.save( product1 ); + entitiesToCleanUp.add( product1 ); + prod1Id = product1.getId(); + + Order order1 = new Order(); + order1.setBuyer( "gavin" ); + order1.setRegion( "APAC" ); + order1.setPlacementDate( sixMonthsAgo.getTime() ); + order1.setFulfillmentDate( fourMonthsAgo.getTime() ); + order1.setSalesperson( steve ); + order1.addLineItem( product1, 500 ); + + session.save( order1 ); + entitiesToCleanUp.add( order1 ); + + Product product2 = new Product(); + product2.setName( "Acme Super-Duper DTO Factory" ); + product2.setStockNumber( 124 ); + product2.setEffectiveStartDate( sixMonthsAgo.getTime() ); + product2.setEffectiveEndDate( new Date() ); + + Category cat3 = new Category( "test cat 2", sixMonthsAgo.getTime(), new Date() ); + product2.addCategory( cat3 ); + + session.save( product2 ); + entitiesToCleanUp.add( product2 ); + + // An uncategorized product + Product product3 = new Product(); + product3.setName( "Uncategorized product" ); + session.save( product3 ); + entitiesToCleanUp.add( product3 ); + + Order order2 = new Order(); + order2.setBuyer( "christian" ); + order2.setRegion( "EMEA" ); + order2.setPlacementDate( lastMonth.getTime() ); + order2.setSalesperson( steve ); + order2.addLineItem( product2, -1 ); + + session.save( order2 ); + entitiesToCleanUp.add( order2 ); + + transaction.commit(); + session.close(); + } + + private void release() { + Session session = openSession(); + Transaction transaction = session.beginTransaction(); + + Iterator itr = entitiesToCleanUp.iterator(); + while ( itr.hasNext() ) { + session.delete( itr.next() ); + } + + transaction.commit(); + session.close(); + } + } +} diff --git a/test/org/hibernate/test/filter/LineItem.hbm.xml b/test/org/hibernate/test/filter/LineItem.hbm.xml new file mode 100644 index 0000000000..8b60d14950 --- /dev/null +++ b/test/org/hibernate/test/filter/LineItem.hbm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/filter/LineItem.java b/test/org/hibernate/test/filter/LineItem.java new file mode 100644 index 0000000000..decd3ef858 --- /dev/null +++ b/test/org/hibernate/test/filter/LineItem.java @@ -0,0 +1,67 @@ +// $Id$ +package org.hibernate.test.filter; + +/** + * Implementation of LineItem. + * + * @author Steve + */ +public class LineItem { + private Long id; + private Order order; + private int sequence; + private Product product; + private long quantity; + + /*package*/ LineItem() {} + + public static LineItem generate(Order order, int sequence, Product product, long quantity) { + LineItem item = new LineItem(); + item.order = order; + item.sequence = sequence; + item.product = product; + item.quantity = quantity; + item.order.getLineItems().add(sequence, item); + return item; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Order getOrder() { + return order; + } + + public void setOrder(Order order) { + this.order = order; + } + + public int getSequence() { + return sequence; + } + + public void setSequence(int sequence) { + this.sequence = sequence; + } + + public Product getProduct() { + return product; + } + + public void setProduct(Product product) { + this.product = product; + } + + public long getQuantity() { + return quantity; + } + + public void setQuantity(long quantity) { + this.quantity = quantity; + } +} diff --git a/test/org/hibernate/test/filter/Order.hbm.xml b/test/org/hibernate/test/filter/Order.hbm.xml new file mode 100644 index 0000000000..576b03d92b --- /dev/null +++ b/test/org/hibernate/test/filter/Order.hbm.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/filter/Order.java b/test/org/hibernate/test/filter/Order.java new file mode 100644 index 0000000000..c30800c11c --- /dev/null +++ b/test/org/hibernate/test/filter/Order.java @@ -0,0 +1,87 @@ +// $Id$ +package org.hibernate.test.filter; + +import java.util.Date; +import java.util.List; +import java.util.ArrayList; + +/** + * @author Steve Ebersole + */ +public class Order { + private Long id; + private String region; + private Date placementDate; + private Date fulfillmentDate; + private Salesperson salesperson; + private String buyer; + private List lineItems = new ArrayList(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public Date getPlacementDate() { + return placementDate; + } + + public void setPlacementDate(Date placementDate) { + this.placementDate = placementDate; + } + + public Date getFulfillmentDate() { + return fulfillmentDate; + } + + public void setFulfillmentDate(Date fulfillmentDate) { + this.fulfillmentDate = fulfillmentDate; + } + + public Salesperson getSalesperson() { + return salesperson; + } + + public void setSalesperson(Salesperson salesperson) { + this.salesperson = salesperson; + } + + public String getBuyer() { + return buyer; + } + + public void setBuyer(String buyer) { + this.buyer = buyer; + } + + public List getLineItems() { + return lineItems; + } + + protected void setLineItems(List lineItems) { + this.lineItems = lineItems; + } + + public LineItem addLineItem(Product product, long quantity) { + return LineItem.generate(this, getLineItems().size(), product, quantity); + } + + public void removeLineItem(LineItem item) { + removeLineItem( item.getSequence() ); + } + + public void removeLineItem(int sequence) { + getLineItems().remove(sequence); + } +} diff --git a/test/org/hibernate/test/filter/Product.hbm.xml b/test/org/hibernate/test/filter/Product.hbm.xml new file mode 100644 index 0000000000..dc872baaf7 --- /dev/null +++ b/test/org/hibernate/test/filter/Product.hbm.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/filter/Product.java b/test/org/hibernate/test/filter/Product.java new file mode 100644 index 0000000000..2495dc550f --- /dev/null +++ b/test/org/hibernate/test/filter/Product.java @@ -0,0 +1,99 @@ +// $Id$ +package org.hibernate.test.filter; + +import java.util.Set; +import java.util.Date; +import java.util.HashSet; + +/** + * @author Steve Ebersole + */ +public class Product { + private Long id; + private String name; + private int stockNumber; // int for ease of hashCode() impl + private Date effectiveStartDate; + private Date effectiveEndDate; + private Set orderLineItems; + private Set categories; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getOrderLineItems() { + return orderLineItems; + } + + public void setOrderLineItems(Set orderLineItems) { + this.orderLineItems = orderLineItems; + } + + public int getStockNumber() { + return stockNumber; + } + + public void setStockNumber(int stockNumber) { + this.stockNumber = stockNumber; + } + + public int hashCode() { + return stockNumber; + } + + public boolean equals(Object obj) { + return ( (Product) obj ).stockNumber == this.stockNumber; + } + + public Date getEffectiveStartDate() { + return effectiveStartDate; + } + + public void setEffectiveStartDate(Date effectiveStartDate) { + this.effectiveStartDate = effectiveStartDate; + } + + public Date getEffectiveEndDate() { + return effectiveEndDate; + } + + public void setEffectiveEndDate(Date effectiveEndDate) { + this.effectiveEndDate = effectiveEndDate; + } + + public Set getCategories() { + return categories; + } + + public void setCategories(Set categories) { + this.categories = categories; + } + + public void addCategory(Category category) { + if ( category == null ) { + return; + } + + if ( categories == null ) { + categories = new HashSet(); + } + + categories.add( category ); + if ( category.getProducts() == null ) { + category.setProducts( new HashSet() ); + } + category.getProducts().add( this ); + } +} diff --git a/test/org/hibernate/test/filter/Salesperson.hbm.xml b/test/org/hibernate/test/filter/Salesperson.hbm.xml new file mode 100644 index 0000000000..36c8be6f2c --- /dev/null +++ b/test/org/hibernate/test/filter/Salesperson.hbm.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/filter/Salesperson.java b/test/org/hibernate/test/filter/Salesperson.java new file mode 100644 index 0000000000..f574438e2c --- /dev/null +++ b/test/org/hibernate/test/filter/Salesperson.java @@ -0,0 +1,68 @@ +// $Id$ +package org.hibernate.test.filter; + +import java.util.Set; +import java.util.HashSet; +import java.util.Date; + +/** + * Implementation of Salesperson. + * + * @author Steve + */ +public class Salesperson { + private Long id; + private String name; + private String region; + private Date hireDate; + private Department department; + private Set orders = new HashSet(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public Set getOrders() { + return orders; + } + + public void setOrders(Set orders) { + this.orders = orders; + } + + public Date getHireDate() { + return hireDate; + } + + public void setHireDate(Date hireDate) { + this.hireDate = hireDate; + } + + public Department getDepartment() { + return department; + } + + public void setDepartment(Department department) { + this.department = department; + } +} diff --git a/test/org/hibernate/test/filter/defs.hbm.xml b/test/org/hibernate/test/filter/defs.hbm.xml new file mode 100644 index 0000000000..f9305a83d2 --- /dev/null +++ b/test/org/hibernate/test/filter/defs.hbm.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/formulajoin/Detail.java b/test/org/hibernate/test/formulajoin/Detail.java new file mode 100755 index 0000000000..70244feca2 --- /dev/null +++ b/test/org/hibernate/test/formulajoin/Detail.java @@ -0,0 +1,46 @@ +//$Id$ +package org.hibernate.test.formulajoin; + +import java.io.Serializable; + +/** + * @author Gavin King + */ +public class Detail implements Serializable { + private Long id; + private Master master; + private int version; + private String details; + private boolean currentVersion; + + public boolean isCurrentVersion() { + return currentVersion; + } + public void setCurrentVersion(boolean currentVersion) { + this.currentVersion = currentVersion; + } + public String getDetails() { + return details; + } + public void setDetails(String details) { + this.details = details; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Master getMaster() { + return master; + } + public void setMaster(Master master) { + this.master = master; + } + public int getVersion() { + return version; + } + public void setVersion(int version) { + this.version = version; + } +} diff --git a/test/org/hibernate/test/formulajoin/FormulaJoinTest.java b/test/org/hibernate/test/formulajoin/FormulaJoinTest.java new file mode 100755 index 0000000000..fc8ed5d54f --- /dev/null +++ b/test/org/hibernate/test/formulajoin/FormulaJoinTest.java @@ -0,0 +1,100 @@ +//$Id$ +package org.hibernate.test.formulajoin; + +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class FormulaJoinTest extends FunctionalTestCase { + + public FormulaJoinTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "formulajoin/Master.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( FormulaJoinTest.class ); + } + + public void testFormulaJoin() { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + Master master = new Master(); + master.setName("master 1"); + Detail current = new Detail(); + current.setCurrentVersion(true); + current.setVersion(2); + current.setDetails("details of master 1 blah blah"); + current.setMaster(master); + master.setDetail(current); + Detail past = new Detail(); + past.setCurrentVersion(false); + past.setVersion(1); + past.setDetails("old details of master 1 yada yada"); + past.setMaster(master); + s.persist(master); + s.persist(past); + s.persist(current); + tx.commit(); + s.close(); + + if ( getDialect() instanceof PostgreSQLDialect ) return; + + s = openSession(); + tx = s.beginTransaction(); + List l = s.createQuery("from Master m left join m.detail d").list(); + assertEquals( l.size(), 1 ); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + l = s.createQuery("from Master m left join fetch m.detail").list(); + assertEquals( l.size(), 1 ); + Master m = (Master) l.get(0); + assertEquals( "master 1", m.getDetail().getMaster().getName() ); + assertTrue( m==m.getDetail().getMaster() ); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + l = s.createQuery("from Master m join fetch m.detail").list(); + assertEquals( l.size(), 1 ); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + l = s.createQuery("from Detail d join fetch d.currentMaster.master").list(); + assertEquals( l.size(), 2 ); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + l = s.createQuery("from Detail d join fetch d.currentMaster.master m join fetch m.detail").list(); + assertEquals( l.size(), 2 ); + + s.createQuery("delete from Detail").executeUpdate(); + s.createQuery("delete from Master").executeUpdate(); + + tx.commit(); + s.close(); + + } + +} + diff --git a/test/org/hibernate/test/formulajoin/Master.hbm.xml b/test/org/hibernate/test/formulajoin/Master.hbm.xml new file mode 100755 index 0000000000..e6b98b1d39 --- /dev/null +++ b/test/org/hibernate/test/formulajoin/Master.hbm.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/formulajoin/Master.java b/test/org/hibernate/test/formulajoin/Master.java new file mode 100755 index 0000000000..ddf7ef5000 --- /dev/null +++ b/test/org/hibernate/test/formulajoin/Master.java @@ -0,0 +1,31 @@ +//$Id$ +package org.hibernate.test.formulajoin; + +import java.io.Serializable; + +/** + * @author Gavin King + */ +public class Master implements Serializable { + private Long id; + private String name; + private Detail detail; + public Detail getDetail() { + return detail; + } + public void setDetail(Detail detail) { + this.detail = detail; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/generated/AbstractGeneratedPropertyTest.java b/test/org/hibernate/test/generated/AbstractGeneratedPropertyTest.java new file mode 100644 index 0000000000..7676c23ed7 --- /dev/null +++ b/test/org/hibernate/test/generated/AbstractGeneratedPropertyTest.java @@ -0,0 +1,47 @@ +// $Id$ +package org.hibernate.test.generated; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.Hibernate; +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; + +/** + * Implementation of AbstractGeneratedPropertyTest. + * + * @author Steve Ebersole + */ +public abstract class AbstractGeneratedPropertyTest extends DatabaseSpecificFunctionalTestCase { + public AbstractGeneratedPropertyTest(String x) { + super( x ); + } + + public final void testGeneratedProperty() { + GeneratedPropertyEntity entity = new GeneratedPropertyEntity(); + entity.setName( "entity-1" ); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.save( entity ); + s.flush(); + assertNotNull( "no timestamp retrieved", entity.getLastModified() ); + t.commit(); + s.close(); + + byte[] bytes = entity.getLastModified(); + + s = openSession(); + t = s.beginTransaction(); + entity = ( GeneratedPropertyEntity ) s.get( GeneratedPropertyEntity.class, entity.getId() ); + assertTrue( Hibernate.BINARY.isEqual( bytes, entity.getLastModified() ) ); + t.commit(); + s.close(); + + assertTrue( Hibernate.BINARY.isEqual( bytes, entity.getLastModified() ) ); + + s = openSession(); + t = s.beginTransaction(); + s.delete( entity ); + t.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/generated/ComponentOwner.hbm.xml b/test/org/hibernate/test/generated/ComponentOwner.hbm.xml new file mode 100644 index 0000000000..ae690bdad0 --- /dev/null +++ b/test/org/hibernate/test/generated/ComponentOwner.hbm.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/generated/ComponentOwner.java b/test/org/hibernate/test/generated/ComponentOwner.java new file mode 100644 index 0000000000..0f0bea626c --- /dev/null +++ b/test/org/hibernate/test/generated/ComponentOwner.java @@ -0,0 +1,55 @@ +package org.hibernate.test.generated; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class ComponentOwner { + private Long id; + private String name; + private Component component; + + public ComponentOwner() { + } + + public ComponentOwner(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Component getComponent() { + return component; + } + + public void setComponent(Component component) { + this.component = component; + } + + public static class Component { + private int generated; + + public int getGenerated() { + return generated; + } + + public void setGenerated(int generated) { + this.generated = generated; + } + } +} diff --git a/test/org/hibernate/test/generated/GeneratedPropertyEntity.hbm.xml b/test/org/hibernate/test/generated/GeneratedPropertyEntity.hbm.xml new file mode 100644 index 0000000000..3369a74b5e --- /dev/null +++ b/test/org/hibernate/test/generated/GeneratedPropertyEntity.hbm.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/generated/GeneratedPropertyEntity.java b/test/org/hibernate/test/generated/GeneratedPropertyEntity.java new file mode 100644 index 0000000000..0d4a5cd84a --- /dev/null +++ b/test/org/hibernate/test/generated/GeneratedPropertyEntity.java @@ -0,0 +1,37 @@ +// $Id$ +package org.hibernate.test.generated; + +/** + * Implementation of GeneratedPropertyEntity. + * + * @author Steve Ebersole + */ +public class GeneratedPropertyEntity { + private Long id; + private String name; + private byte[] lastModified; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public byte[] getLastModified() { + return lastModified; + } + + public void setLastModified(byte[] lastModified) { + this.lastModified = lastModified; + } +} diff --git a/test/org/hibernate/test/generated/GeneratedPropertySuite.java b/test/org/hibernate/test/generated/GeneratedPropertySuite.java new file mode 100644 index 0000000000..4783aef5c1 --- /dev/null +++ b/test/org/hibernate/test/generated/GeneratedPropertySuite.java @@ -0,0 +1,20 @@ +package org.hibernate.test.generated; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class GeneratedPropertySuite { + public static Test suite() { + TestSuite suite = new TestSuite( "generated property suite" ); + suite.addTest( TimestampGeneratedValuesWithCachingTest.suite() ); + suite.addTest( TriggerGeneratedValuesWithCachingTest.suite() ); + suite.addTest( TriggerGeneratedValuesWithoutCachingTest.suite() ); + suite.addTest( PartiallyGeneratedComponentTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/generated/MSSQLGeneratedPropertyEntity.hbm.xml b/test/org/hibernate/test/generated/MSSQLGeneratedPropertyEntity.hbm.xml new file mode 100644 index 0000000000..8048ac4543 --- /dev/null +++ b/test/org/hibernate/test/generated/MSSQLGeneratedPropertyEntity.hbm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java b/test/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java new file mode 100644 index 0000000000..7be2ac4941 --- /dev/null +++ b/test/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java @@ -0,0 +1,64 @@ +package org.hibernate.test.generated; + +import junit.framework.Test; + +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class PartiallyGeneratedComponentTest extends DatabaseSpecificFunctionalTestCase { + public PartiallyGeneratedComponentTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "generated/ComponentOwner.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PartiallyGeneratedComponentTest.class ); + } + + public boolean appliesTo(Dialect dialect) { + return dialect instanceof Oracle9Dialect; + } + + public void testPartialComponentGeneration() { + ComponentOwner owner = new ComponentOwner( "initial" ); + Session s = openSession(); + s.beginTransaction(); + s.save( owner ); + s.getTransaction().commit(); + s.close(); + + assertNotNull( "expecting insert value generation", owner.getComponent() ); + int previousValue = owner.getComponent().getGenerated(); + assertFalse( "expecting insert value generation", 0 == previousValue ); + + s = openSession(); + s.beginTransaction(); + owner = ( ComponentOwner ) s.get( ComponentOwner.class, owner.getId() ); + assertEquals( "expecting insert value generation", previousValue, owner.getComponent().getGenerated() ); + owner.setName( "subsequent" ); + s.getTransaction().commit(); + s.close(); + + assertNotNull( owner.getComponent() ); + previousValue = owner.getComponent().getGenerated(); + + s = openSession(); + s.beginTransaction(); + owner = ( ComponentOwner ) s.get( ComponentOwner.class, owner.getId() ); + assertEquals( "expecting update value generation", previousValue, owner.getComponent().getGenerated() ); + s.delete( owner ); + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/generated/TimestampGeneratedValuesWithCachingTest.java b/test/org/hibernate/test/generated/TimestampGeneratedValuesWithCachingTest.java new file mode 100644 index 0000000000..7fe7ca2f2e --- /dev/null +++ b/test/org/hibernate/test/generated/TimestampGeneratedValuesWithCachingTest.java @@ -0,0 +1,34 @@ +// $Id$ +package org.hibernate.test.generated; + +import junit.framework.Test; + +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Implementation of TimestampGeneratedValuesWithCachingTest. + * + * @author Steve Ebersole + */ +public class TimestampGeneratedValuesWithCachingTest extends AbstractGeneratedPropertyTest { + + public TimestampGeneratedValuesWithCachingTest(String x) { + super( x ); + } + + public final String[] getMappings() { + return new String[] { "generated/MSSQLGeneratedPropertyEntity.hbm.xml" }; + } + + public boolean appliesTo(Dialect dialect) { + // this test is specific to Sybase/SQLServer as it is testing support + // for their TIMESTAMP datatype... + return ( dialect instanceof SybaseDialect ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( TimestampGeneratedValuesWithCachingTest.class ); + } +} diff --git a/test/org/hibernate/test/generated/TriggerGeneratedValuesWithCachingTest.java b/test/org/hibernate/test/generated/TriggerGeneratedValuesWithCachingTest.java new file mode 100644 index 0000000000..c26cda80b0 --- /dev/null +++ b/test/org/hibernate/test/generated/TriggerGeneratedValuesWithCachingTest.java @@ -0,0 +1,35 @@ +// $Id$ +package org.hibernate.test.generated; + +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.dialect.Dialect; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Implementation of TriggerGeneratedValuesWithoutCachingTest. + * + * @author Steve Ebersole + */ +public class TriggerGeneratedValuesWithCachingTest extends AbstractGeneratedPropertyTest { + + public TriggerGeneratedValuesWithCachingTest(String x) { + super( x ); + } + + public final String[] getMappings() { + return new String[] { "generated/GeneratedPropertyEntity.hbm.xml" }; + } + + public boolean appliesTo(Dialect dialect) { + // currently have only defined triggers for oracle... + // TODO : add more triggers for dialects which allow mods in triggers... + return ( dialect instanceof Oracle9Dialect ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( TriggerGeneratedValuesWithCachingTest.class ); + } +} diff --git a/test/org/hibernate/test/generated/TriggerGeneratedValuesWithoutCachingTest.java b/test/org/hibernate/test/generated/TriggerGeneratedValuesWithoutCachingTest.java new file mode 100644 index 0000000000..24931bf111 --- /dev/null +++ b/test/org/hibernate/test/generated/TriggerGeneratedValuesWithoutCachingTest.java @@ -0,0 +1,38 @@ +// $Id$ +package org.hibernate.test.generated; + +import junit.framework.Test; + +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Implementation of TriggerGeneratedValuesWithoutCachingTest. + * + * @author Steve Ebersole + */ +public class TriggerGeneratedValuesWithoutCachingTest extends AbstractGeneratedPropertyTest { + + public TriggerGeneratedValuesWithoutCachingTest(String x) { + super( x ); + } + + public final String[] getMappings() { + return new String[] { "generated/GeneratedPropertyEntity.hbm.xml" }; + } + + public boolean appliesTo(Dialect dialect) { + // currently have only defined triggers for oracle... + // TODO : add more triggers for dialects which allow mods in triggers... + return ( dialect instanceof Oracle9Dialect ); + } + + public String getCacheConcurrencyStrategy() { + return null; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( TriggerGeneratedValuesWithoutCachingTest.class ); + } +} diff --git a/test/org/hibernate/test/generatedkeys/GeneratedKeysSuite.java b/test/org/hibernate/test/generatedkeys/GeneratedKeysSuite.java new file mode 100644 index 0000000000..e840a131d7 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/GeneratedKeysSuite.java @@ -0,0 +1,23 @@ +package org.hibernate.test.generatedkeys; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.test.generatedkeys.identity.IdentityGeneratedKeysTest; +import org.hibernate.test.generatedkeys.select.SelectGeneratorTest; +import org.hibernate.test.generatedkeys.seqidentity.SequenceIdentityTest; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class GeneratedKeysSuite { + public static Test suite() { + TestSuite suite = new TestSuite( "generated keys suite" ); + suite.addTest( IdentityGeneratedKeysTest.suite() ); + suite.addTest( SelectGeneratorTest.suite() ); + suite.addTest( SequenceIdentityTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java b/test/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java new file mode 100644 index 0000000000..a198b81f48 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java @@ -0,0 +1,160 @@ +package org.hibernate.test.generatedkeys.identity; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.Dialect; +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Steve Ebersole + */ +public class IdentityGeneratedKeysTest extends DatabaseSpecificFunctionalTestCase { + public IdentityGeneratedKeysTest(String name) { + super( name ); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + } + + public String[] getMappings() { + return new String[] { "generatedkeys/identity/MyEntity.hbm.xml" }; + } + + public boolean appliesTo(Dialect dialect) { + return dialect.supportsIdentityColumns(); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( IdentityGeneratedKeysTest.class ); + } + + public void testIdentityColumnGeneratedIds() { + Session s = openSession(); + s.beginTransaction(); + MyEntity myEntity = new MyEntity( "test" ); + Long id = ( Long ) s.save( myEntity ); + assertNotNull( "identity column did not force immediate insert", id ); + assertEquals( id, myEntity.getId() ); + s.delete( myEntity ); + s.getTransaction().commit(); + s.close(); + } + + public void testPersistOutsideTransaction() { + Session s = openSession(); + + // first test save() which should force an immediate insert... + MyEntity myEntity1 = new MyEntity( "test-save" ); + Long id = ( Long ) s.save( myEntity1 ); + assertNotNull( "identity column did not force immediate insert", id ); + assertEquals( id, myEntity1.getId() ); + + // next test persist() which should cause a delayed insert... + long initialInsertCount = sfi().getStatistics().getEntityInsertCount(); + MyEntity myEntity2 = new MyEntity( "test-persist"); + s.persist( myEntity2 ); + assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() ); + assertNull( myEntity2.getId() ); + + // an explicit flush should cause execution of the delayed insertion + s.flush(); + assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 1, sfi().getStatistics().getEntityInsertCount() ); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.delete( myEntity1 ); + s.delete( myEntity2 ); + s.getTransaction().commit(); + s.close(); + } + + public void testPersistOutsideTransactionCascadedToNonInverseCollection() { + long initialInsertCount = sfi().getStatistics().getEntityInsertCount(); + Session s = openSession(); + MyEntity myEntity = new MyEntity( "test-persist"); + myEntity.getNonInverseChildren().add( new MyChild( "test-child-persist-non-inverse" ) ); + s.persist( myEntity ); + assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() ); + assertNull( myEntity.getId() ); + s.flush(); + assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() ); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.createQuery( "delete MyChild" ).executeUpdate(); + s.createQuery( "delete MyEntity" ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } + + public void testPersistOutsideTransactionCascadedToInverseCollection() { + long initialInsertCount = sfi().getStatistics().getEntityInsertCount(); + Session s = openSession(); + MyEntity myEntity2 = new MyEntity( "test-persist-2"); + MyChild child = new MyChild( "test-child-persist-inverse" ); + myEntity2.getInverseChildren().add( child ); + child.setInverseParent( myEntity2 ); + s.persist( myEntity2 ); + assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() ); + assertNull( myEntity2.getId() ); + s.flush(); + assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() ); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.createQuery( "delete MyChild" ).executeUpdate(); + s.createQuery( "delete MyEntity" ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } + + public void testPersistOutsideTransactionCascadedToManyToOne() { + long initialInsertCount = sfi().getStatistics().getEntityInsertCount(); + Session s = openSession(); + MyEntity myEntity = new MyEntity( "test-persist"); + myEntity.setSibling( new MySibling( "test-persist-sibling-out" ) ); + s.persist( myEntity ); + assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() ); + assertNull( myEntity.getId() ); + s.flush(); + assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() ); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.createQuery( "delete MyEntity" ).executeUpdate(); + s.createQuery( "delete MySibling" ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } + + public void testPersistOutsideTransactionCascadedFromManyToOne() { + long initialInsertCount = sfi().getStatistics().getEntityInsertCount(); + Session s = openSession(); + MyEntity myEntity2 = new MyEntity( "test-persist-2"); + MySibling sibling = new MySibling( "test-persist-sibling-in" ); + sibling.setEntity( myEntity2 ); + s.persist( sibling ); + assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() ); + assertNull( myEntity2.getId() ); + s.flush(); + assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() ); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.createQuery( "delete MySibling" ).executeUpdate(); + s.createQuery( "delete MyEntity" ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/generatedkeys/identity/MyChild.java b/test/org/hibernate/test/generatedkeys/identity/MyChild.java new file mode 100644 index 0000000000..c3f6c483e6 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/identity/MyChild.java @@ -0,0 +1,41 @@ +package org.hibernate.test.generatedkeys.identity; + +/** + * @author Steve Ebersole + */ +public class MyChild { + private Long id; + private String name; + private MyEntity inverseParent; + + public MyChild() { + } + + public MyChild(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MyEntity getInverseParent() { + return inverseParent; + } + + public void setInverseParent(MyEntity inverseParent) { + this.inverseParent = inverseParent; + } +} diff --git a/test/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml b/test/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml new file mode 100644 index 0000000000..87d2c28a8e --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/generatedkeys/identity/MyEntity.java b/test/org/hibernate/test/generatedkeys/identity/MyEntity.java new file mode 100644 index 0000000000..7a5bc7d7c2 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/identity/MyEntity.java @@ -0,0 +1,62 @@ +package org.hibernate.test.generatedkeys.identity; + +import java.util.Set; +import java.util.HashSet; + +/** + * @author Steve Ebersole + */ +public class MyEntity { + private Long id; + private String name; + private MySibling sibling; + private Set nonInverseChildren = new HashSet(); + private Set inverseChildren = new HashSet(); + + public MyEntity() { + } + + public MyEntity(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MySibling getSibling() { + return sibling; + } + + public void setSibling(MySibling sibling) { + this.sibling = sibling; + } + + public Set getNonInverseChildren() { + return nonInverseChildren; + } + + public void setNonInverseChildren(Set nonInverseChildren) { + this.nonInverseChildren = nonInverseChildren; + } + + public Set getInverseChildren() { + return inverseChildren; + } + + public void setInverseChildren(Set inverseChildren) { + this.inverseChildren = inverseChildren; + } +} diff --git a/test/org/hibernate/test/generatedkeys/identity/MySibling.java b/test/org/hibernate/test/generatedkeys/identity/MySibling.java new file mode 100644 index 0000000000..cf0193d1e0 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/identity/MySibling.java @@ -0,0 +1,41 @@ +package org.hibernate.test.generatedkeys.identity; + +/** + * @author Steve Ebersole + */ +public class MySibling { + private Long id; + private String name; + private MyEntity entity; + + public MySibling() { + } + + public MySibling(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MyEntity getEntity() { + return entity; + } + + public void setEntity(MyEntity entity) { + this.entity = entity; + } +} diff --git a/test/org/hibernate/test/generatedkeys/select/MyEntity.hbm.xml b/test/org/hibernate/test/generatedkeys/select/MyEntity.hbm.xml new file mode 100644 index 0000000000..e8413ff1a9 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/select/MyEntity.hbm.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/generatedkeys/select/MyEntity.java b/test/org/hibernate/test/generatedkeys/select/MyEntity.java new file mode 100644 index 0000000000..90e0d53088 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/select/MyEntity.java @@ -0,0 +1,28 @@ +package org.hibernate.test.generatedkeys.select; + +/** + * @author Steve Ebersole + */ +public class MyEntity { + private Long id; + private String name; + + public MyEntity() { + } + + public MyEntity(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/generatedkeys/select/SelectGeneratorTest.java b/test/org/hibernate/test/generatedkeys/select/SelectGeneratorTest.java new file mode 100644 index 0000000000..5790b3c4bf --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/select/SelectGeneratorTest.java @@ -0,0 +1,52 @@ +package org.hibernate.test.generatedkeys.select; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.dialect.DataDirectOracle9Dialect; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Steve Ebersole + */ +public class SelectGeneratorTest extends DatabaseSpecificFunctionalTestCase { + public SelectGeneratorTest(String x) { + super( x ); + } + + // TODO : need to determine appropriate physical generation strategies for select-generator testing on other databases... + + public String[] getMappings() { + return new String[] { "generatedkeys/select/MyEntity.hbm.xml" }; + } + + public boolean appliesTo(Dialect dialect) { + return ( dialect instanceof Oracle9Dialect ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( SelectGeneratorTest.class ); + } + + public void testJDBC3GetGeneratedKeysSupportOnOracle() { + if ( getDialect() instanceof DataDirectOracle9Dialect ) { + reportSkip( "DataDirect drivers known to not support JDBC3 getGeneratedKeys for Oracle", "oracle getGeneratedKeys support" ); + return; + } + Session session = openSession(); + session.beginTransaction(); + + MyEntity e = new MyEntity( "entity-1" ); + session.save( e ); + + // this insert should happen immediately! + assertEquals( "id not generated through forced insertion", new Long(1), e.getId() ); + + session.delete( e ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/generatedkeys/seqidentity/MyEntity.hbm.xml b/test/org/hibernate/test/generatedkeys/seqidentity/MyEntity.hbm.xml new file mode 100644 index 0000000000..81054820d9 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/seqidentity/MyEntity.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/generatedkeys/seqidentity/MyEntity.java b/test/org/hibernate/test/generatedkeys/seqidentity/MyEntity.java new file mode 100644 index 0000000000..07fc0a1734 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/seqidentity/MyEntity.java @@ -0,0 +1,28 @@ +package org.hibernate.test.generatedkeys.seqidentity; + +/** + * @author Steve Ebersole + */ +public class MyEntity { + private Long id; + private String name; + + public MyEntity() { + } + + public MyEntity(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/generatedkeys/seqidentity/SequenceIdentityTest.java b/test/org/hibernate/test/generatedkeys/seqidentity/SequenceIdentityTest.java new file mode 100644 index 0000000000..68b8749259 --- /dev/null +++ b/test/org/hibernate/test/generatedkeys/seqidentity/SequenceIdentityTest.java @@ -0,0 +1,53 @@ +package org.hibernate.test.generatedkeys.seqidentity; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.dialect.DataDirectOracle9Dialect; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Steve Ebersole + */ +public class SequenceIdentityTest extends DatabaseSpecificFunctionalTestCase { + public SequenceIdentityTest(String x) { + super( x ); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + } + + public boolean appliesTo(Dialect dialect) { + // the DataDirect driver for Oracle known to not support + // JDBC3 getGeneratedKeys... + return ( dialect instanceof Oracle9Dialect ) && ( ! ( dialect instanceof DataDirectOracle9Dialect ) ) ; + } + + public String[] getMappings() { + return new String[] { "generatedkeys/seqidentity/MyEntity.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( SequenceIdentityTest.class ); + } + + public void testSequenceIdentityGenerator() { + Session session = openSession(); + session.beginTransaction(); + + MyEntity e = new MyEntity( "entity-1" ); + session.save( e ); + + // this insert should happen immediately! + assertEquals( "id not generated through forced insertion", new Long(1), e.getId() ); + + session.delete( e ); + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/hql/ASTParserLoadingTest.java b/test/org/hibernate/test/hql/ASTParserLoadingTest.java new file mode 100644 index 0000000000..a51993fcc5 --- /dev/null +++ b/test/org/hibernate/test/hql/ASTParserLoadingTest.java @@ -0,0 +1,1916 @@ +// $Id$ +package org.hibernate.test.hql; + +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import junit.framework.Test; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.hibernate.Hibernate; +import org.hibernate.HibernateException; +import org.hibernate.Query; +import org.hibernate.QueryException; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.TypeMismatchException; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.Oracle8iDialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.dialect.SQLServerDialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.hql.ast.ASTQueryTranslatorFactory; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.stat.QueryStatistics; +import org.hibernate.test.any.IntegerPropertyValue; +import org.hibernate.test.any.PropertySet; +import org.hibernate.test.any.PropertyValue; +import org.hibernate.test.any.StringPropertyValue; +import org.hibernate.test.cid.Customer; +import org.hibernate.test.cid.LineItem; +import org.hibernate.test.cid.Order; +import org.hibernate.test.cid.Product; +import org.hibernate.transform.DistinctRootEntityResultTransformer; +import org.hibernate.transform.Transformers; +import org.hibernate.type.ComponentType; +import org.hibernate.type.ManyToOneType; +import org.hibernate.type.Type; +import org.hibernate.util.StringHelper; + +/** + * Tests the integration of the new AST parser into the loading of query results using + * the Hibernate persisters and loaders. + *

+ * Also used to test the syntax of the resulting sql against the underlying + * database, specifically for functionality not supported by the classic + * parser. + * + * @author Steve + */ +public class ASTParserLoadingTest extends FunctionalTestCase { + + private static final Log log = LogFactory.getLog( ASTParserLoadingTest.class ); + + private List createdAnimalIds = new ArrayList(); + + public ASTParserLoadingTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { + "hql/Animal.hbm.xml", + "hql/FooBarCopy.hbm.xml", + "hql/SimpleEntityWithAssociation.hbm.xml", + "hql/CrazyIdFieldNames.hbm.xml", + "batchfetch/ProductLine.hbm.xml", + "cid/Customer.hbm.xml", + "cid/Order.hbm.xml", + "cid/LineItem.hbm.xml", + "cid/Product.hbm.xml", + "any/Properties.hbm.xml", + "legacy/Commento.hbm.xml", + "legacy/Marelo.hbm.xml" + }; + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.USE_QUERY_CACHE, "true" ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + cfg.setProperty( Environment.QUERY_TRANSLATOR, ASTQueryTranslatorFactory.class.getName() ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ASTParserLoadingTest.class ); + } + + public void testInvalidCollectionDereferencesFail() { + Session s = openSession(); + s.beginTransaction(); + + // control group... + s.createQuery( "from Animal a join a.offspring o where o.description = 'xyz'" ).list(); + s.createQuery( "from Animal a join a.offspring o where o.father.description = 'xyz'" ).list(); + s.createQuery( "from Animal a join a.offspring o order by o.description" ).list(); + s.createQuery( "from Animal a join a.offspring o order by o.father.description" ).list(); + + try { + s.createQuery( "from Animal a where a.offspring.description = 'xyz'" ).list(); + fail( "illegal collection dereference semantic did not cause failure" ); + } + catch( QueryException qe ) { + log.trace( "expected failure...", qe ); + } + + try { + s.createQuery( "from Animal a where a.offspring.father.description = 'xyz'" ).list(); + fail( "illegal collection dereference semantic did not cause failure" ); + } + catch( QueryException qe ) { + log.trace( "expected failure...", qe ); + } + + try { + s.createQuery( "from Animal a order by a.offspring.description" ).list(); + fail( "illegal collection dereference semantic did not cause failure" ); + } + catch( QueryException qe ) { + log.trace( "expected failure...", qe ); + } + + try { + s.createQuery( "from Animal a order by a.offspring.father.description" ).list(); + fail( "illegal collection dereference semantic did not cause failure" ); + } + catch( QueryException qe ) { + log.trace( "expected failure...", qe ); + } + + s.getTransaction().commit(); + s.close(); + } + + /** + * Copied from {@link HQLTest#testConcatenation} + */ + public void testConcatenation() { + // simple syntax checking... + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Human h where h.nickName = '1' || 'ov' || 'tha' || 'few'" ).list(); + s.getTransaction().commit(); + s.close(); + } + + /** + * Copied from {@link HQLTest#testExpressionWithParamInFunction} + */ + public void testExpressionWithParamInFunction() { + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Animal a where abs(a.bodyWeight-:param) < 2.0" ).setLong( "param", 1 ).list(); + s.createQuery( "from Animal a where abs(:param - a.bodyWeight) < 2.0" ).setLong( "param", 1 ).list(); + if ( ! ( getDialect() instanceof HSQLDialect ) ) { + // HSQLDB does not like the abs(? - ?) syntax... + s.createQuery( "from Animal where abs(:x - :y) < 2.0" ).setLong( "x", 1 ).setLong( "y", 1 ).list(); + } + s.createQuery( "from Animal where lower(upper(:foo)) like 'f%'" ).setString( "foo", "foo" ).list(); + s.createQuery( "from Animal a where abs(abs(a.bodyWeight - 1.0 + :param) * abs(length('ffobar')-3)) = 3.0" ).setLong( "param", 1 ).list(); + s.createQuery( "from Animal where lower(upper('foo') || upper(:bar)) like 'f%'" ).setString( "bar", "xyz" ).list(); + if ( ! ( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof MySQLDialect ) ) { + s.createQuery( "from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0" ).setLong( "param", 1 ).list(); + } + s.getTransaction().commit(); + s.close(); + } + + public void testCrazyIdFieldNames() { + MoreCrazyIdFieldNameStuffEntity top = new MoreCrazyIdFieldNameStuffEntity( "top" ); + HeresAnotherCrazyIdFieldName next = new HeresAnotherCrazyIdFieldName( "next" ); + top.setHeresAnotherCrazyIdFieldName( next ); + MoreCrazyIdFieldNameStuffEntity other = new MoreCrazyIdFieldNameStuffEntity( "other" ); + Session s = openSession(); + s.beginTransaction(); + s.save( next ); + s.save( top ); + s.save( other ); + s.flush(); + + List results = s.createQuery( "select e.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e where e.heresAnotherCrazyIdFieldName is not null" ).list(); + assertEquals( 1, results.size() ); + Object result = results.get( 0 ); + assertClassAssignability( HeresAnotherCrazyIdFieldName.class, result.getClass() ); + assertSame( next, result ); + + results = s.createQuery( "select e.heresAnotherCrazyIdFieldName.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e where e.heresAnotherCrazyIdFieldName is not null" ).list(); + assertEquals( 1, results.size() ); + result = results.get( 0 ); + assertClassAssignability( Long.class, result.getClass() ); + assertEquals( next.getHeresAnotherCrazyIdFieldName(), result ); + + results = s.createQuery( "select e.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e" ).list(); + assertEquals( 1, results.size() ); + Iterator itr = s.createQuery( "select e.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e" ).iterate(); + assertTrue( itr.hasNext() ); itr.next(); assertFalse( itr.hasNext() ); + + s.delete( top ); + s.delete( next ); + s.getTransaction().commit(); + s.close(); + } + + public void testImplicitJoinsInDifferentClauses() { + // HHH-2257 : + // both the classic and ast translators output the same syntactically valid sql + // for all of these cases; the issue is that shallow (iterate) and + // non-shallow (list/scroll) queries return different results because the + // shallow skips the inner join which "weeds out" results from the non-shallow queries. + // The results were initially different depending upon the clause(s) in which the + // implicit join occurred + Session s = openSession(); + s.beginTransaction(); + SimpleEntityWithAssociation owner = new SimpleEntityWithAssociation( "owner" ); + SimpleAssociatedEntity e1 = new SimpleAssociatedEntity( "thing one", owner ); + SimpleAssociatedEntity e2 = new SimpleAssociatedEntity( "thing two" ); + s.save( e1 ); + s.save( e2 ); + s.save( owner ); + s.getTransaction().commit(); + s.close(); + + checkCounts( "select e.owner from SimpleAssociatedEntity e", 1, "implicit-join in select clause" ); + checkCounts( "select e.id, e.owner from SimpleAssociatedEntity e", 1, "implicit-join in select clause" ); + + // resolved to a "id short cut" when part of the order by clause -> no inner join = no weeding out... + checkCounts( "from SimpleAssociatedEntity e order by e.owner", 2, "implicit-join in order-by clause" ); + // resolved to a "id short cut" when part of the group by clause -> no inner join = no weeding out... + checkCounts( "select e.owner.id, count(*) from SimpleAssociatedEntity e group by e.owner", 2, "implicit-join in select and group-by clauses" ); + + s = openSession(); + s.beginTransaction(); + s.delete( e1 ); + s.delete( e2 ); + s.delete( owner ); + s.getTransaction().commit(); + s.close(); + } + + private void checkCounts(String hql, int expected, String testCondition) { + Session s = openSession(); + s.beginTransaction(); + int count = determineCount( s.createQuery( hql ).list().iterator() ); + assertEquals( "list() [" + testCondition + "]", expected, count ); + count = determineCount( s.createQuery( hql ).iterate() ); + assertEquals( "iterate() [" + testCondition + "]", expected, count ); + s.getTransaction().commit(); + s.close(); + } + + public void testImplicitSelectEntityAssociationInShallowQuery() { + // HHH-2257 : + // both the classic and ast translators output the same syntactically valid sql. + // the issue is that shallow and non-shallow queries return different + // results because the shallow skips the inner join which "weeds out" results + // from the non-shallow queries... + Session s = openSession(); + s.beginTransaction(); + SimpleEntityWithAssociation owner = new SimpleEntityWithAssociation( "owner" ); + SimpleAssociatedEntity e1 = new SimpleAssociatedEntity( "thing one", owner ); + SimpleAssociatedEntity e2 = new SimpleAssociatedEntity( "thing two" ); + s.save( e1 ); + s.save( e2 ); + s.save( owner ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + int count = determineCount( s.createQuery( "select e.id, e.owner from SimpleAssociatedEntity e" ).list().iterator() ); + assertEquals( 1, count ); // thing two would be removed from the result due to the inner join + count = determineCount( s.createQuery( "select e.id, e.owner from SimpleAssociatedEntity e" ).iterate() ); + assertEquals( 1, count ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.delete( e1 ); + s.delete( e2 ); + s.delete( owner ); + s.getTransaction().commit(); + s.close(); + } + + private int determineCount(Iterator iterator) { + int count = 0; + while( iterator.hasNext() ) { + count++; + iterator.next(); + } + return count; + } + + public void testNestedComponentIsNull() { + // (1) From MapTest originally... + // (2) Was then moved into HQLTest... + // (3) However, a bug fix to EntityType#getIdentifierOrUniqueKeyType (HHH-2138) + // caused the classic parser to suddenly start throwing exceptions on + // this query, apparently relying on the buggy behavior somehow; thus + // moved here to at least get some syntax checking... + // + // fyi... found and fixed the problem in the classic parser; still + // leaving here for syntax checking + new SyntaxChecker( "from Commento c where c.marelo.commento.mcompr is null" ).checkAll(); + } + + public void testSpecialClassPropertyReference() { + // this is a long standing bug in Hibernate when applied to joined-subclasses; + // see HHH-939 for details and history + new SyntaxChecker( "from Zoo zoo where zoo.class = PettingZoo" ).checkAll(); + new SyntaxChecker( "select a.description from Animal a where a.class = Mammal" ).checkAll(); + new SyntaxChecker( "select a.class from Animal a" ).checkAll(); + new SyntaxChecker( "from DomesticAnimal an where an.class = Dog" ).checkAll(); + new SyntaxChecker( "from Animal an where an.class = Dog" ).checkAll(); + } + + public void testSpecialClassPropertyReferenceFQN() { + // tests relating to HHH-2376 + new SyntaxChecker( "from Zoo zoo where zoo.class = org.hibernate.test.hql.PettingZoo" ).checkAll(); + new SyntaxChecker( "select a.description from Animal a where a.class = org.hibernate.test.hql.Mammal" ).checkAll(); + new SyntaxChecker( "from DomesticAnimal an where an.class = org.hibernate.test.hql.Dog" ).checkAll(); + new SyntaxChecker( "from Animal an where an.class = org.hibernate.test.hql.Dog" ).checkAll(); + } + + public void testSubclassOrSuperclassPropertyReferenceInJoinedSubclass() { + // this is a long standing bug in Hibernate; see HHH-1631 for details and history + // + // (1) pregnant is defined as a property of the class (Mammal) itself + // (2) description is defined as a property of the superclass (Animal) + // (3) name is defined as a property of a particular subclass (Human) + + new SyntaxChecker( "from Zoo z join z.mammals as m where m.name.first = 'John'" ).checkIterate(); + + new SyntaxChecker( "from Zoo z join z.mammals as m where m.pregnant = false" ).checkAll(); + new SyntaxChecker( "select m.pregnant from Zoo z join z.mammals as m where m.pregnant = false" ).checkAll(); + + new SyntaxChecker( "from Zoo z join z.mammals as m where m.description = 'tabby'" ).checkAll(); + new SyntaxChecker( "select m.description from Zoo z join z.mammals as m where m.description = 'tabby'" ).checkAll(); + + new SyntaxChecker( "from Zoo z join z.mammals as m where m.name.first = 'John'" ).checkAll(); + new SyntaxChecker( "select m.name from Zoo z join z.mammals as m where m.name.first = 'John'" ).checkAll(); + + new SyntaxChecker( "select m.pregnant from Zoo z join z.mammals as m" ).checkAll(); + new SyntaxChecker( "select m.description from Zoo z join z.mammals as m" ).checkAll(); + new SyntaxChecker( "select m.name from Zoo z join z.mammals as m" ).checkAll(); + + new SyntaxChecker( "from DomesticAnimal da join da.owner as o where o.nickName = 'Gavin'" ).checkAll(); + new SyntaxChecker( "select da.father from DomesticAnimal da join da.owner as o where o.nickName = 'Gavin'" ).checkAll(); + } + + public void testSimpleSelectWithLimitAndOffset() throws Exception { + if ( ! ( getDialect().supportsLimit() && getDialect().supportsLimitOffset() ) ) { + reportSkip( "dialect does not support offset and limit combo", "limit and offset combination" ); + return; + } + + // just checking correctness of param binding code... + Session session = openSession(); + session.createQuery( "from Animal" ) + .setFirstResult( 2 ) + .setMaxResults( 1 ) + .list(); + session.close(); + } + + public void testJPAPositionalParameterList() { + Session s = openSession(); + s.beginTransaction(); + ArrayList params = new ArrayList(); + params.add( "Doe" ); + params.add( "Public" ); + s.createQuery( "from Human where name.last in (?1)" ) + .setParameterList( "1", params ) + .list(); + s.getTransaction().commit(); + s.close(); + } + + public void testComponentQueries() { + Session s = openSession(); + s.beginTransaction(); + + Type[] types = s.createQuery( "select h.name from Human h" ).getReturnTypes(); + assertEquals( 1, types.length ); + assertTrue( types[0] instanceof ComponentType ); + + // Test the ability to perform comparisions between component values + s.createQuery( "from Human h where h.name = h.name" ).list(); + s.createQuery( "from Human h where h.name = :name" ).setParameter( "name", new Name() ).list(); + s.createQuery( "from Human where name = :name" ).setParameter( "name", new Name() ).list(); + s.createQuery( "from Human h where :name = h.name" ).setParameter( "name", new Name() ).list(); + s.createQuery( "from Human h where :name <> h.name" ).setParameter( "name", new Name() ).list(); + + // Test the ability to perform comparisions between a component and an explicit row-value + s.createQuery( "from Human h where h.name = ('John', 'X', 'Doe')" ).list(); + s.createQuery( "from Human h where ('John', 'X', 'Doe') = h.name" ).list(); + s.createQuery( "from Human h where ('John', 'X', 'Doe') <> h.name" ).list(); + s.createQuery( "from Human h where ('John', 'X', 'Doe') >= h.name" ).list(); + + s.createQuery( "from Human h order by h.name" ).list(); + + s.getTransaction().commit(); + s.close(); + } + + public void testComponentParameterBinding() { + // HHH-1774 : parameters are bound incorrectly with component parameters... + Session s = openSession(); + s.beginTransaction(); + + Order.Id oId = new Order.Id( "1234", 1 ); + + // control + s.createQuery("from Order o where o.customer.name =:name and o.id = :id") + .setParameter( "name", "oracle" ) + .setParameter( "id", oId ) + .list(); + + // this is the form that caused problems in the original case... + s.createQuery("from Order o where o.id = :id and o.customer.name =:name ") + .setParameter( "id", oId ) + .setParameter( "name", "oracle" ) + .list(); + + s.getTransaction().commit(); + s.close(); + } + + public void testAnyMappingReference() { + Session s = openSession(); + s.beginTransaction(); + + PropertyValue redValue = new StringPropertyValue( "red" ); + PropertyValue lonliestNumberValue = new IntegerPropertyValue( 1 ); + + Long id; + PropertySet ps = new PropertySet( "my properties" ); + ps.setSomeSpecificProperty( redValue ); + ps.getGeneralProperties().put( "the lonliest number", lonliestNumberValue ); + ps.getGeneralProperties().put( "i like", new StringPropertyValue( "pina coladas" ) ); + ps.getGeneralProperties().put( "i also like", new StringPropertyValue( "getting caught in the rain" ) ); + s.save( ps ); + + s.getTransaction().commit(); + id = ps.getId(); + s.clear(); + s.beginTransaction(); + + // TODO : setEntity() currently will not work here, but that would be *very* nice + // does not work because the corresponding EntityType is then used as the "bind type" rather + // than the "discovered" AnyType... + s.createQuery( "from PropertySet p where p.someSpecificProperty = :ssp" ).setParameter( "ssp", redValue ).list(); + + s.createQuery( "from PropertySet p where p.someSpecificProperty.id is not null" ).list(); + + s.createQuery( "from PropertySet p join p.generalProperties gp where gp.id is not null" ).list(); + + s.delete( s.load( PropertySet.class, id ) ); + + s.getTransaction().commit(); + s.close(); + } + + public void testJdkEnumStyleEnumConstant() throws Exception { + Session s = openSession(); + s.beginTransaction(); + + s.createQuery( "from Zoo z where z.classification = org.hibernate.test.hql.Classification.LAME" ).list(); + + s.getTransaction().commit(); + s.close(); + } + + public void testParameterTypeMismatchFailureExpected() { + Session s = openSession(); + s.beginTransaction(); + + Query query = s.createQuery( "from Animal a where a.description = :nonstring" ) + .setParameter( "nonstring", new Integer(1) ); + try { + query.list(); + fail( "query execution should have failed" ); + } + catch( TypeMismatchException tme ) { + // expected behavior + } + + s.getTransaction().commit(); + s.close(); + } + + public void testMultipleBagFetchesFail() { + Session s = openSession(); + s.beginTransaction(); + try { + s.createQuery( "from Human h join fetch h.friends f join fetch f.friends fof" ).list(); + fail( "failure expected" ); + } + catch( HibernateException e ) { + assertTrue( "unexpected failure reason : " + e, e.getMessage().indexOf( "multiple bags" ) > 0 ); + } + s.getTransaction().commit(); + s.close(); + } + + public void testCollectionJoinsInSubselect() { + // HHH-1248 : initially FromElementFactory treated any explicit join + // as an implied join so that theta-style joins would always be used. + // This was because correlated subqueries cannot use ANSI-style joins + // for the correlation. However, this special treatment was not limited + // to only correlated subqueries; it was applied to any subqueries -> + // which in-and-of-itself is not necessarily bad. But somewhere later + // the choices made there caused joins to be dropped. + Session s = openSession(); + String qryString = + "select a.id, a.description" + + " from Animal a" + + " left join a.offspring" + + " where a in (" + + " select a1 from Animal a1" + + " left join a1.offspring o" + + " where a1.id=1" + + ")"; + s.createQuery( qryString ).list(); + qryString = + "select h.id, h.description" + + " from Human h" + + " left join h.friends" + + " where h in (" + + " select h1" + + " from Human h1" + + " left join h1.friends f" + + " where h1.id=1" + + ")"; + s.createQuery( qryString ).list(); + qryString = + "select h.id, h.description" + + " from Human h" + + " left join h.friends f" + + " where f in (" + + " select h1" + + " from Human h1" + + " left join h1.friends f1" + + " where h = f1" + + ")"; + s.createQuery( qryString ).list(); + s.close(); + } + + public void testCollectionFetchWithDistinctionAndLimit() { + // create some test data... + Session s = openSession(); + Transaction t = s.beginTransaction(); + int parentCount = 30; + for ( int i = 0; i < parentCount; i++ ) { + Animal child1 = new Animal(); + child1.setDescription( "collection fetch distinction (child1 - parent" + i + ")" ); + s.persist( child1 ); + Animal child2 = new Animal(); + child2.setDescription( "collection fetch distinction (child2 - parent " + i + ")" ); + s.persist( child2 ); + Animal parent = new Animal(); + parent.setDescription( "collection fetch distinction (parent" + i + ")" ); + parent.setSerialNumber( "123-" + i ); + parent.addOffspring( child1 ); + parent.addOffspring( child2 ); + s.persist( parent ); + } + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + // Test simple distinction + List results; + results = s.createQuery( "select distinct p from Animal p inner join fetch p.offspring" ).list(); + assertEquals( "duplicate list() returns", 30, results.size() ); + // Test first/max + results = s.createQuery( "select p from Animal p inner join fetch p.offspring order by p.id" ) + .setFirstResult( 5 ) + .setMaxResults( 20 ) + .list(); + assertEquals( "duplicate returns", 20, results.size() ); + Animal firstReturn = ( Animal ) results.get( 0 ); + assertEquals( "firstResult not applied correctly", "123-5", firstReturn.getSerialNumber() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery( "delete Animal where mother is not null" ).executeUpdate(); + s.createQuery( "delete Animal" ).executeUpdate(); + t.commit(); + s.close(); + } + + public void testFetchInSubqueryFails() { + Session s = openSession(); + try { + s.createQuery( "from Animal a where a.mother in (select m from Animal a1 inner join a1.mother as m join fetch m.mother)" ).list(); + fail( "fetch join allowed in subquery" ); + } + catch( QueryException expected ) { + // expected behavior + } + s.close(); + } + + public void testQueryMetadataRetrievalWithFetching() { + // HHH-1464 : there was a problem due to the fact they we polled + // the shallow version of the query plan to get the metadata. + Session s = openSession(); + Query query = s.createQuery( "from Animal a inner join fetch a.mother" ); + assertEquals( 1, query.getReturnTypes().length ); + assertNull( query.getReturnAliases() ); + s.close(); + } + + public void testSuperclassPropertyReferenceAfterCollectionIndexedAccess() { + // note: simply performing syntax checking in the db + // test for HHH-429 + Session s = openSession(); + s.beginTransaction(); + Mammal tiger = new Mammal(); + tiger.setDescription( "Tiger" ); + s.persist( tiger ); + Mammal mother = new Mammal(); + mother.setDescription( "Tiger's mother" ); + mother.setBodyWeight( 4.0f ); + mother.addOffspring( tiger ); + s.persist( mother ); + Zoo zoo = new Zoo(); + zoo.setName( "Austin Zoo" ); + zoo.setMammals( new HashMap() ); + zoo.getMammals().put( "tiger", tiger ); + s.persist( zoo ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + List results = s.createQuery( "from Zoo zoo where zoo.mammals['tiger'].mother.bodyWeight > 3.0f" ).list(); + assertEquals( 1, results.size() ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.delete( tiger ); + s.delete( mother ); + s.delete( zoo ); + s.getTransaction().commit(); + s.close(); + } + + public void testJoinFetchCollectionOfValues() { + // note: simply performing syntax checking in the db + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "select h from Human as h join fetch h.nickNames" ).list(); + s.getTransaction().commit(); + s.close(); + } + + public void testIntegerLiterals() { + // note: simply performing syntax checking in the db + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Foo where long = 1" ).list(); + s.createQuery( "from Foo where long = " + Integer.MIN_VALUE ).list(); + s.createQuery( "from Foo where long = " + Integer.MAX_VALUE ).list(); + s.createQuery( "from Foo where long = 1L" ).list(); + s.createQuery( "from Foo where long = " + (Long.MIN_VALUE + 1) + "L" ).list(); + s.createQuery( "from Foo where long = " + Long.MAX_VALUE + "L" ).list(); + s.createQuery( "from Foo where integer = " + (Long.MIN_VALUE + 1) ).list(); +// currently fails due to HHH-1387 +// s.createQuery( "from Foo where long = " + Long.MIN_VALUE ).list(); + s.getTransaction().commit(); + s.close(); + } + + public void testDecimalLiterals() { + // note: simply performing syntax checking in the db + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Animal where bodyWeight > 100.0e-10" ).list(); + s.createQuery( "from Animal where bodyWeight > 100.0E-10" ).list(); + s.createQuery( "from Animal where bodyWeight > 100.001f" ).list(); + s.createQuery( "from Animal where bodyWeight > 100.001F" ).list(); + s.createQuery( "from Animal where bodyWeight > 100.001d" ).list(); + s.createQuery( "from Animal where bodyWeight > 100.001D" ).list(); + s.createQuery( "from Animal where bodyWeight > .001f" ).list(); + s.createQuery( "from Animal where bodyWeight > 100e-10" ).list(); + s.createQuery( "from Animal where bodyWeight > .01E-10" ).list(); + s.createQuery( "from Animal where bodyWeight > 1e-38" ).list(); + s.getTransaction().commit(); + s.close(); + } + + public void testNakedPropertyRef() { + // note: simply performing syntax and column/table resolution checking in the db + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Animal where bodyWeight = bodyWeight" ).list(); + s.createQuery( "select bodyWeight from Animal" ).list(); + s.createQuery( "select max(bodyWeight) from Animal" ).list(); + s.getTransaction().commit(); + s.close(); + } + + public void testNakedComponentPropertyRef() { + // note: simply performing syntax and column/table resolution checking in the db + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Human where name.first = 'Gavin'" ).list(); + s.createQuery( "select name from Human" ).list(); + s.createQuery( "select upper(h.name.first) from Human as h" ).list(); + s.createQuery( "select upper(name.first) from Human" ).list(); + s.getTransaction().commit(); + s.close(); + } + + public void testNakedImplicitJoins() { + // note: simply performing syntax and column/table resolution checking in the db + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Animal where mother.father.id = 1" ).list(); + s.getTransaction().commit(); + s.close(); + } + + public void testNakedEntityAssociationReference() { + // note: simply performing syntax and column/table resolution checking in the db + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Animal where mother = :mother" ).setParameter( "mother", null ).list(); + s.getTransaction().commit(); + s.close(); + } + + public void testNakedMapIndex() throws Exception { + // note: simply performing syntax and column/table resolution checking in the db + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "from Zoo where mammals['dog'].description like '%black%'" ).list(); + s.getTransaction().commit(); + s.close(); + } + + public void testInvalidFetchSemantics() { + Session s = openSession(); + s.beginTransaction(); + + try { + s.createQuery( "select mother from Human a left join fetch a.mother mother" ).list(); + fail( "invalid fetch semantic allowed!" ); + } + catch( QueryException e ) { + } + + try { + s.createQuery( "select mother from Human a left join fetch a.mother mother" ).list(); + fail( "invalid fetch semantic allowed!" ); + } + catch( QueryException e ) { + } + + s.getTransaction().commit(); + s.close(); + } + + public void testArithmetic() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Zoo zoo = new Zoo(); + zoo.setName("Melbourne Zoo"); + s.persist(zoo); + s.createQuery("select 2*2*2*2*(2*2) from Zoo").uniqueResult(); + s.createQuery("select 2 / (1+1) from Zoo").uniqueResult(); + int result0 = ( (Integer) s.createQuery("select 2 - (1+1) from Zoo").uniqueResult() ).intValue(); + int result1 = ( (Integer) s.createQuery("select 2 - 1 + 1 from Zoo").uniqueResult() ).intValue(); + int result2 = ( (Integer) s.createQuery("select 2 * (1-1) from Zoo").uniqueResult() ).intValue(); + int result3 = ( (Integer) s.createQuery("select 4 / (2 * 2) from Zoo").uniqueResult() ).intValue(); + int result4 = ( (Integer) s.createQuery("select 4 / 2 * 2 from Zoo").uniqueResult() ).intValue(); + int result5 = ( (Integer) s.createQuery("select 2 * (2/2) from Zoo").uniqueResult() ).intValue(); + int result6 = ( (Integer) s.createQuery("select 2 * (2/2+1) from Zoo").uniqueResult() ).intValue(); + assertEquals(result0, 0); + assertEquals(result1, 2); + assertEquals(result2, 0); + assertEquals(result3, 1); + assertEquals(result4, 4); + assertEquals(result5, 2); + assertEquals(result6, 4); + s.delete(zoo); + t.commit(); + s.close(); + } + + public void testNestedCollectionFetch() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createQuery("from Animal a left join fetch a.offspring o left join fetch o.offspring where a.mother.id = 1 order by a.description").list(); + s.createQuery("from Zoo z left join fetch z.animals a left join fetch a.offspring where z.name ='MZ' order by a.description").list(); + s.createQuery("from Human h left join fetch h.pets a left join fetch a.offspring where h.name.first ='Gavin' order by a.description").list(); + t.commit(); + s.close(); + } + + public void testSelectClauseSubselect() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Zoo zoo = new Zoo(); + zoo.setName("Melbourne Zoo"); + zoo.setMammals( new HashMap() ); + zoo.setAnimals( new HashMap() ); + Mammal plat = new Mammal(); + plat.setBodyWeight( 11f ); + plat.setDescription( "Platypus" ); + plat.setZoo(zoo); + plat.setSerialNumber("plat123"); + zoo.getMammals().put("Platypus", plat); + zoo.getAnimals().put("plat123", plat); + s.persist( plat ); + s.persist(zoo); + + s.createQuery("select (select max(z.id) from a.zoo z) from Animal a").list(); + s.createQuery("select (select max(z.id) from a.zoo z where z.name=:name) from Animal a") + .setParameter("name", "Melbourne Zoo").list(); + + s.delete(plat); + s.delete(zoo); + t.commit(); + s.close(); + } + + public void testInitProxy() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Mammal plat = new Mammal(); + plat.setBodyWeight( 11f ); + plat.setDescription( "Platypus" ); + s.persist( plat ); + s.flush(); + s.clear(); + plat = (Mammal) s.load(Mammal.class, plat.getId() ); + assertFalse( Hibernate.isInitialized(plat) ); + Object plat2 = s.createQuery("from Animal a").uniqueResult(); + assertSame(plat, plat2); + assertTrue( Hibernate.isInitialized(plat) ); + s.delete(plat); + t.commit(); + s.close(); + } + + public void testSelectClauseImplicitJoin() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Zoo zoo = new Zoo(); + zoo.setName("The Zoo"); + zoo.setMammals( new HashMap() ); + zoo.setAnimals( new HashMap() ); + Mammal plat = new Mammal(); + plat.setBodyWeight( 11f ); + plat.setDescription( "Platypus" ); + plat.setZoo(zoo); + plat.setSerialNumber("plat123"); + zoo.getMammals().put("Platypus", plat); + zoo.getAnimals().put("plat123", plat); + s.persist( plat ); + s.persist(zoo); + s.flush(); + s.clear(); + Query q = s.createQuery("select distinct a.zoo from Animal a where a.zoo is not null"); + Type type = q.getReturnTypes()[0]; + assertTrue( type instanceof ManyToOneType ); + assertEquals( ( (ManyToOneType) type ).getAssociatedEntityName(), "org.hibernate.test.hql.Zoo" ); + zoo = (Zoo) q.list().get(0); + assertEquals( zoo.getMammals().size(), 1 ); + assertEquals( zoo.getAnimals().size(), 1 ); + s.clear(); + s.delete(plat); + s.delete(zoo); + t.commit(); + s.close(); + } + + public void testSelectClauseImplicitJoinWithIterate() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Zoo zoo = new Zoo(); + zoo.setName("The Zoo"); + zoo.setMammals( new HashMap() ); + zoo.setAnimals( new HashMap() ); + Mammal plat = new Mammal(); + plat.setBodyWeight( 11f ); + plat.setDescription( "Platypus" ); + plat.setZoo(zoo); + plat.setSerialNumber("plat123"); + zoo.getMammals().put("Platypus", plat); + zoo.getAnimals().put("plat123", plat); + s.persist( plat ); + s.persist(zoo); + s.flush(); + s.clear(); + Query q = s.createQuery("select distinct a.zoo from Animal a where a.zoo is not null"); + Type type = q.getReturnTypes()[0]; + assertTrue( type instanceof ManyToOneType ); + assertEquals( ( (ManyToOneType) type ).getAssociatedEntityName(), "org.hibernate.test.hql.Zoo" ); + zoo = (Zoo) q + .iterate().next(); + assertEquals( zoo.getMammals().size(), 1 ); + assertEquals( zoo.getAnimals().size(), 1 ); + s.clear(); + s.delete(plat); + s.delete(zoo); + t.commit(); + s.close(); + } + + public void testComponentOrderBy() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Long id1 = ( Long ) s.save( genSimpleHuman( "John", "Jacob" ) ); + Long id2 = ( Long ) s.save( genSimpleHuman( "Jingleheimer", "Schmidt" ) ); + + s.flush(); + + // the component is defined with the firstName column first... + List results = s.createQuery( "from Human as h order by h.name" ).list(); + assertEquals( "Incorrect return count", 2, results.size() ); + + Human h1 = ( Human ) results.get( 0 ); + Human h2 = ( Human ) results.get( 1 ); + + assertEquals( "Incorrect ordering", id2, h1.getId() ); + assertEquals( "Incorrect ordering", id1, h2.getId() ); + + s.delete( h1 ); + s.delete( h2 ); + + t.commit(); + s.close(); + } + + private Human genSimpleHuman(String fName, String lName) { + Human h = new Human(); + h.setName( new Name( fName, 'X', lName ) ); + + return h; + } + + public void testCastInSelect() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Animal a = new Animal(); + a.setBodyWeight(12.4f); + a.setDescription("an animal"); + s.persist(a); + Integer bw = (Integer) s.createQuery("select cast(bodyWeight as integer) from Animal").uniqueResult(); + bw = (Integer) s.createQuery("select cast(a.bodyWeight as integer) from Animal a").uniqueResult(); + bw.toString(); + s.delete(a); + t.commit(); + s.close(); + } + + public void testAliases() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Animal a = new Animal(); + a.setBodyWeight(12.4f); + a.setDescription("an animal"); + s.persist(a); + String[] aliases1 = s.createQuery("select a.bodyWeight as abw, a.description from Animal a").getReturnAliases(); + assertEquals(aliases1[0], "abw"); + assertEquals(aliases1[1], "1"); + String[] aliases2 = s.createQuery("select count(*), avg(a.bodyWeight) as avg from Animal a").getReturnAliases(); + assertEquals(aliases2[0], "0"); + assertEquals(aliases2[1], "avg"); + s.delete(a); + t.commit(); + s.close(); + } + + public void testParameterMixing() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createQuery( "from Animal a where a.description = ? and a.bodyWeight = ? or a.bodyWeight = :bw" ) + .setString( 0, "something" ) + .setFloat( 1, 12345f ) + .setFloat( "bw", 123f ) + .list(); + t.commit(); + s.close(); + } + + public void testOrdinalParameters() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createQuery( "from Animal a where a.description = ? and a.bodyWeight = ?" ) + .setString( 0, "something" ) + .setFloat( 1, 123f ) + .list(); + s.createQuery( "from Animal a where a.bodyWeight in (?, ?)" ) + .setFloat( 0, 999f ) + .setFloat( 1, 123f ) + .list(); + t.commit(); + s.close(); + } + + public void testIndexParams() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createQuery("from Zoo zoo where zoo.mammals[:name] = :id") + .setParameter("name", "Walrus") + .setParameter("id", new Long(123)) + .list(); + s.createQuery("from Zoo zoo where zoo.mammals[:name].bodyWeight > :w") + .setParameter("name", "Walrus") + .setParameter("w", new Float(123.32)) + .list(); + s.createQuery("from Zoo zoo where zoo.animals[:sn].mother.bodyWeight < :mw") + .setParameter("sn", "ant-123") + .setParameter("mw", new Float(23.32)) + .list(); + /*s.createQuery("from Zoo zoo where zoo.animals[:sn].description like :desc and zoo.animals[:sn].bodyWeight > :wmin and zoo.animals[:sn].bodyWeight < :wmax") + .setParameter("sn", "ant-123") + .setParameter("desc", "%big%") + .setParameter("wmin", new Float(123.32)) + .setParameter("wmax", new Float(167.89)) + .list();*/ + /*s.createQuery("from Human where addresses[:type].city = :city and addresses[:type].country = :country") + .setParameter("type", "home") + .setParameter("city", "Melbourne") + .setParameter("country", "Australia") + .list();*/ + t.commit(); + s.close(); + } + + public void testAggregation() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Human h = new Human(); + h.setBodyWeight( (float) 74.0 ); + h.setHeight(120.5); + h.setDescription("Me"); + h.setName( new Name("Gavin", 'A', "King") ); + h.setNickName("Oney"); + s.persist(h); + Double sum = (Double) s.createQuery("select sum(h.bodyWeight) from Human h").uniqueResult(); + Double avg = (Double) s.createQuery("select avg(h.height) from Human h").uniqueResult(); + assertEquals(sum.floatValue(), 74.0, 0.01); + assertEquals(avg.doubleValue(), 120.5, 0.01); + Long id = (Long) s.createQuery("select max(a.id) from Animal a").uniqueResult(); + s.delete(h); + t.commit(); + s.close(); + } + + public void testSelectClauseCase() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Human h = new Human(); + h.setBodyWeight( (float) 74.0 ); + h.setHeight(120.5); + h.setDescription("Me"); + h.setName( new Name("Gavin", 'A', "King") ); + h.setNickName("Oney"); + s.persist(h); + String name = (String) s.createQuery("select case nickName when 'Oney' then 'gavin' when 'Turin' then 'christian' else nickName end from Human").uniqueResult(); + assertEquals(name, "gavin"); + String result = (String) s.createQuery("select case when bodyWeight > 100 then 'fat' else 'skinny' end from Human").uniqueResult(); + assertEquals(result, "skinny"); + s.delete(h); + t.commit(); + s.close(); + } + + public void testImplicitPolymorphism() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Product product = new Product(); + product.setDescription( "My Product" ); + product.setNumberAvailable( 10 ); + product.setPrice( new BigDecimal( 123 ) ); + product.setProductId( "4321" ); + s.save( product ); + + List list = s.createQuery("from java.lang.Comparable").list(); + assertEquals( list.size(), 0 ); + + list = s.createQuery("from java.lang.Object").list(); + assertEquals( list.size(), 1 ); + + s.delete(product); + + list = s.createQuery("from java.lang.Object").list(); + assertEquals( list.size(), 0 ); + + t.commit(); + s.close(); + } + + public void testCoalesce() { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + session.createQuery("from Human h where coalesce(h.nickName, h.name.first, h.name.last) = 'max'").list(); + session.createQuery("select nullif(nickName, '1e1') from Human").list(); + txn.commit(); + session.close(); + } + + public void testStr() { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + Animal an = new Animal(); + an.setBodyWeight(123.45f); + session.persist(an); + String str = (String) session.createQuery("select str(an.bodyWeight) from Animal an where str(an.bodyWeight) like '123%' or str(an.bodyWeight) like '1.23%'").uniqueResult(); + if ( getDialect() instanceof DB2Dialect ) { + assertTrue( str.startsWith("1.234") ); + } + else if ( getDialect() instanceof SQLServerDialect ) { + // no assertion as SQLServer always returns nulls here; even trying directly against the + // database, it seems to have problems with str() in the where clause... + } + else { + assertTrue( str.startsWith("123.4") ); + } + if ( ! ( getDialect() instanceof SybaseDialect ) ) { + // In TransactSQL (the variant spoken by Sybase and SQLServer), the str() function + // is explicitly intended for numeric values only... + String dateStr1 = (String) session.createQuery("select str(current_date) from Animal").uniqueResult(); + String dateStr2 = (String) session.createQuery("select str(year(current_date))||'-'||str(month(current_date))||'-'||str(day(current_date)) from Animal").uniqueResult(); + System.out.println(dateStr1 + '=' + dateStr2); + if ( ! ( getDialect() instanceof Oracle9Dialect || getDialect() instanceof Oracle8iDialect ) ) { //Oracle renders the name of the month :( + String[] dp1 = StringHelper.split("-", dateStr1); + String[] dp2 = StringHelper.split("-", dateStr2); + for (int i=0; i<3; i++) { + if ( dp1[i].startsWith( "0" ) ) { + dp1[i] = dp1[i].substring( 1 ); + } + assertEquals( dp1[i], dp2[i] ); + } + } + } + session.delete(an); + txn.commit(); + session.close(); + } + + public void testCast() { + if ( ( getDialect() instanceof MySQLDialect ) || ( getDialect() instanceof DB2Dialect ) ) { + return; + } + Session session = openSession(); + Transaction txn = session.beginTransaction(); + session.createQuery("from Human h where h.nickName like 'G%'").list(); + session.createQuery("from Animal a where cast(a.bodyWeight as string) like '1.%'").list(); + session.createQuery("from Animal a where cast(a.bodyWeight as integer) = 1").list(); + txn.commit(); + session.close(); + } + + public void testExtract() { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + session.createQuery("select second(current_timestamp()), minute(current_timestamp()), hour(current_timestamp()) from Mammal m").list(); + session.createQuery("select day(m.birthdate), month(m.birthdate), year(m.birthdate) from Mammal m").list(); + if ( !(getDialect() instanceof DB2Dialect) ) { //no ANSI extract + session.createQuery("select extract(second from current_timestamp()), extract(minute from current_timestamp()), extract(hour from current_timestamp()) from Mammal m").list(); + session.createQuery("select extract(day from m.birthdate), extract(month from m.birthdate), extract(year from m.birthdate) from Mammal m").list(); + } + txn.commit(); + session.close(); + } + + public void testOneToManyFilter() throws Throwable { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + + Product product = new Product(); + product.setDescription( "My Product" ); + product.setNumberAvailable( 10 ); + product.setPrice( new BigDecimal( 123 ) ); + product.setProductId( "4321" ); + session.save( product ); + + Customer customer = new Customer(); + customer.setCustomerId( "123456789" ); + customer.setName( "My customer" ); + customer.setAddress( "somewhere" ); + session.save( customer ); + + Order order = customer.generateNewOrder( new BigDecimal( 1234 ) ); + session.save( order ); + + LineItem li = order.generateLineItem( product, 5 ); + session.save( li ); + + session.flush(); + + assertEquals( session.createFilter( customer.getOrders(), "" ).list().size(), 1 ); + + assertEquals( session.createFilter( order.getLineItems(), "" ).list().size(), 1 ); + assertEquals( session.createFilter( order.getLineItems(), "where this.quantity > :quantity" ).setInteger( "quantity", 5 ).list().size(), 0 ); + + session.delete(li); + session.delete(order); + session.delete(product); + session.delete(customer); + txn.commit(); + session.close(); + } + + public void testManyToManyFilter() throws Throwable { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + + Human human = new Human(); + human.setName( new Name( "Steve", 'L', "Ebersole" ) ); + session.save( human ); + + Human friend = new Human(); + friend.setName( new Name( "John", 'Q', "Doe" ) ); + friend.setBodyWeight( 11.0f ); + session.save( friend ); + + human.setFriends( new ArrayList() ); + friend.setFriends( new ArrayList() ); + human.getFriends().add( friend ); + friend.getFriends().add( human ); + + session.flush(); + + assertEquals( session.createFilter( human.getFriends(), "" ).list().size(), 1 ); + assertEquals( session.createFilter( human.getFriends(), "where this.bodyWeight > ?" ).setFloat( 0, 10f ).list().size(), 1 ); + assertEquals( session.createFilter( human.getFriends(), "where this.bodyWeight < ?" ).setFloat( 0, 10f ).list().size(), 0 ); + + session.delete(human); + session.delete(friend); + + txn.commit(); + session.close(); + } + + public void testSelectExpressions() { + createTestBaseData(); + Session session = openSession(); + Transaction txn = session.beginTransaction(); + Human h = new Human(); + h.setName( new Name("Gavin", 'A', "King") ); + h.setNickName("Oney"); + h.setBodyWeight(1.0f); + session.persist(h); + List results = session.createQuery("select 'found', lower(h.name.first) from Human h where lower(h.name.first) = 'gavin'").list(); + results = session.createQuery("select 'found', lower(h.name.first) from Human h where concat(h.name.first, ' ', h.name.initial, ' ', h.name.last) = 'Gavin A King'").list(); + results = session.createQuery("select 'found', lower(h.name.first) from Human h where h.name.first||' '||h.name.initial||' '||h.name.last = 'Gavin A King'").list(); + results = session.createQuery("select a.bodyWeight + m.bodyWeight from Animal a join a.mother m").list(); + results = session.createQuery("select 2.0 * (a.bodyWeight + m.bodyWeight) from Animal a join a.mother m").list(); + results = session.createQuery("select sum(a.bodyWeight + m.bodyWeight) from Animal a join a.mother m").list(); + results = session.createQuery("select sum(a.mother.bodyWeight * 2.0) from Animal a").list(); + results = session.createQuery("select concat(h.name.first, ' ', h.name.initial, ' ', h.name.last) from Human h").list(); + results = session.createQuery("select h.name.first||' '||h.name.initial||' '||h.name.last from Human h").list(); + results = session.createQuery("select nickName from Human").list(); + results = session.createQuery("select lower(nickName) from Human").list(); + results = session.createQuery("select abs(bodyWeight*-1) from Human").list(); + results = session.createQuery("select upper(h.name.first||' ('||h.nickName||')') from Human h").list(); + results = session.createQuery("select abs(a.bodyWeight-:param) from Animal a").setParameter("param", new Float(2.0)).list(); + results = session.createQuery("select abs(:param - a.bodyWeight) from Animal a").setParameter("param", new Float(2.0)).list(); + results = session.createQuery("select lower(upper('foo')) from Animal").list(); + results = session.createQuery("select lower(upper('foo') || upper('bar')) from Animal").list(); + results = session.createQuery("select sum(abs(bodyWeight - 1.0) * abs(length('ffobar')-3)) from Animal").list(); + session.delete(h); + txn.commit(); + session.close(); + destroyTestBaseData(); + } + + private void createTestBaseData() { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + + Mammal m1 = new Mammal(); + m1.setBodyWeight( 11f ); + m1.setDescription( "Mammal #1" ); + + session.save( m1 ); + + Mammal m2 = new Mammal(); + m2.setBodyWeight( 9f ); + m2.setDescription( "Mammal #2" ); + m2.setMother( m1 ); + + session.save( m2 ); + + txn.commit(); + session.close(); + + createdAnimalIds.add( m1.getId() ); + createdAnimalIds.add( m2.getId() ); + } + + private void destroyTestBaseData() { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + + for ( int i = 0; i < createdAnimalIds.size(); i++ ) { + Animal animal = ( Animal ) session.load( Animal.class, ( Long ) createdAnimalIds.get( i ) ); + session.delete( animal ); + } + + txn.commit(); + session.close(); + } + + public void testImplicitJoin() throws Exception { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Animal a = new Animal(); + a.setBodyWeight(0.5f); + a.setBodyWeight(1.5f); + Animal b = new Animal(); + Animal mother = new Animal(); + mother.setBodyWeight(10.0f); + mother.addOffspring(a); + mother.addOffspring(b); + session.persist(a); + session.persist(b); + session.persist(mother); + List list = session.createQuery("from Animal a where a.mother.bodyWeight < 2.0 or a.mother.bodyWeight > 9.0").list(); + assertEquals( list.size(), 2 ); + list = session.createQuery("from Animal a where a.mother.bodyWeight > 2.0 and a.mother.bodyWeight > 9.0").list(); + assertEquals( list.size(), 2 ); + session.delete(b); + session.delete(a); + session.delete(mother); + t.commit(); + session.close(); + } + + public void testFromOnly() throws Exception { + + createTestBaseData(); + + Session session = openSession(); + + List results = session.createQuery( "from Animal" ).list(); + assertEquals( "Incorrect result size", 2, results.size() ); + assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal ); + + session.close(); + + destroyTestBaseData(); + } + + public void testSimpleSelect() throws Exception { + + createTestBaseData(); + + Session session = openSession(); + + List results = session.createQuery( "select a from Animal as a" ).list(); + assertEquals( "Incorrect result size", 2, results.size() ); + assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal ); + + session.close(); + + destroyTestBaseData(); + } + + public void testEntityPropertySelect() throws Exception { + + createTestBaseData(); + + Session session = openSession(); + + List results = session.createQuery( "select a.mother from Animal as a" ).list(); +// assertEquals("Incorrect result size", 2, results.size()); + assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal ); + + session.close(); + + destroyTestBaseData(); + } + + public void testWhere() throws Exception { + + createTestBaseData(); + + Session session = openSession(); + List results = null; + + results = session.createQuery( "from Animal an where an.bodyWeight > 10" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + + results = session.createQuery( "from Animal an where not an.bodyWeight > 10" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + + results = session.createQuery( "from Animal an where an.bodyWeight between 0 and 10" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + + results = session.createQuery( "from Animal an where an.bodyWeight not between 0 and 10" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + + results = session.createQuery( "from Animal an where sqrt(an.bodyWeight)/2 > 10" ).list(); + assertEquals( "Incorrect result size", 0, results.size() ); + + results = session.createQuery( "from Animal an where (an.bodyWeight > 10 and an.bodyWeight < 100) or an.bodyWeight is null" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + + session.close(); + + destroyTestBaseData(); + } + + public void testEntityFetching() throws Exception { + + createTestBaseData(); + + Session session = openSession(); + + List results = session.createQuery( "from Animal an join fetch an.mother" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal ); + Animal mother = ( ( Animal ) results.get( 0 ) ).getMother(); + assertTrue( "fetch uninitialized", mother != null && Hibernate.isInitialized( mother ) ); + + results = session.createQuery( "select an from Animal an join fetch an.mother" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal ); + mother = ( ( Animal ) results.get( 0 ) ).getMother(); + assertTrue( "fetch uninitialized", mother != null && Hibernate.isInitialized( mother ) ); + + session.close(); + + destroyTestBaseData(); + } + + public void testCollectionFetching() throws Exception { + + createTestBaseData(); + + Session session = openSession(); + List results = session.createQuery( "from Animal an join fetch an.offspring" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal ); + Collection os = ( ( Animal ) results.get( 0 ) ).getOffspring(); + assertTrue( "fetch uninitialized", os != null && Hibernate.isInitialized( os ) && os.size() == 1 ); + + results = session.createQuery( "select an from Animal an join fetch an.offspring" ).list(); + assertEquals( "Incorrect result size", 1, results.size() ); + assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal ); + os = ( ( Animal ) results.get( 0 ) ).getOffspring(); + assertTrue( "fetch uninitialized", os != null && Hibernate.isInitialized( os ) && os.size() == 1 ); + + session.close(); + + destroyTestBaseData(); + } + + public void testProjectionQueries() throws Exception { + + createTestBaseData(); + + Session session = openSession(); + + List results = session.createQuery( "select an.mother.id, max(an.bodyWeight) from Animal an group by an.mother.id" ).list(); + // mysql returns nulls in this group by + assertEquals( "Incorrect result size", 2, results.size() ); + assertTrue( "Incorrect return type", results.get( 0 ) instanceof Object[] ); + assertEquals( "Incorrect return dimensions", 2, ( ( Object[] ) results.get( 0 ) ).length ); + + session.close(); + + destroyTestBaseData(); + + } + + public void testStandardFunctions() throws Exception { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product p = new Product(); + p.setDescription("a product"); + p.setPrice( new BigDecimal(1.0) ); + p.setProductId("abc123"); + session.persist(p); + Object[] result = (Object[]) session + .createQuery("select current_time(), current_date(), current_timestamp() from Product") + .uniqueResult(); + assertTrue( result[0] instanceof Time ); + assertTrue( result[1] instanceof Date ); + assertTrue( result[2] instanceof Timestamp ); + assertNotNull( result[0] ); + assertNotNull( result[1] ); + assertNotNull( result[2] ); + session.delete(p); + t.commit(); + session.close(); + + } + + public void testDynamicInstantiationQueries() throws Exception { + + createTestBaseData(); + + Session session = openSession(); + + List results = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ).list(); + assertEquals( "Incorrect result size", 2, results.size() ); + assertClassAssignability( results.get( 0 ).getClass(), Animal.class ); + + Iterator iter = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ).iterate(); + assertTrue( "Incorrect result size", iter.hasNext() ); + assertTrue( "Incorrect return type", iter.next() instanceof Animal ); + + results = session.createQuery( "select new list(an.description, an.bodyWeight) from Animal an" ).list(); + assertEquals( "Incorrect result size", 2, results.size() ); + assertTrue( "Incorrect return type", results.get( 0 ) instanceof List ); + assertEquals( "Incorrect return type", ( (List) results.get( 0 ) ).size(), 2 ); + + results = session.createQuery( "select new list(an.description, an.bodyWeight) from Animal an" ).list(); + assertEquals( "Incorrect result size", 2, results.size() ); + assertTrue( "Incorrect return type", results.get( 0 ) instanceof List ); + assertEquals( "Incorrect return type", ( (List) results.get( 0 ) ).size(), 2 ); + + iter = session.createQuery( "select new list(an.description, an.bodyWeight) from Animal an" ).iterate(); + assertTrue( "Incorrect result size", iter.hasNext() ); + Object obj = iter.next(); + assertTrue( "Incorrect return type", obj instanceof List ); + assertEquals( "Incorrect return type", ( (List) obj ).size(), 2 ); + + iter = ((org.hibernate.classic.Session)session).iterate( "select new list(an.description, an.bodyWeight) from Animal an" ); + assertTrue( "Incorrect result size", iter.hasNext() ); + obj = iter.next(); + assertTrue( "Incorrect return type", obj instanceof List ); + assertEquals( "Incorrect return type", ( (List) obj ).size(), 2 ); + + results = session.createQuery( "select new map(an.description, an.bodyWeight) from Animal an" ).list(); + assertEquals( "Incorrect result size", 2, results.size() ); + assertTrue( "Incorrect return type", results.get( 0 ) instanceof Map ); + assertEquals( "Incorrect return type", ( (Map) results.get( 0 ) ).size(), 2 ); + assertTrue( ( (Map) results.get( 0 ) ).containsKey("0") ); + assertTrue( ( (Map) results.get( 0 ) ).containsKey("1") ); + + results = session.createQuery( "select new map(an.description as descr, an.bodyWeight as bw) from Animal an" ).list(); + assertEquals( "Incorrect result size", 2, results.size() ); + assertTrue( "Incorrect return type", results.get( 0 ) instanceof Map ); + assertEquals( "Incorrect return type", ( (Map) results.get( 0 ) ).size(), 2 ); + assertTrue( ( (Map) results.get( 0 ) ).containsKey("descr") ); + assertTrue( ( (Map) results.get( 0 ) ).containsKey("bw") ); + + iter = session.createQuery( "select new map(an.description, an.bodyWeight) from Animal an" ).iterate(); + assertTrue( "Incorrect result size", iter.hasNext() ); + obj = iter.next(); + assertTrue( "Incorrect return type", obj instanceof Map ); + assertEquals( "Incorrect return type", ( (Map) obj ).size(), 2 ); + + ScrollableResults sr = session.createQuery( "select new map(an.description, an.bodyWeight) from Animal an" ).scroll(); + assertTrue( "Incorrect result size", sr.next() ); + obj = sr.get(0); + assertTrue( "Incorrect return type", obj instanceof Map ); + assertEquals( "Incorrect return type", ( (Map) obj ).size(), 2 ); + sr.close(); + + sr = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ).scroll(); + assertTrue( "Incorrect result size", sr.next() ); + assertTrue( "Incorrect return type", sr.get(0) instanceof Animal ); + sr.close(); + + // caching... + QueryStatistics stats = getSessions().getStatistics().getQueryStatistics( "select new Animal(an.description, an.bodyWeight) from Animal an" ); + results = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ) + .setCacheable( true ) + .list(); + assertEquals( "incorrect result size", 2, results.size() ); + assertClassAssignability( Animal.class, results.get( 0 ).getClass() ); + long initCacheHits = stats.getCacheHitCount(); + results = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ) + .setCacheable( true ) + .list(); + assertEquals( "dynamic intantiation query not served from cache", initCacheHits + 1, stats.getCacheHitCount() ); + assertEquals( "incorrect result size", 2, results.size() ); + assertClassAssignability( Animal.class, results.get( 0 ).getClass() ); + + session.close(); + + destroyTestBaseData(); + } + + public void testIllegalMixedTransformerQueries() { + Session session = openSession(); + + try { + getSelectNewQuery( session ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list(); + fail("'select new' together with a resulttransformer should result in error!"); + } catch(QueryException he) { + assertTrue(he.getMessage().indexOf("ResultTransformer")==0); + } + + try { + getSelectNewQuery( session ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).iterate(); + fail("'select new' together with a resulttransformer should result in error!"); + } catch(HibernateException he) { + assertTrue(he.getMessage().indexOf("ResultTransformer")==0); + } + + try { + getSelectNewQuery( session ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).scroll(); + fail("'select new' together with a resulttransformer should result in error!"); + } catch(HibernateException he) { + assertTrue(he.getMessage().indexOf("ResultTransformer")==0); + } + + session.close(); + } + + private Query getSelectNewQuery(Session session) { + return session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ); + } + public void testResultTransformerScalarQueries() throws Exception { + + createTestBaseData(); + + String query = "select an.description as description, an.bodyWeight as bodyWeight from Animal an order by bodyWeight desc"; + + Session session = openSession(); + + List results = session.createQuery( query ) + .setResultTransformer(Transformers.aliasToBean(Animal.class)).list(); + assertEquals( "Incorrect result size", results.size(), 2 ); + assertTrue( "Incorrect return type", results.get(0) instanceof Animal ); + Animal firstAnimal = (Animal) results.get(0); + Animal secondAnimal = (Animal) results.get(1); + assertEquals("Mammal #1", firstAnimal.getDescription()); + assertEquals("Mammal #2", secondAnimal.getDescription()); + assertFalse(session.contains(firstAnimal)); + session.close(); + + session = openSession(); + + Iterator iter = session.createQuery( query ) + .setResultTransformer(Transformers.aliasToBean(Animal.class)).iterate(); + assertTrue( "Incorrect result size", iter.hasNext() ); + assertTrue( "Incorrect return type", iter.next() instanceof Animal ); + + session.close(); + + session = openSession(); + + ScrollableResults sr = session.createQuery( query ) + .setResultTransformer(Transformers.aliasToBean(Animal.class)).scroll(); + assertTrue( "Incorrect result size", sr.next() ); + assertTrue( "Incorrect return type", sr.get(0) instanceof Animal ); + assertFalse(session.contains(sr.get(0))); + sr.close(); + + session.close(); + + session = openSession(); + + results = session.createQuery( "select a from Animal a, Animal b order by a.id" ) + .setResultTransformer(new DistinctRootEntityResultTransformer()) + .list(); + assertEquals( "Incorrect result size", 2, results.size()); + assertTrue( "Incorrect return type", results.get(0) instanceof Animal ); + firstAnimal = (Animal) results.get(0); + secondAnimal = (Animal) results.get(1); + assertEquals("Mammal #1", firstAnimal.getDescription()); + assertEquals("Mammal #2", secondAnimal.getDescription()); + + session.close(); + + destroyTestBaseData(); + } + + public void testResultTransformerEntityQueries() throws Exception { + + createTestBaseData(); + + String query = "select an as an from Animal an order by bodyWeight desc"; + + Session session = openSession(); + + List results = session.createQuery( query ) + .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list(); + assertEquals( "Incorrect result size", results.size(), 2 ); + assertTrue( "Incorrect return type", results.get(0) instanceof Map ); + Map map = ((Map) results.get(0)); + assertEquals(1, map.size()); + Animal firstAnimal = (Animal) map.get("an"); + map = ((Map) results.get(1)); + Animal secondAnimal = (Animal) map.get("an"); + assertEquals("Mammal #1", firstAnimal.getDescription()); + assertEquals("Mammal #2", secondAnimal.getDescription()); + assertTrue(session.contains(firstAnimal)); + assertSame(firstAnimal, session.get(Animal.class,firstAnimal.getId())); + session.close(); + + session = openSession(); + + Iterator iter = session.createQuery( query ) + .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).iterate(); + assertTrue( "Incorrect result size", iter.hasNext() ); + map = (Map) iter.next(); + firstAnimal = (Animal) map.get("an"); + assertEquals("Mammal #1", firstAnimal.getDescription()); + assertTrue( "Incorrect result size", iter.hasNext() ); + + session.close(); + + session = openSession(); + + ScrollableResults sr = session.createQuery( query ) + .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).scroll(); + assertTrue( "Incorrect result size", sr.next() ); + assertTrue( "Incorrect return type", sr.get(0) instanceof Map ); + assertFalse(session.contains(sr.get(0))); + sr.close(); + + session.close(); + + destroyTestBaseData(); + } + + public void testEJBQLFunctions() throws Exception { + Session session = openSession(); + + String hql = "from Animal a where a.description = concat('1', concat('2','3'), '4'||'5')||'0'"; + session.createQuery(hql).list(); + + hql = "from Animal a where substring(a.description, 1, 3) = 'cat'"; + session.createQuery(hql).list(); + + hql = "select substring(a.description, 1, 3) from Animal a"; + session.createQuery(hql).list(); + + hql = "from Animal a where lower(a.description) = 'cat'"; + session.createQuery(hql).list(); + + hql = "select lower(a.description) from Animal a"; + session.createQuery(hql).list(); + + hql = "from Animal a where upper(a.description) = 'CAT'"; + session.createQuery(hql).list(); + + hql = "select upper(a.description) from Animal a"; + session.createQuery(hql).list(); + + hql = "from Animal a where length(a.description) = 5"; + session.createQuery(hql).list(); + + hql = "select length(a.description) from Animal a"; + session.createQuery(hql).list(); + + //note: postgres and db2 don't have a 3-arg form, it gets transformed to 2-args + hql = "from Animal a where locate('abc', a.description, 2) = 2"; + session.createQuery(hql).list(); + + hql = "from Animal a where locate('abc', a.description) = 2"; + session.createQuery(hql).list(); + + hql = "select locate('cat', a.description, 2) from Animal a"; + session.createQuery(hql).list(); + + if ( !( getDialect() instanceof DB2Dialect ) ) { + hql = "from Animal a where trim(trailing '_' from a.description) = 'cat'"; + session.createQuery(hql).list(); + + hql = "select trim(trailing '_' from a.description) from Animal a"; + session.createQuery(hql).list(); + + hql = "from Animal a where trim(leading '_' from a.description) = 'cat'"; + session.createQuery(hql).list(); + + hql = "from Animal a where trim(both from a.description) = 'cat'"; + session.createQuery(hql).list(); + } + + if ( !(getDialect() instanceof HSQLDialect) ) { //HSQL doesn't like trim() without specification + hql = "from Animal a where trim(a.description) = 'cat'"; + session.createQuery(hql).list(); + } + + hql = "from Animal a where abs(a.bodyWeight) = sqrt(a.bodyWeight)"; + session.createQuery(hql).list(); + + hql = "from Animal a where mod(16, 4) = 4"; + session.createQuery(hql).list(); + + hql = "from Animal a where bit_length(a.bodyWeight) = 24"; + session.createQuery(hql).list(); + + hql = "select bit_length(a.bodyWeight) from Animal a"; + session.createQuery(hql).list(); + + /*hql = "select object(a) from Animal a where CURRENT_DATE = :p1 or CURRENT_TIME = :p2 or CURRENT_TIMESTAMP = :p3"; + session.createQuery(hql).list();*/ + + // todo the following is not supported + //hql = "select CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP from Animal a"; + //parse(hql, true); + //System.out.println("sql: " + toSql(hql)); + + hql = "from Animal a where a.description like '%a%'"; + session.createQuery(hql).list(); + + hql = "from Animal a where a.description not like '%a%'"; + session.createQuery(hql).list(); + + hql = "from Animal a where a.description like 'x%ax%' escape 'x'"; + session.createQuery(hql).list(); + + session.close(); + } + + public void testSubselectBetween() { + if ( supportsSubselectOnLeftSideIn() ) { + assertResultSize( "from Animal x where (select max(a.bodyWeight) from Animal a) in (1,2,3)", 0 ); + assertResultSize( "from Animal x where (select max(a.bodyWeight) from Animal a) between 0 and 100", 0 ); + assertResultSize( "from Animal x where (select max(a.description) from Animal a) like 'big%'", 0 ); + assertResultSize( "from Animal x where (select max(a.bodyWeight) from Animal a) is not null", 0 ); + } + assertResultSize( "from Animal x where exists (select max(a.bodyWeight) from Animal a)", 0 ); + } + + private void assertResultSize(String hql, int size) { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + assertEquals( size, session.createQuery(hql).list().size() ); + txn.commit(); + session.close(); + } + + private interface QueryPreparer { + public void prepare(Query query); + } + + private static final QueryPreparer DEFAULT_PREPARER = new QueryPreparer() { + public void prepare(Query query) { + } + }; + + private class SyntaxChecker { + private final String hql; + private final QueryPreparer preparer; + + public SyntaxChecker(String hql) { + this( hql, DEFAULT_PREPARER ); + } + + public SyntaxChecker(String hql, QueryPreparer preparer) { + this.hql = hql; + this.preparer = preparer; + } + + public void checkAll() { + checkList(); + checkIterate(); + checkScroll(); + } + + public SyntaxChecker checkList() { + Session s = openSession(); + s.beginTransaction(); + Query query = s.createQuery( hql ); + preparer.prepare( query ); + query.list(); + s.getTransaction().commit(); + s.close(); + return this; + } + + public SyntaxChecker checkScroll() { + Session s = openSession(); + s.beginTransaction(); + Query query = s.createQuery( hql ); + preparer.prepare( query ); + query.scroll(); + s.getTransaction().commit(); + s.close(); + return this; + } + + public SyntaxChecker checkIterate() { + Session s = openSession(); + s.beginTransaction(); + Query query = s.createQuery( hql ); + preparer.prepare( query ); + query.iterate(); + s.getTransaction().commit(); + s.close(); + return this; + } + } +} diff --git a/test/org/hibernate/test/hql/ASTQueryTranslatorTest.java b/test/org/hibernate/test/hql/ASTQueryTranslatorTest.java new file mode 100644 index 0000000000..dd78181caa --- /dev/null +++ b/test/org/hibernate/test/hql/ASTQueryTranslatorTest.java @@ -0,0 +1,176 @@ +// $Id$ +package org.hibernate.test.hql; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Tests cases where the AST based QueryTranslator does not generate identical SQL. + * + * @author josh Dec 6, 2004 9:07:58 AM + */ +public class ASTQueryTranslatorTest extends QueryTranslatorTestCase { + + public ASTQueryTranslatorTest(String x) { + super( x ); + } + + public static Test suite() { + return new TestSuite( ASTQueryTranslatorTest.class ); + } + + protected boolean dropAfterFailure() { + return false; + } + + // ##### TESTS THAT DON'T PASS BECAUSE THEY GENERATE DIFFERENT, POSSIBLY VALID SQL ##### + + public void testSelectManyToOne() { + assertTranslation("select distinct a.zoo from Animal a where a.zoo is not null"); + assertTranslation("select a.zoo from Animal a"); + } + + public void testSelectExpression() { + //old qt cant handle select-clause expressions + assertTranslation("select a.bodyWeight + m.bodyWeight from Animal a join a.mother m"); + } + + public void testFetchProperties() { + //not implemented in old qt + assertTranslation("from Animal a fetch all properties join a.offspring o fetch all properties"); + } + + public void testOldSyntax() { + //generates ANSI join instead of theta join + assertTranslation("from a in class Animal, o in elements(a.offspring), h in class Human"); + } + + public void testImplicitJoinInsideOutsideSubselect() { + // new qt re-uses the joins defined by 's.other.count' path when referenced in the subquery, + // whereas the old qt reuses only the "root table" (not the already defined join to 'other'): + // OLD SQL : + // select simple0_.id_ as col_0_0_ + // from Simple simple0_, + // Simple simple1_ + // where (simple1_.count_>0 + // and simple0_.other=simple1_.id_) + // and (simple0_.id_=some( + // select simple2_.id_ + // from Simple simple2_, + // Simple simple3_, + // Simple simple4_ + // where (simple3_.count_=simple4_.count_ + // and simple2_.other=simple3_.id_ + // and simple0_.other=simple4_.id_) + // )) + // NEW SQL : + // select simple0_.id_ as col_0_0_ + // from Simple simple0_, + // Simple simple1_ + // where (simple1_.count_>0 + // and simple0_.id_=some( + // select simple2_.id_ + // from Simple simple2_, + // Simple simple3_ + // where (simple3_.count_=simple1_.count_ + // and simple2_.other=simple3_.id_) + // ) + // and simple0_.other=simple1_.id_) + assertTranslation( "from Simple s where s = some( from Simple sim where sim.other.count=s.other.count ) and s.other.count > 0" ); + assertTranslation( "from Simple s where s.other.count > 0 and s = some( from Simple sim where sim.other.count=s.other.count )" ); + } + + public void testNakedPropertyRef() { + // this is needed for ejb3 selects and bulk statements + // Note: these all fail because the old parser did not have this + // feature, it just "passes the tokens through" to the SQL. + assertTranslation( "from Animal where bodyWeight = bodyWeight" ); + assertTranslation( "select bodyWeight from Animal" ); + assertTranslation( "select max(bodyWeight) from Animal" ); + } + + public void testNakedComponentPropertyRef() { + // this is needed for ejb3 selects and bulk statements + // Note: these all fail because the old parser did not have this + // feature, it just "passes the tokens through" to the SQL. + assertTranslation( "from Human where name.first = 'Gavin'" ); + assertTranslation( "select name from Human" ); + assertTranslation( "select upper(h.name.first) from Human as h" ); + assertTranslation( "select upper(name.first) from Human" ); + } + + public void testNakedMapIndex() throws Exception { + assertTranslation( "from Zoo where mammals['dog'].description like '%black%'" ); + } + + public void testNakedImplicitJoins() { + assertTranslation( "from Animal where mother.father = ?" ); + } + + public void testDuplicateImplicitJoinInWhere() { + //new qt has more organized joins + assertTranslation("from Human h where h.mother.bodyWeight>10 and h.mother.bodyWeight<10"); + } + + public void testWhereExpressions() { + assertTranslation("from User u where u.userName='gavin' and u.human.name.first='Gavin'"); + //new qt has more organized joins + assertTranslation("from User u where u.human.name.last='King' and u.human.name.first='Gavin'"); + assertTranslation("from Bar bar where bar.baz.name='josh'"); + assertTranslation("from Bar bar where bar.baz.name='josh' and not bar.baz.name='gavin'"); + } + + public void testImplicitJoinInSelect() { + //slightly diff select clause, both correct + assertTranslation("select foo.long, foo.foo from Foo foo"); + } + + public void testSelectStandardFunctions() throws Exception { + //old parser throws an exception + assertTranslation( "select current_date(), current_time(), current_timestamp() from Animal" ); + } + + public void testSelectClauseImplicitJoin() throws Exception { + //the old query translator has a bug which results in the wrong return type! + assertTranslation( "select d.owner.mother from Dog d" ); + } + + public void testComplexWhereExpression() throws Exception { + // classic QT generates lots of extra parens and some extra theta joins. + assertTranslation( "select distinct s from Simple s\n" + + "where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2" ); + } + + public void testDuplicateImplicitJoin() throws Exception { + // old qt generates an extra theta join + assertTranslation( "from Animal an where an.mother.bodyWeight > 10 and an.mother.bodyWeight < 20" ); + } + + public void testKeywordClassNameAndAlias() throws Exception { + // The old QT throws an exception, the new one doesn't, which is better + assertTranslation( "from Order order" ); + } + + public void testComponent3() throws Exception { + // The old translator generates duplicate inner joins *and* duplicate theta join clauses in the where statement in this case. + assertTranslation( "from Dog dog where dog.owner.name.first = 'Gavin' and dog.owner.name.last='King' and dog.owner.bodyWeight<70" ); + } + + public void testUncorrelatedSubselectWithJoin() throws Exception { + // The old translator generates unnecessary inner joins for the Animal subclass of zoo.mammals + // The new one is working fine now! + assertTranslation( "from Animal a where a in (select mam from Zoo zoo join zoo.mammals mam)" ); + } + + public void testFetch() throws Exception { + //SQL is correct, new qt is not throwing an exception when it should be (minor issue) + assertTranslation("from Customer cust left join fetch cust.billingAddress where cust.customerId='abc123'"); + } + + public void testImplicitJoin() throws Exception { + //old qt generates an exception, the new one doesnt + //this is actually invalid HQL, an implicit join on a many-valued association + assertTranslation( "from Animal an where an.offspring.mother.bodyWeight > 10" ); + } + +} diff --git a/test/org/hibernate/test/hql/Address.java b/test/org/hibernate/test/hql/Address.java new file mode 100644 index 0000000000..839e0285bd --- /dev/null +++ b/test/org/hibernate/test/hql/Address.java @@ -0,0 +1,55 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of Address. + * + * @author Steve Ebersole + */ +public class Address { + private String street; + private String city; + private String postalCode; + private String country; + private StateProvince stateProvince; + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getPostalCode() { + return postalCode; + } + + public void setPostalCode(String postalCode) { + this.postalCode = postalCode; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public StateProvince getStateProvince() { + return stateProvince; + } + + public void setStateProvince(StateProvince stateProvince) { + this.stateProvince = stateProvince; + } +} diff --git a/test/org/hibernate/test/hql/Animal.hbm.xml b/test/org/hibernate/test/hql/Animal.hbm.xml new file mode 100644 index 0000000000..5692dce616 --- /dev/null +++ b/test/org/hibernate/test/hql/Animal.hbm.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + human + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/hql/Animal.java b/test/org/hibernate/test/hql/Animal.java new file mode 100644 index 0000000000..5bade0768a --- /dev/null +++ b/test/org/hibernate/test/hql/Animal.java @@ -0,0 +1,99 @@ +//$Id$ +package org.hibernate.test.hql; + +import java.util.Set; +import java.util.HashSet; + +/** + * @author Gavin King + */ +public class Animal { + private Long id; + private float bodyWeight; + private Set offspring; + private Animal mother; + private Animal father; + private String description; + private Zoo zoo; + private String serialNumber; + + public Animal() { + } + + public Animal(String description, float bodyWeight) { + this.description = description; + this.bodyWeight = bodyWeight; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public float getBodyWeight() { + return bodyWeight; + } + + public void setBodyWeight(float bodyWeight) { + this.bodyWeight = bodyWeight; + } + + public Set getOffspring() { + return offspring; + } + + public void addOffspring(Animal offspring) { + if ( this.offspring == null ) { + this.offspring = new HashSet(); + } + + this.offspring.add( offspring ); + } + + public void setOffspring(Set offspring) { + this.offspring = offspring; + } + + public Animal getMother() { + return mother; + } + + public void setMother(Animal mother) { + this.mother = mother; + } + + public Animal getFather() { + return father; + } + + public void setFather(Animal father) { + this.father = father; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Zoo getZoo() { + return zoo; + } + + public void setZoo(Zoo zoo) { + this.zoo = zoo; + } + + public String getSerialNumber() { + return serialNumber; + } + + public void setSerialNumber(String serialNumber) { + this.serialNumber = serialNumber; + } +} diff --git a/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml b/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml new file mode 100644 index 0000000000..d0347c7aa5 --- /dev/null +++ b/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/hql/BooleanLiteralEntity.java b/test/org/hibernate/test/hql/BooleanLiteralEntity.java new file mode 100644 index 0000000000..0ee6ddc834 --- /dev/null +++ b/test/org/hibernate/test/hql/BooleanLiteralEntity.java @@ -0,0 +1,45 @@ +package org.hibernate.test.hql; + +/** + * todo: describe BooleanLiteralEntity + * + * @author Steve Ebersole + */ +public class BooleanLiteralEntity { + private Long id; + private boolean yesNoBoolean; + private boolean trueFalseBoolean; + private boolean zeroOneBoolean; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public boolean isYesNoBoolean() { + return yesNoBoolean; + } + + public void setYesNoBoolean(boolean yesNoBoolean) { + this.yesNoBoolean = yesNoBoolean; + } + + public boolean isTrueFalseBoolean() { + return trueFalseBoolean; + } + + public void setTrueFalseBoolean(boolean trueFalseBoolean) { + this.trueFalseBoolean = trueFalseBoolean; + } + + public boolean isZeroOneBoolean() { + return zeroOneBoolean; + } + + public void setZeroOneBoolean(boolean zeroOneBoolean) { + this.zeroOneBoolean = zeroOneBoolean; + } +} diff --git a/test/org/hibernate/test/hql/BulkManipulationTest.java b/test/org/hibernate/test/hql/BulkManipulationTest.java new file mode 100644 index 0000000000..119fdcaa1e --- /dev/null +++ b/test/org/hibernate/test/hql/BulkManipulationTest.java @@ -0,0 +1,1209 @@ +// $Id$ +package org.hibernate.test.hql; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.QueryException; +import org.hibernate.Transaction; +import org.hibernate.classic.Session; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.hql.ast.HqlSqlWalker; +import org.hibernate.id.IdentifierGenerator; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Tests execution of bulk UPDATE/DELETE statements through the new AST parser. + * + * @author Steve Ebersole + */ +public class BulkManipulationTest extends FunctionalTestCase { + + private static final Log log = LogFactory.getLog( BulkManipulationTest.class ); + + public BulkManipulationTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BulkManipulationTest.class ); + } + + public String[] getMappings() { + return new String[] { + "hql/Animal.hbm.xml", + "hql/Vehicle.hbm.xml", + "hql/KeyManyToOneEntity.hbm.xml", + "hql/Versions.hbm.xml", + "hql/FooBarCopy.hbm.xml", + "legacy/Multi.hbm.xml", + "hql/EntityWithCrazyCompositeKey.hbm.xml", + "hql/SimpleEntityWithAssociation.hbm.xml", + "hql/BooleanLiteralEntity.hbm.xml" + }; + } + + + // Non-exists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public void testDeleteNonExistentEntity() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + try { + s.createQuery( "delete NonExistentEntity" ).executeUpdate(); + fail( "no exception thrown" ); + } + catch( QueryException e ) { + log.debug( "Caught expected error type : " + e.getMessage() ); + } + + t.commit(); + s.close(); + } + + public void testUpdateNonExistentEntity() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + try { + s.createQuery( "update NonExistentEntity e set e.someProp = ?" ).executeUpdate(); + fail( "no exception thrown" ); + } + catch( QueryException e ) { + log.debug( "Caught expected error type : " + e.getMessage() ); + } + + t.commit(); + s.close(); + } + + public void testTempTableGenerationIsolation() throws Throwable{ + Session s = openSession(); + s.beginTransaction(); + + Truck truck = new Truck(); + truck.setVin( "123t" ); + truck.setOwner( "Steve" ); + s.save( truck ); + + // manually flush the session to ensure the insert happens + s.flush(); + + // now issue a bulk delete against Car which should force the temp table to be + // created. we need to test to ensure that this does not cause the transaction + // to be committed... + s.createQuery( "delete from Vehicle" ).executeUpdate(); + + s.getTransaction().rollback(); + s.close(); + + s = openSession(); + s.beginTransaction(); + List list = s.createQuery( "from Car" ).list(); + assertEquals( "temp table gen caused premature commit", 0, list.size() ); + s.createQuery( "delete from Car" ).executeUpdate(); + s.getTransaction().rollback(); + s.close(); + } + + + // BOOLEAN HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public void testBooleanHandling() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + // currently, we need the three different binds because they are different underlying types... + int count = s.createQuery( "update BooleanLiteralEntity set yesNoBoolean = :b1, trueFalseBoolean = :b2, zeroOneBoolean = :b3" ) + .setBoolean( "b1", true ) + .setBoolean( "b2", true ) + .setBoolean( "b3", true ) + .executeUpdate(); + assertEquals( 1, count ); + BooleanLiteralEntity entity = ( BooleanLiteralEntity ) s.createQuery( "from BooleanLiteralEntity" ).uniqueResult(); + assertTrue( entity.isYesNoBoolean() ); + assertTrue( entity.isTrueFalseBoolean() ); + assertTrue( entity.isZeroOneBoolean() ); + s.clear(); + + count = s.createQuery( "update BooleanLiteralEntity set yesNoBoolean = true, trueFalseBoolean = true, zeroOneBoolean = true" ) + .executeUpdate(); + assertEquals( 1, count ); + entity = ( BooleanLiteralEntity ) s.createQuery( "from BooleanLiteralEntity" ).uniqueResult(); + assertTrue( entity.isYesNoBoolean() ); + assertTrue( entity.isTrueFalseBoolean() ); + assertTrue( entity.isZeroOneBoolean() ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + + // INSERTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public void testSimpleInsert() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + s.createQuery( "insert into Pickup (id, vin, owner) select id, vin, owner from Car" ).executeUpdate(); + + t.commit(); + t = s.beginTransaction(); + + s.createQuery( "delete Vehicle" ).executeUpdate(); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testSimpleNativeSQLInsert() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + List l = s.createQuery("from Vehicle").list(); + assertEquals(l.size(),4); + + s.createSQLQuery( "insert into PICKUP (id, vin, owner) select id, vin, owner from Car" ).executeUpdate(); + + l = s.createQuery("from Vehicle").list(); + assertEquals(l.size(),5); + + t.commit(); + t = s.beginTransaction(); + + s.createSQLQuery( "delete from TRUCK" ).executeUpdate(); + + l = s.createQuery("from Vehicle").list(); + assertEquals(l.size(),4); + + Car c = (Car) s.createQuery( "from Car where owner = 'Kirsten'" ).uniqueResult(); + c.setOwner("NotKirsten"); + assertEquals(0,s.getNamedQuery( "native-delete-car" ).setString( 0, "Kirsten" ).executeUpdate()); + assertEquals(1,s.getNamedQuery( "native-delete-car" ).setString( 0, "NotKirsten" ).executeUpdate()); + + + assertEquals(0,s.createSQLQuery( "delete from SUV where owner = :owner" ).setString( "owner", "NotThere" ).executeUpdate()); + assertEquals(1,s.createSQLQuery( "delete from SUV where owner = :owner" ).setString( "owner", "Joe" ).executeUpdate()); + s.createSQLQuery( "delete from PICKUP" ).executeUpdate(); + + l = s.createQuery("from Vehicle").list(); + assertEquals(l.size(),0); + + + t.commit(); + s.close(); + + + data.cleanup(); + } + + public void testInsertWithManyToOne() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + s.createQuery( "insert into Animal (description, bodyWeight, mother) select description, bodyWeight, mother from Human" ).executeUpdate(); + + t.commit(); + t = s.beginTransaction(); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testInsertWithMismatchedTypes() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + try { + s.createQuery( "insert into Pickup (owner, vin, id) select id, vin, owner from Car" ).executeUpdate(); + fail( "mismatched types did not error" ); + } + catch( QueryException e ) { + // expected result + } + + t.commit(); + t = s.beginTransaction(); + + s.createQuery( "delete Vehicle" ).executeUpdate(); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testInsertIntoSuperclassPropertiesFails() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + try { + s.createQuery( "insert into Human (id, bodyWeight) select id, bodyWeight from Lizard" ).executeUpdate(); + fail( "superclass prop insertion did not error" ); + } + catch( QueryException e ) { + // expected result + } + + t.commit(); + t = s.beginTransaction(); + + s.createQuery( "delete Animal where mother is not null" ).executeUpdate(); + s.createQuery( "delete Animal where father is not null" ).executeUpdate(); + s.createQuery( "delete Animal" ).executeUpdate(); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testInsertAcrossMappedJoinFails() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + try { + s.createQuery( "insert into Joiner (name, joinedName) select vin, owner from Car" ).executeUpdate(); + fail( "mapped-join insertion did not error" ); + } + catch( QueryException e ) { + // expected result + } + + t.commit(); + t = s.beginTransaction(); + + s.createQuery( "delete Joiner" ).executeUpdate(); + s.createQuery( "delete Vehicle" ).executeUpdate(); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testInsertWithGeneratedId() { + // Make sure the env supports bulk inserts with generated ids... + EntityPersister persister = sfi().getEntityPersister( PettingZoo.class.getName() ); + IdentifierGenerator generator = persister.getIdentifierGenerator(); + if ( !HqlSqlWalker.supportsIdGenWithBulkInsertion( generator ) ) { + return; + } + + // create a Zoo + Zoo zoo = new Zoo(); + zoo.setName( "zoo" ); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.save( zoo ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + int count = s.createQuery( "insert into PettingZoo (name) select name from Zoo" ).executeUpdate(); + t.commit(); + s.close(); + + assertEquals( "unexpected insertion count", 1, count ); + + s = openSession(); + t = s.beginTransaction(); + PettingZoo pz = ( PettingZoo ) s.createQuery( "from PettingZoo" ).uniqueResult(); + t.commit(); + s.close(); + + assertEquals( zoo.getName(), pz.getName() ); + assertTrue( zoo.getId() != pz.getId() ); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery( "delete Zoo" ).executeUpdate(); + t.commit(); + s.close(); + } + + public void testInsertWithGeneratedVersionAndId() { + // Make sure the env supports bulk inserts with generated ids... + EntityPersister persister = sfi().getEntityPersister( IntegerVersioned.class.getName() ); + IdentifierGenerator generator = persister.getIdentifierGenerator(); + if ( !HqlSqlWalker.supportsIdGenWithBulkInsertion( generator ) ) { + return; + } + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + IntegerVersioned entity = new IntegerVersioned( "int-vers" ); + s.save( entity ); + s.createQuery( "select id, name, version from IntegerVersioned" ).list(); + t.commit(); + s.close(); + + Long initialId = entity.getId(); + int initialVersion = entity.getVersion(); + + s = openSession(); + t = s.beginTransaction(); + int count = s.createQuery( "insert into IntegerVersioned ( name ) select name from IntegerVersioned" ).executeUpdate(); + t.commit(); + s.close(); + + assertEquals( "unexpected insertion count", 1, count ); + + s = openSession(); + t = s.beginTransaction(); + IntegerVersioned created = ( IntegerVersioned ) s.createQuery( "from IntegerVersioned where id <> :initialId" ) + .setLong( "initialId", initialId.longValue() ) + .uniqueResult(); + t.commit(); + s.close(); + + assertEquals( "version was not seeded", initialVersion, created.getVersion() ); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery( "delete IntegerVersioned" ).executeUpdate(); + t.commit(); + s.close(); + } + + public void testInsertWithGeneratedTimestampVersion() { + // Make sure the env supports bulk inserts with generated ids... + EntityPersister persister = sfi().getEntityPersister( TimestampVersioned.class.getName() ); + IdentifierGenerator generator = persister.getIdentifierGenerator(); + if ( !HqlSqlWalker.supportsIdGenWithBulkInsertion( generator ) ) { + return; + } + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + TimestampVersioned entity = new TimestampVersioned( "int-vers" ); + s.save( entity ); + s.createQuery( "select id, name, version from TimestampVersioned" ).list(); + t.commit(); + s.close(); + + Long initialId = entity.getId(); + //Date initialVersion = entity.getVersion(); + + s = openSession(); + t = s.beginTransaction(); + int count = s.createQuery( "insert into TimestampVersioned ( name ) select name from TimestampVersioned" ).executeUpdate(); + t.commit(); + s.close(); + + assertEquals( "unexpected insertion count", 1, count ); + + s = openSession(); + t = s.beginTransaction(); + TimestampVersioned created = ( TimestampVersioned ) s.createQuery( "from TimestampVersioned where id <> :initialId" ) + .setLong( "initialId", initialId.longValue() ) + .uniqueResult(); + t.commit(); + s.close(); + + assertNotNull( created.getVersion() ); + //assertEquals( "version was not seeded", initialVersion, created.getVersion() ); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery( "delete TimestampVersioned" ).executeUpdate(); + t.commit(); + s.close(); + } + + // UPDATES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public void testIncorrectSyntax() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + try { + s.createQuery( "update Human set Human.description = 'xyz' where Human.id = 1 and Human.description is null" ); + fail( "expected failure" ); + } + catch( QueryException expected ) { + // ignore : expected behavior + } + t.commit(); + s.close(); + } + + public void testUpdateWithWhereExistsSubquery() { + // multi-table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Session s = openSession(); + Transaction t = s.beginTransaction(); + Human joe = new Human(); + joe.setName( new Name( "Joe", 'Q', "Public" ) ); + s.save( joe ); + Human doll = new Human(); + doll.setName( new Name( "Kyu", 'P', "Doll" ) ); + doll.setFriends( new ArrayList() ); + doll.getFriends().add( joe ); + s.save( doll ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + String updateQryString = "update Human h " + + "set h.description = 'updated' " + + "where exists (" + + " select f.id " + + " from h.friends f " + + " where f.name.last = 'Public' " + + ")"; + int count = s.createQuery( updateQryString ).executeUpdate(); + assertEquals( 1, count ); + s.delete( doll ); + s.delete( joe ); + t.commit(); + s.close(); + + // single-table (one-to-many & many-to-many) ~~~~~~~~~~~~~~~~~~~~~~~~~~ + s = openSession(); + t = s.beginTransaction(); + SimpleEntityWithAssociation entity = new SimpleEntityWithAssociation(); + SimpleEntityWithAssociation other = new SimpleEntityWithAssociation(); + entity.setName( "main" ); + other.setName( "many-to-many-association" ); + entity.getManyToManyAssociatedEntities().add( other ); + entity.addAssociation( "one-to-many-association" ); + s.save( entity ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + // one-to-many test + updateQryString = "update SimpleEntityWithAssociation e " + + "set e.name = 'updated' " + + "where exists (" + + " select a.id " + + " from e.associatedEntities a " + + " where a.name = 'one-to-many-association' " + + ")"; + count = s.createQuery( updateQryString ).executeUpdate(); + assertEquals( 1, count ); + // many-to-many test + if ( supportsSubqueryOnMutatingTable() ) { + updateQryString = "update SimpleEntityWithAssociation e " + + "set e.name = 'updated' " + + "where exists (" + + " select a.id " + + " from e.manyToManyAssociatedEntities a " + + " where a.name = 'many-to-many-association' " + + ")"; + count = s.createQuery( updateQryString ).executeUpdate(); + assertEquals( 1, count ); + } + s.delete( entity.getManyToManyAssociatedEntities().iterator().next() ); + s.delete( entity ); + t.commit(); + s.close(); + } + + public void testIncrementCounterVersion() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + IntegerVersioned entity = new IntegerVersioned( "int-vers" ); + s.save( entity ); + t.commit(); + s.close(); + + int initialVersion = entity.getVersion(); + + s = openSession(); + t = s.beginTransaction(); + int count = s.createQuery( "update versioned IntegerVersioned set name = name" ).executeUpdate(); + assertEquals( "incorrect exec count", 1, count ); + t.commit(); + + t = s.beginTransaction(); + entity = ( IntegerVersioned ) s.load( IntegerVersioned.class, entity.getId() ); + assertEquals( "version not incremented", initialVersion + 1, entity.getVersion() ); + + s.delete( entity ); + t.commit(); + s.close(); + } + + public void testIncrementTimestampVersion() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + TimestampVersioned entity = new TimestampVersioned( "ts-vers" ); + s.save( entity ); + t.commit(); + s.close(); + + Date initialVersion = entity.getVersion(); + + synchronized (this) { + try { + wait(1500); + } + catch (InterruptedException ie) {} + } + + s = openSession(); + t = s.beginTransaction(); + int count = s.createQuery( "update versioned TimestampVersioned set name = name" ).executeUpdate(); + assertEquals( "incorrect exec count", 1, count ); + t.commit(); + + t = s.beginTransaction(); + entity = ( TimestampVersioned ) s.load( TimestampVersioned.class, entity.getId() ); + assertTrue( "version not incremented", entity.getVersion().after( initialVersion ) ); + + s.delete( entity ); + t.commit(); + s.close(); + } + + public void testUpdateOnComponent() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Human human = new Human(); + human.setName( new Name( "Stevee", 'X', "Ebersole" ) ); + + s.save( human ); + s.flush(); + + t.commit(); + + String correctName = "Steve"; + + t = s.beginTransaction(); + + int count = s.createQuery( "update Human set name.first = :correction where id = :id" ) + .setString( "correction", correctName ) + .setLong( "id", human.getId().longValue() ) + .executeUpdate(); + + assertEquals( "Incorrect update count", 1, count ); + + t.commit(); + + t = s.beginTransaction(); + + s.refresh( human ); + + assertEquals( "Update did not execute properly", correctName, human.getName().getFirst() ); + + s.createQuery( "delete Human" ).executeUpdate(); + t.commit(); + + s.close(); + } + + public void testUpdateOnManyToOne() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + s.createQuery( "update Animal a set a.mother = null where a.id = 2" ).executeUpdate(); + if ( ! ( getDialect() instanceof MySQLDialect ) ) { + // MySQL does not support (even un-correlated) subqueries against the update-mutating table + s.createQuery( "update Animal a set a.mother = (from Animal where id = 1) where a.id = 2" ).executeUpdate(); + } + + t.commit(); + s.close(); + } + + public void testUpdateOnImplicitJoinFails() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Human human = new Human(); + human.setName( new Name( "Steve", 'E', null ) ); + + Human mother = new Human(); + mother.setName( new Name( "Jane", 'E', null ) ); + human.setMother( mother ); + + s.save( human ); + s.save( mother ); + s.flush(); + + t.commit(); + + t = s.beginTransaction(); + try { + s.createQuery( "update Human set mother.name.initial = :initial" ).setString( "initial", "F" ).executeUpdate(); + fail( "update allowed across implicit join" ); + } + catch( QueryException e ) { + log.debug( "TEST (OK) : " + e.getMessage() ); + // expected condition + } + + s.createQuery( "delete Human where mother is not null" ).executeUpdate(); + s.createQuery( "delete Human" ).executeUpdate(); + t.commit(); + s.close(); + } + + public void testUpdateOnDiscriminatorSubclass() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "update PettingZoo set name = name" ).executeUpdate(); + assertEquals( "Incorrect discrim subclass update count", 1, count ); + + t.rollback(); + t = s.beginTransaction(); + + count = s.createQuery( "update PettingZoo pz set pz.name = pz.name where pz.id = :id" ) + .setLong( "id", data.pettingZoo.getId().longValue() ) + .executeUpdate(); + assertEquals( "Incorrect discrim subclass update count", 1, count ); + + t.rollback(); + t = s.beginTransaction(); + + count = s.createQuery( "update Zoo as z set z.name = z.name" ).executeUpdate(); + assertEquals( "Incorrect discrim subclass update count", 2, count ); + + t.rollback(); + t = s.beginTransaction(); + + // TODO : not so sure this should be allowed. Seems to me that if they specify an alias, + // property-refs should be required to be qualified. + count = s.createQuery( "update Zoo as z set name = name where id = :id" ) + .setLong( "id", data.zoo.getId().longValue() ) + .executeUpdate(); + assertEquals( "Incorrect discrim subclass update count", 1, count ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testUpdateOnAnimal() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + int count = s.createQuery( "update Animal set description = description where description = :desc" ) + .setString( "desc", data.frog.getDescription() ) + .executeUpdate(); + assertEquals( "Incorrect entity-updated count", 1, count ); + + count = s.createQuery( "update Animal set description = :newDesc where description = :desc" ) + .setString( "desc", data.polliwog.getDescription() ) + .setString( "newDesc", "Tadpole" ) + .executeUpdate(); + assertEquals( "Incorrect entity-updated count", 1, count ); + + Animal tadpole = ( Animal ) s.load( Animal.class, data.polliwog.getId() ); + assertEquals( "Update did not take effect", "Tadpole", tadpole.getDescription() ); + + count = s.createQuery( "update Animal set bodyWeight = bodyWeight + :w1 + :w2" ) + .setDouble( "w1", 1 ) + .setDouble( "w2", 2 ) + .executeUpdate(); + assertEquals( "incorrect count on 'complex' update assignment", count, 6 ); + + if ( ! ( getDialect() instanceof MySQLDialect ) ) { + // MySQL does not support (even un-correlated) subqueries against the update-mutating table + s.createQuery( "update Animal set bodyWeight = ( select max(bodyWeight) from Animal )" ) + .executeUpdate(); + } + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testUpdateOnMammal() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "update Mammal set description = description" ).executeUpdate(); + assertEquals( "incorrect update count against 'middle' of joined-subclass hierarchy", 2, count ); + + count = s.createQuery( "update Mammal set bodyWeight = 25" ).executeUpdate(); + assertEquals( "incorrect update count against 'middle' of joined-subclass hierarchy", 2, count ); + + if ( ! ( getDialect() instanceof MySQLDialect ) ) { + // MySQL does not support (even un-correlated) subqueries against the update-mutating table + count = s.createQuery( "update Mammal set bodyWeight = ( select max(bodyWeight) from Animal )" ).executeUpdate(); + assertEquals( "incorrect update count against 'middle' of joined-subclass hierarchy", 2, count ); + } + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testUpdateSetNullUnionSubclass() { + TestData data = new TestData(); + data.prepare(); + + // These should reach out into *all* subclass tables... + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "update Vehicle set owner = 'Steve'" ).executeUpdate(); + assertEquals( "incorrect restricted update count", 4, count ); + count = s.createQuery( "update Vehicle set owner = null where owner = 'Steve'" ).executeUpdate(); + assertEquals( "incorrect restricted update count", 4, count ); + + count = s.createQuery( "delete Vehicle where owner is null" ).executeUpdate(); + assertEquals( "incorrect restricted update count", 4, count ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testUpdateSetNullOnDiscriminatorSubclass() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "update PettingZoo set address.city = null" ).executeUpdate(); + assertEquals( "Incorrect discrim subclass delete count", 1, count ); + count = s.createQuery( "delete Zoo where address.city is null" ).executeUpdate(); + assertEquals( "Incorrect discrim subclass delete count", 1, count ); + + count = s.createQuery( "update Zoo set address.city = null" ).executeUpdate(); + assertEquals( "Incorrect discrim subclass delete count", 1, count ); + count = s.createQuery( "delete Zoo where address.city is null" ).executeUpdate(); + assertEquals( "Incorrect discrim subclass delete count", 1, count ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testUpdateSetNullOnJoinedSubclass() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "update Mammal set bodyWeight = null" ).executeUpdate(); + assertEquals( "Incorrect deletion count on joined subclass", 2, count ); + + count = s.createQuery( "delete Animal where bodyWeight = null" ).executeUpdate(); + assertEquals( "Incorrect deletion count on joined subclass", 2, count ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + + // DELETES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public void testDeleteWithSubquery() { + // setup the test data... + Session s = openSession(); + s.beginTransaction(); + SimpleEntityWithAssociation owner = new SimpleEntityWithAssociation( "myEntity-1" ); + owner.addAssociation( "assoc-1" ); + owner.addAssociation( "assoc-2" ); + owner.addAssociation( "assoc-3" ); + s.save( owner ); + SimpleEntityWithAssociation owner2 = new SimpleEntityWithAssociation( "myEntity-2" ); + owner2.addAssociation( "assoc-1" ); + owner2.addAssociation( "assoc-2" ); + owner2.addAssociation( "assoc-3" ); + owner2.addAssociation( "assoc-4" ); + s.save( owner2 ); + SimpleEntityWithAssociation owner3 = new SimpleEntityWithAssociation( "myEntity-3" ); + s.save( owner3 ); + s.getTransaction().commit(); + s.close(); + + // now try the bulk delete + s = openSession(); + s.beginTransaction(); + int count = s.createQuery( "delete SimpleEntityWithAssociation e where size( e.associatedEntities ) = 0 and e.name like '%'" ).executeUpdate(); + assertEquals( "incorrect delete count", 1, count ); + s.getTransaction().commit(); + s.close(); + + // finally, clean up + s = openSession(); + s.beginTransaction(); + s.createQuery( "delete SimpleAssociatedEntity" ).executeUpdate(); + s.createQuery( "delete SimpleEntityWithAssociation" ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } + + public void testSimpleDeleteOnAnimal() { + if ( getDialect().hasSelfReferentialForeignKeyBug() ) { + reportSkip( "self referential FK bug", "HQL delete testing" ); + return; + } + + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "delete from Animal as a where a.id = :id" ) + .setLong( "id", data.polliwog.getId().longValue() ) + .executeUpdate(); + assertEquals( "Incorrect delete count", 1, count ); + + count = s.createQuery( "delete Animal where id = :id" ) + .setLong( "id", data.catepillar.getId().longValue() ) + .executeUpdate(); + assertEquals( "incorrect delete count", 1, count ); + + // HHH-873... + if ( supportsSubqueryOnMutatingTable() ) { + count = s.createQuery( "delete from User u where u not in (select u from User u)" ).executeUpdate(); + assertEquals( 0, count ); + } + + count = s.createQuery( "delete Animal a" ).executeUpdate(); + assertEquals( "Incorrect delete count", 4, count ); + + List list = s.createQuery( "select a from Animal as a" ).list(); + assertTrue( "table not empty", list.isEmpty() ); + + t.commit(); + s.close(); + data.cleanup(); + } + + public void testDeleteOnDiscriminatorSubclass() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "delete PettingZoo" ).executeUpdate(); + assertEquals( "Incorrect discrim subclass delete count", 1, count ); + + count = s.createQuery( "delete Zoo" ).executeUpdate(); + assertEquals( "Incorrect discrim subclass delete count", 1, count ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testDeleteOnJoinedSubclass() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "delete Mammal where bodyWeight > 150" ).executeUpdate(); + assertEquals( "Incorrect deletion count on joined subclass", 1, count ); + + count = s.createQuery( "delete Mammal" ).executeUpdate(); + assertEquals( "Incorrect deletion count on joined subclass", 1, count ); + + count = s.createQuery( "delete SubMulti" ).executeUpdate(); + assertEquals( "Incorrect deletion count on joined subclass", 0, count ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testDeleteOnMappedJoin() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "delete Joiner where joinedName = :joinedName" ).setString( "joinedName", "joined-name" ).executeUpdate(); + assertEquals( "Incorrect deletion count on joined subclass", 1, count ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testDeleteUnionSubclassAbstractRoot() { + TestData data = new TestData(); + data.prepare(); + + // These should reach out into *all* subclass tables... + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "delete Vehicle where owner = :owner" ).setString( "owner", "Steve" ).executeUpdate(); + assertEquals( "incorrect restricted update count", 1, count ); + + count = s.createQuery( "delete Vehicle" ).executeUpdate(); + assertEquals( "incorrect update count", 3, count ); + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testDeleteUnionSubclassConcreteSubclass() { + TestData data = new TestData(); + data.prepare(); + + // These should only affect the given table + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "delete Truck where owner = :owner" ).setString( "owner", "Steve" ).executeUpdate(); + assertEquals( "incorrect restricted update count", 1, count ); + + count = s.createQuery( "delete Truck" ).executeUpdate(); + assertEquals( "incorrect update count", 2, count ); + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testDeleteUnionSubclassLeafSubclass() { + TestData data = new TestData(); + data.prepare(); + + // These should only affect the given table + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "delete Car where owner = :owner" ).setString( "owner", "Kirsten" ).executeUpdate(); + assertEquals( "incorrect restricted update count", 1, count ); + + count = s.createQuery( "delete Car" ).executeUpdate(); + assertEquals( "incorrect update count", 0, count ); + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testDeleteWithMetadataWhereFragments() throws Throwable { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + // Note: we are just checking the syntax here... + s.createQuery("delete from Bar").executeUpdate(); + s.createQuery("delete from Bar where barString = 's'").executeUpdate(); + + t.commit(); + s.close(); + } + + public void testDeleteRestrictedOnManyToOne() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + int count = s.createQuery( "delete Animal where mother = :mother" ) + .setEntity( "mother", data.butterfly ) + .executeUpdate(); + assertEquals( 1, count ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + public void testDeleteSyntaxWithCompositeId() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + s.createQuery( "delete EntityWithCrazyCompositeKey where id.id = 1 and id.otherId = 2" ).executeUpdate(); + s.createQuery( "delete from EntityWithCrazyCompositeKey where id.id = 1 and id.otherId = 2" ).executeUpdate(); + s.createQuery( "delete from EntityWithCrazyCompositeKey e where e.id.id = 1 and e.id.otherId = 2" ).executeUpdate(); + + t.commit(); + s.close(); + } + + private class TestData { + + private Animal polliwog; + private Animal catepillar; + private Animal frog; + private Animal butterfly; + + private Zoo zoo; + private Zoo pettingZoo; + + private void prepare() { + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + polliwog = new Animal(); + polliwog.setBodyWeight( 12 ); + polliwog.setDescription( "Polliwog" ); + + catepillar = new Animal(); + catepillar.setBodyWeight( 10 ); + catepillar.setDescription( "Catepillar" ); + + frog = new Animal(); + frog.setBodyWeight( 34 ); + frog.setDescription( "Frog" ); + + polliwog.setFather( frog ); + frog.addOffspring( polliwog ); + + butterfly = new Animal(); + butterfly.setBodyWeight( 9 ); + butterfly.setDescription( "Butterfly" ); + + catepillar.setMother( butterfly ); + butterfly.addOffspring( catepillar ); + + s.save( frog ); + s.save( polliwog ); + s.save( butterfly ); + s.save( catepillar ); + + Dog dog = new Dog(); + dog.setBodyWeight( 200 ); + dog.setDescription( "dog" ); + s.save( dog ); + + Cat cat = new Cat(); + cat.setBodyWeight( 100 ); + cat.setDescription( "cat" ); + s.save( cat ); + + zoo = new Zoo(); + zoo.setName( "Zoo" ); + Address add = new Address(); + add.setCity("MEL"); + add.setCountry("AU"); + add.setStreet("Main st"); + add.setPostalCode("3000"); + zoo.setAddress(add); + + pettingZoo = new PettingZoo(); + pettingZoo.setName( "Petting Zoo" ); + Address addr = new Address(); + addr.setCity("Sydney"); + addr.setCountry("AU"); + addr.setStreet("High st"); + addr.setPostalCode("2000"); + pettingZoo.setAddress(addr); + + s.save( zoo ); + s.save( pettingZoo ); + + Joiner joiner = new Joiner(); + joiner.setJoinedName( "joined-name" ); + joiner.setName( "name" ); + s.save( joiner ); + + Car car = new Car(); + car.setVin( "123c" ); + car.setOwner( "Kirsten" ); + s.save( car ); + + Truck truck = new Truck(); + truck.setVin( "123t" ); + truck.setOwner( "Steve" ); + s.save( truck ); + + SUV suv = new SUV(); + suv.setVin( "123s" ); + suv.setOwner( "Joe" ); + s.save( suv ); + + Pickup pickup = new Pickup(); + pickup.setVin( "123p" ); + pickup.setOwner( "Cecelia" ); + s.save( pickup ); + + BooleanLiteralEntity bool = new BooleanLiteralEntity(); + s.save( bool ); + + txn.commit(); + s.close(); + } + + private void cleanup() { + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + // workaround awesome HSQLDB "feature" + s.createQuery( "delete from Animal where mother is not null or father is not null" ).executeUpdate(); + s.createQuery( "delete from Animal" ).executeUpdate(); + s.createQuery( "delete from Zoo" ).executeUpdate(); + s.createQuery( "delete from Joiner" ).executeUpdate(); + s.createQuery( "delete from Vehicle" ).executeUpdate(); + s.createQuery( "delete from BooleanLiteralEntity" ).executeUpdate(); + + txn.commit(); + s.close(); + } + } +} diff --git a/test/org/hibernate/test/hql/Car.java b/test/org/hibernate/test/hql/Car.java new file mode 100644 index 0000000000..aef58dc2ab --- /dev/null +++ b/test/org/hibernate/test/hql/Car.java @@ -0,0 +1,10 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of Car. + * + * @author Steve Ebersole + */ +public class Car extends Vehicle { +} diff --git a/test/org/hibernate/test/hql/Cat.java b/test/org/hibernate/test/hql/Cat.java new file mode 100644 index 0000000000..32b32fa9a5 --- /dev/null +++ b/test/org/hibernate/test/hql/Cat.java @@ -0,0 +1,9 @@ +//$Id$ +package org.hibernate.test.hql; + +/** + * @author Gavin King + */ +public class Cat extends DomesticAnimal { + +} diff --git a/test/org/hibernate/test/hql/ClassicTranslatorTest.java b/test/org/hibernate/test/hql/ClassicTranslatorTest.java new file mode 100644 index 0000000000..cefa4c0281 --- /dev/null +++ b/test/org/hibernate/test/hql/ClassicTranslatorTest.java @@ -0,0 +1,64 @@ +package org.hibernate.test.hql; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.hql.classic.ClassicQueryTranslatorFactory; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Some simple test queries using the classic translator explicitly + * to ensure that code is not broken in changes for the new translator. + *

+ * Only really checking translation and syntax, not results. + * + * @author Steve Ebersole + */ +public class ClassicTranslatorTest extends QueryTranslatorTestCase { + + public ClassicTranslatorTest(String x) { + super( x ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ClassicTranslatorTest.class ); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.QUERY_TRANSLATOR, ClassicQueryTranslatorFactory.class.getName() ); + } + + + public boolean createSchema() { + return true; + } + + public boolean recreateSchemaAfterFailure() { + return true; + } + + public void testQueries() { + Session session = openSession(); + session.beginTransaction(); + + session.createQuery( "from Animal" ).list(); + + session.createQuery( "select a from Animal as a" ).list(); + session.createQuery( "select a.mother from Animal as a" ).list(); + session.createQuery( "select m from Animal as a inner join a.mother as m" ).list(); + session.createQuery( "select a from Animal as a inner join fetch a.mother" ).list(); + + session.createQuery( "from Animal as a where a.description = ?" ).setString( 0, "jj" ).list(); + session.createQuery( "from Animal as a where a.description = :desc" ).setString( "desc", "jr" ).list(); + session.createQuery( "from Animal as a where a.description = ? or a.description = :desc" ) + .setString( 0, "jj" ) + .setString( "desc", "jr" ) + .list(); + + session.getTransaction().commit(); + session.close(); + } +} diff --git a/test/org/hibernate/test/hql/Classification.java b/test/org/hibernate/test/hql/Classification.java new file mode 100644 index 0000000000..7ff83daee4 --- /dev/null +++ b/test/org/hibernate/test/hql/Classification.java @@ -0,0 +1,78 @@ +package org.hibernate.test.hql; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * Mimic a JDK 5 enum. + * + * @author Steve Ebersole + */ +public class Classification implements Serializable, Comparable { + + public static final Classification COOL = new Classification( "COOL", 0 ); + public static final Classification LAME = new Classification( "LAME", 1 ); + + private static final HashMap INSTANCES = new HashMap(); + static { + INSTANCES.put( COOL.name, COOL ); + INSTANCES.put( LAME.name, LAME ); + } + + private final String name; + private final int ordinal; + private final int hashCode; + + private Classification(String name, int ordinal) { + this.name = name; + this.ordinal = ordinal; + + int hashCode = name.hashCode(); + hashCode = 29 * hashCode + ordinal; + this.hashCode = hashCode; + } + + public String name() { + return name; + } + + public int ordinal() { + return ordinal; + } + + public boolean equals(Object obj) { + return compareTo( obj ) == 0; + } + + public int compareTo(Object o) { + int otherOrdinal = ( ( Classification ) o ).ordinal; + if ( ordinal == otherOrdinal ) { + return 0; + } + else if ( ordinal > otherOrdinal ) { + return 1; + } + else { + return -1; + } + } + + public int hashCode() { + return hashCode; + } + + public static Classification valueOf(String name) { + return ( Classification ) INSTANCES.get( name ); + } + + public static Classification valueOf(Integer ordinal) { + if ( ordinal == null ) { + return null; + } + switch ( ordinal.intValue() ) { + case 0: return COOL; + case 1: return LAME; + default: throw new IllegalArgumentException( "unknown classification ordinal [" + ordinal + "]" ); + } + } +} diff --git a/test/org/hibernate/test/hql/ClassificationType.java b/test/org/hibernate/test/hql/ClassificationType.java new file mode 100644 index 0000000000..02c8ecce3e --- /dev/null +++ b/test/org/hibernate/test/hql/ClassificationType.java @@ -0,0 +1,101 @@ +package org.hibernate.test.hql; + +import org.hibernate.usertype.EnhancedUserType; +import org.hibernate.HibernateException; +import org.hibernate.Hibernate; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.PreparedStatement; +import java.sql.Types; +import java.io.Serializable; + +/** + * A custom type for mapping {@link org.hibernate.test.hql.Classification} instances + * to the respective db column. + *

+ * THis is largely intended to mimic JDK5 enum support in JPA. Here we are + * using the approach of storing the ordinal values, rather than the names. + * + * @author Steve Ebersole + */ +public class ClassificationType implements EnhancedUserType { + + public int[] sqlTypes() { + return new int[] { Types.TINYINT }; + } + + public Class returnedClass() { + return Classification.class; + } + + public boolean equals(Object x, Object y) throws HibernateException { + if ( x == null && y == null ) { + return false; + } + else if ( x != null ) { + return x.equals( y ); + } + else { + return y.equals( x ); + } + } + + public int hashCode(Object x) throws HibernateException { + return x.hashCode(); + } + + public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { + Integer ordinal = ( Integer ) Hibernate.INTEGER.nullSafeGet( rs, names[0] ); + return Classification.valueOf( ordinal ); + } + + public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + Integer ordinal = value == null ? null : new Integer( ( ( Classification ) value ).ordinal() ); + Hibernate.INTEGER.nullSafeSet( st, ordinal, index ); + } + + public Object deepCopy(Object value) throws HibernateException { + return value; + } + + public boolean isMutable() { + return false; + } + + public Serializable disassemble(Object value) throws HibernateException { + return ( Classification ) value; + } + + public Object assemble(Serializable cached, Object owner) throws HibernateException { + return cached; + } + + public Object replace(Object original, Object target, Object owner) throws HibernateException { + return original; + } + + public String objectToSQLString(Object value) { + return extractOrdinalString( value ); + } + + public String toXMLString(Object value) { + return extractName( value ); + } + + public Object fromXMLString(String xmlValue) { + return Classification.valueOf( xmlValue ); + } + + private String extractName(Object obj) { + return ( ( Classification ) obj ).name(); + } + + private int extractOrdinal(Object value) { + return ( ( Classification ) value ).ordinal(); + } + + private String extractOrdinalString(Object value) { + return Integer.toString( extractOrdinal( value ) ); + } +} diff --git a/test/org/hibernate/test/hql/ComponentContainer.hbm.xml b/test/org/hibernate/test/hql/ComponentContainer.hbm.xml new file mode 100644 index 0000000000..4758248a1c --- /dev/null +++ b/test/org/hibernate/test/hql/ComponentContainer.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/hql/ComponentContainer.java b/test/org/hibernate/test/hql/ComponentContainer.java new file mode 100644 index 0000000000..ab1483c559 --- /dev/null +++ b/test/org/hibernate/test/hql/ComponentContainer.java @@ -0,0 +1,107 @@ +package org.hibernate.test.hql; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class ComponentContainer { + + private Long id; + private ComponentContainer.Address address; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public ComponentContainer.Address getAddress() { + return address; + } + + public void setAddress(ComponentContainer.Address address) { + this.address = address; + } + + public static class Address { + private String street; + private String city; + private String state; + private ComponentContainer.Address.Zip zip; + + public Address() { + } + + public Address(String street, String city, String state, ComponentContainer.Address.Zip zip) { + this.street = street; + this.city = city; + this.state = state; + this.zip = zip; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public ComponentContainer.Address.Zip getZip() { + return zip; + } + + public void setZip(ComponentContainer.Address.Zip zip) { + this.zip = zip; + } + + public static class Zip { + private int code; + private int plus4; + + public Zip() { + } + + public Zip(int code, int plus4) { + this.code = code; + this.plus4 = plus4; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public int getPlus4() { + return plus4; + } + + public void setPlus4(int plus4) { + this.plus4 = plus4; + } + } + } + +} diff --git a/test/org/hibernate/test/hql/CrazyCompositeKey.java b/test/org/hibernate/test/hql/CrazyCompositeKey.java new file mode 100644 index 0000000000..1b85e5a325 --- /dev/null +++ b/test/org/hibernate/test/hql/CrazyCompositeKey.java @@ -0,0 +1,40 @@ +// $Id$ +package org.hibernate.test.hql; + +import java.io.Serializable; + +/** + * Implementation of CrazyCompositeKey. + * + * @author Steve Ebersole + */ +public class CrazyCompositeKey implements Serializable { + private Long id; + private Long otherId; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getOtherId() { + return otherId; + } + + public void setOtherId(Long otherId) { + this.otherId = otherId; + } + + public boolean equals(Object that) { + CrazyCompositeKey cck = (CrazyCompositeKey) that; + return cck.id.longValue() == id.longValue() + && cck.otherId.longValue() == otherId.longValue(); + } + + public int hashCode() { + return id.hashCode() + otherId.hashCode(); + } +} diff --git a/test/org/hibernate/test/hql/CrazyIdFieldNames.hbm.xml b/test/org/hibernate/test/hql/CrazyIdFieldNames.hbm.xml new file mode 100644 index 0000000000..0166bd14eb --- /dev/null +++ b/test/org/hibernate/test/hql/CrazyIdFieldNames.hbm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/hql/CriteriaClassicAggregationReturnTest.java b/test/org/hibernate/test/hql/CriteriaClassicAggregationReturnTest.java new file mode 100644 index 0000000000..76ec1a646f --- /dev/null +++ b/test/org/hibernate/test/hql/CriteriaClassicAggregationReturnTest.java @@ -0,0 +1,107 @@ +package org.hibernate.test.hql; + +import java.util.Collections; + +import junit.framework.Test; + +import org.hibernate.cfg.Configuration; +import org.hibernate.dialect.function.ClassicCountFunction; +import org.hibernate.dialect.function.ClassicAvgFunction; +import org.hibernate.dialect.function.ClassicSumFunction; +import org.hibernate.hql.ast.QueryTranslatorImpl; +import org.hibernate.hql.QueryTranslator; +import org.hibernate.hql.QueryTranslatorFactory; +import org.hibernate.hql.classic.ClassicQueryTranslatorFactory; +import org.hibernate.Hibernate; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class CriteriaClassicAggregationReturnTest extends QueryTranslatorTestCase { + + public CriteriaClassicAggregationReturnTest(String x) { + super( x ); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.addSqlFunction( "count", new ClassicCountFunction() ); + cfg.addSqlFunction( "avg", new ClassicAvgFunction() ); + cfg.addSqlFunction( "sum", new ClassicSumFunction() ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CriteriaClassicAggregationReturnTest.class ); + } + + public void testClassicHQLAggregationReturnTypes() { + // EJB3: COUNT returns Long + QueryTranslatorImpl translator = createNewQueryTranslator( "select count(*) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select count(h.height) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] ); + + // MAX, MIN return the type of the state-field to which they are applied. + translator = createNewQueryTranslator( "select max(h.height) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select max(h.id) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] ); + + // AVG returns Float integrals, and otherwise the field type. + translator = createNewQueryTranslator( "select avg(h.height) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select avg(h.id) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.FLOAT, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select avg(h.bigIntegerValue) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.BIG_INTEGER, translator.getReturnTypes()[0] ); + + // SUM returns underlying type sum + translator = createNewQueryTranslator( "select sum(h.id) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select sum(h.intValue) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select sum(h.height) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select sum(h.floatValue) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.FLOAT, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select sum(h.bigIntegerValue) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.BIG_INTEGER, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select sum(h.bigDecimalValue) from Human h", sfi() ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.BIG_DECIMAL, translator.getReturnTypes()[0] ); + + // special case to test classicquery special case handling of count(*) + QueryTranslator oldQueryTranslator = null; + String hql = "select count(*) from Human h"; + QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory(); + oldQueryTranslator = classic.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, sfi() ); + oldQueryTranslator.compile( Collections.EMPTY_MAP, true); + assertEquals( "incorrect return type count", 1, oldQueryTranslator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.INTEGER, oldQueryTranslator.getReturnTypes()[0] ); + + } +} diff --git a/test/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java b/test/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java new file mode 100644 index 0000000000..9da70fc593 --- /dev/null +++ b/test/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java @@ -0,0 +1,173 @@ +//$Id: HQLTest.java 9873 2006-05-04 13:42:48Z max.andersen@jboss.com $ +package org.hibernate.test.hql; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collections; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.classic.Session; +import org.hibernate.criterion.Projections; +import org.hibernate.hql.QueryTranslator; +import org.hibernate.hql.QueryTranslatorFactory; +import org.hibernate.hql.ast.QueryTranslatorImpl; +import org.hibernate.hql.ast.tree.SelectClause; +import org.hibernate.hql.classic.ClassicQueryTranslatorFactory; + +/** + * Tests cases for ensuring alignment between HQL and Criteria behavior. + * + * @author Max Rydahl Andersen + */ +public class CriteriaHQLAlignmentTest extends QueryTranslatorTestCase { + + public CriteriaHQLAlignmentTest(String x) { + super( x ); + SelectClause.VERSION2_SQL = true; + } + + public boolean createSchema() { + return true; // needed for the Criteria return type test + } + + public boolean recreateSchemaAfterFailure() { + return true; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CriteriaHQLAlignmentTest.class ); + } + + public void testHQLAggregationReturnType() { + // EJB3: COUNT returns Long + QueryTranslatorImpl translator = createNewQueryTranslator( "select count(*) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select count(h.height) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] ); + + // MAX, MIN return the type of the state-field to which they are applied. + translator = createNewQueryTranslator( "select max(h.height) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select max(h.id) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] ); + + // AVG returns Double. + translator = createNewQueryTranslator( "select avg(h.height) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select avg(h.id) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select avg(h.bigIntegerValue) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + // SUM returns Long when applied to state-fields of integral types (other than BigInteger); + translator = createNewQueryTranslator( "select sum(h.id) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select sum(h.intValue) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] ); + + // SUM returns Double when applied to state-fields of floating point types; + translator = createNewQueryTranslator( "select sum(h.height) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "select sum(h.floatValue) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + + // SUM returns BigInteger when applied to state-fields of type BigInteger + translator = createNewQueryTranslator( "select sum(h.bigIntegerValue) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.BIG_INTEGER, translator.getReturnTypes()[0] ); + + // SUM and BigDecimal when applied to state-fields of type BigDecimal. + translator = createNewQueryTranslator( "select sum(h.bigDecimalValue) from Human h" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.BIG_DECIMAL, translator.getReturnTypes()[0] ); + + // special case to test classicquery special case handling of count(*) + QueryTranslator oldQueryTranslator = null; + String hql = "select count(*) from Human h"; + QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory(); + oldQueryTranslator = classic.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, getSessionFactoryImplementor() ); + oldQueryTranslator.compile( Collections.EMPTY_MAP, true); + assertEquals( "incorrect return type count", 1, oldQueryTranslator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.LONG, oldQueryTranslator.getReturnTypes()[0] ); + + } + + // HHH-1724 Align Criteria with HQL aggregation return types. + public void testCriteriaAggregationReturnTypeFailureExpected() { + Session s = openSession(); + Human human = new Human(); + human.setBigIntegerValue( new BigInteger("42") ); + human.setBigDecimalValue( new BigDecimal(45) ); + s.save(human); + + // EJB3: COUNT returns Long + Long longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.rowCount()).uniqueResult(); + assertEquals(longValue, new Long(1)); + longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.count("height")).uniqueResult(); + assertEquals(longValue, new Long(1)); + + // MAX, MIN return the type of the state-field to which they are applied. + Double dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.max( "height" )).uniqueResult(); + assertNotNull(dblValue); + + longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.max( "id" )).uniqueResult(); + assertNotNull(longValue); + + // AVG returns Double. + dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "height" )).uniqueResult(); + assertNotNull(dblValue); + + dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "id" )).uniqueResult(); + assertNotNull(dblValue); + + dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "bigIntegerValue" )).uniqueResult(); + assertNotNull(dblValue); + + // SUM returns Long when applied to state-fields of integral types (other than BigInteger); + longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.sum( "id" )).uniqueResult(); + assertNotNull(longValue); + + longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.sum( "intValue" )).uniqueResult(); + assertNotNull(longValue); + + // SUM returns Double when applied to state-fields of floating point types; + dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.sum( "height" )).uniqueResult(); + assertNotNull(dblValue); + + dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.sum( "floatValue" )).uniqueResult(); + assertNotNull(dblValue); + + // SUM returns BigInteger when applied to state-fields of type BigInteger + BigInteger bigIValue = (BigInteger) s.createCriteria( Human.class ).setProjection( Projections.sum( "bigIntegerValue" )).uniqueResult(); + assertNotNull(bigIValue); + + // SUM and BigDecimal when applied to state-fields of type BigDecimal. + BigDecimal bigDValue = (BigDecimal) s.createCriteria( Human.class ).setProjection( Projections.sum( "bigDecimalValue" )).uniqueResult(); + assertNotNull(bigDValue); + + s.delete( human ); + s.flush(); + s.close(); + } + +} diff --git a/test/org/hibernate/test/hql/Dog.java b/test/org/hibernate/test/hql/Dog.java new file mode 100644 index 0000000000..99a976dff1 --- /dev/null +++ b/test/org/hibernate/test/hql/Dog.java @@ -0,0 +1,9 @@ +//$Id$ +package org.hibernate.test.hql; + +/** + * @author Gavin King + */ +public class Dog extends DomesticAnimal { + +} diff --git a/test/org/hibernate/test/hql/DomesticAnimal.java b/test/org/hibernate/test/hql/DomesticAnimal.java new file mode 100755 index 0000000000..5cb9262b3b --- /dev/null +++ b/test/org/hibernate/test/hql/DomesticAnimal.java @@ -0,0 +1,17 @@ +//$Id$ +package org.hibernate.test.hql; + +/** + * @author Gavin King + */ +public class DomesticAnimal extends Mammal { + private Human owner; + + public Human getOwner() { + return owner; + } + + public void setOwner(Human owner) { + this.owner = owner; + } +} diff --git a/test/org/hibernate/test/hql/EJBQLTest.java b/test/org/hibernate/test/hql/EJBQLTest.java new file mode 100755 index 0000000000..7b10a6075a --- /dev/null +++ b/test/org/hibernate/test/hql/EJBQLTest.java @@ -0,0 +1,311 @@ +//$Id$ +package org.hibernate.test.hql; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Collections; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.hql.QueryTranslator; +import org.hibernate.hql.QueryTranslatorFactory; +import org.hibernate.hql.antlr.HqlSqlTokenTypes; +import org.hibernate.hql.ast.ASTQueryTranslatorFactory; +import org.hibernate.hql.ast.HqlParser; +import org.hibernate.hql.ast.QueryTranslatorImpl; +import org.hibernate.hql.ast.util.ASTUtil; +import org.hibernate.test.TestCase; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +import antlr.RecognitionException; +import antlr.TokenStreamException; +import antlr.collections.AST; + + +/** + * @author Alexey Loubyansky + */ +public class EJBQLTest extends FunctionalTestCase { + + public EJBQLTest(String x) { + super( x ); + } + + public String[] getMappings() { + return new String[]{ + "hql/Animal.hbm.xml", + "batchfetch/ProductLine.hbm.xml", + "cid/Customer.hbm.xml", + "cid/Order.hbm.xml", + "cid/LineItem.hbm.xml", + "cid/Product.hbm.xml", + "legacy/Glarch.hbm.xml", + "legacy/Fee.hbm.xml", + "legacy/Qux.hbm.xml", + "legacy/Fum.hbm.xml", + "legacy/Holder.hbm.xml", + "legacy/One.hbm.xml", + "legacy/FooBar.hbm.xml", + "legacy/Many.hbm.xml", + "legacy/Baz.hbm.xml", + "legacy/Simple.hbm.xml", + "legacy/Middle.hbm.xml", + "legacy/Category.hbm.xml", + "legacy/Multi.hbm.xml", + "legacy/Commento.hbm.xml", + "legacy/Marelo.hbm.xml", + "compositeelement/Parent.hbm.xml", + "legacy/Container.hbm.xml", + }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( EJBQLTest.class ); + } + + + public boolean createSchema() { + return false; + } + + public void testEjb3PositionalParameters() throws Exception { + QueryTranslatorImpl qt = compile( "from Animal a where a.bodyWeight = ?1" ); + AST ast = ( AST ) qt.getSqlAST(); + + // make certain that the ejb3-positional param got recognized as a named param + List namedParams = ASTUtil.collectChildren( + ast, + new ASTUtil.FilterPredicate() { + public boolean exclude(AST n) { + return n.getType() != HqlSqlTokenTypes.NAMED_PARAM; + } + } + ); + assertTrue( "ejb3 positional param not recognized as a named param", namedParams.size() > 0 ); + } + + /** + * SELECT OBJECT(identifier) + */ + public void testSelectObjectClause() throws Exception { + //parse("select object(m) from Model m"); + assertEjbqlEqualsHql( "select object(m) from Model m", "from Model m" ); + } + + /** + * IN(collection_valued_path) identifier + */ + public void testCollectionMemberDeclaration() throws Exception { + String hql = "select o from Animal a inner join a.offspring o"; + String ejbql = "select object(o) from Animal a, in(a.offspring) o"; + //parse(hql); + //parse(ejbql); + assertEjbqlEqualsHql( ejbql, hql ); + } + + /** + * collection_valued_path IS [NOT] EMPTY + */ + public void testIsEmpty() throws Exception { + //String hql = "from Animal a where not exists (from a.offspring)"; + String hql = "from Animal a where not exists elements(a.offspring)"; + String ejbql = "select object(a) from Animal a where a.offspring is empty"; + //parse(hql); + //parse(ejbql); + assertEjbqlEqualsHql(ejbql, hql); + + hql = "from Animal a where exists (from a.mother.father.offspring)"; + ejbql = "select object(a) from Animal a where a.mother.father.offspring is not empty"; + assertEjbqlEqualsHql( ejbql, hql ); + } + + /** + * [NOT] MEMBER OF + */ + public void testMemberOf() throws Exception { + String hql = "from Animal a where a.mother in (from a.offspring)"; + //String hql = "from Animal a where a.mother in elements(a.offspring)"; + String ejbql = "select object(a) from Animal a where a.mother member of a.offspring"; + //parse(hql); + //parse(ejbql); + assertEjbqlEqualsHql( ejbql, hql ); + + hql = "from Animal a where a.mother not in (from a.offspring)"; + //hql = "from Animal a where a.mother not in elements(a.offspring)"; + ejbql = "select object(a) from Animal a where a.mother not member of a.offspring"; + //parse(hql); + //parse(ejbql); + assertEjbqlEqualsHql( ejbql, hql ); + } + + /** + * Various functions. + * Tests just parsing for now which means it doesn't guarantee that the generated SQL is as expected or even valid. + */ + public void testEJBQLFunctions() throws Exception { + String hql = "select object(a) from Animal a where a.description = concat('1', concat('2','3'), '4'||'5')||0"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "from Animal a where substring(a.description, 1, 3) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select substring(a.description, 1, 3) from Animal a"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "from Animal a where lower(a.description) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select lower(a.description) from Animal a"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "from Animal a where upper(a.description) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select upper(a.description) from Animal a"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "from Animal a where length(a.description) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select length(a.description) from Animal a"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "from Animal a where locate(a.description, 'abc', 2) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select locate(a.description, :p1, 2) from Animal a"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where trim(trailing '_' from a.description) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select trim(trailing '_' from a.description) from Animal a"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where trim(leading '_' from a.description) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where trim(both a.description) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where trim(a.description) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where abs(a.bodyWeight) = sqrt(a.bodyWeight)"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where mod(a.bodyWeight, a.mother.bodyWeight) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where BIT_LENGTH(a.bodyWeight) = :p1"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select BIT_LENGTH(a.bodyWeight) from Animal a"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where CURRENT_DATE = :p1 or CURRENT_TIME = :p2 or CURRENT_TIMESTAMP = :p3"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + // todo the following is not supported + //hql = "select CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP from Animal a"; + //parse(hql, true); + //System.out.println("sql: " + toSql(hql)); + + hql = "select object(a) from Animal a where a.bodyWeight like '%a%'"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where a.bodyWeight not like '%a%'"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + + hql = "select object(a) from Animal a where a.bodyWeight like '%a%' escape '%'"; + parse( hql, false ); + System.out.println( "sql: " + toSql( hql ) ); + } + + public void testTrueFalse() throws Exception { + assertEjbqlEqualsHql( "from Human h where h.pregnant is true", "from Human h where h.pregnant = true" ); + assertEjbqlEqualsHql( "from Human h where h.pregnant is false", "from Human h where h.pregnant = false" ); + assertEjbqlEqualsHql( "from Human h where not(h.pregnant is true)", "from Human h where not( h.pregnant=true )" ); + } + + + // Private + + private void assertEjbqlEqualsHql(String ejbql, String hql) { + QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); + + QueryTranslator queryTranslator = ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, sfi() ); + queryTranslator.compile( Collections.EMPTY_MAP, true ); + String hqlSql = queryTranslator.getSQLString(); + + queryTranslator = ast.createQueryTranslator( ejbql, ejbql, Collections.EMPTY_MAP, sfi() ); + queryTranslator.compile( Collections.EMPTY_MAP, true ); + String ejbqlSql = queryTranslator.getSQLString(); + + assertEquals( hqlSql, ejbqlSql ); + } + + private QueryTranslatorImpl compile(String input) { + QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); + QueryTranslator queryTranslator = ast.createQueryTranslator( input, input, Collections.EMPTY_MAP, sfi() ); + queryTranslator.compile( Collections.EMPTY_MAP, true ); + + return ( QueryTranslatorImpl ) queryTranslator; + } + + private AST parse(String input, boolean logging) throws RecognitionException, TokenStreamException { + if ( logging ) { + System.out.println( "input: ->" + input + "<-" ); + } + + HqlParser parser = HqlParser.getInstance( input ); + parser.setFilter( false ); + parser.statement(); + AST ast = parser.getAST(); + + if ( logging ) { + System.out.println( "AST : " + ast.toStringTree() + "" ); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + parser.showAst( ast, new PrintStream( baos ) ); + System.out.println( baos.toString() ); + } + + assertEquals( "At least one error occurred during parsing!", 0, parser.getParseErrorHandler().getErrorCount() ); + + return ast; + } + + private String toSql(String hql) { + QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); + QueryTranslator queryTranslator = ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, sfi() ); + queryTranslator.compile( Collections.EMPTY_MAP, true ); + return queryTranslator.getSQLString(); + } +} diff --git a/test/org/hibernate/test/hql/EntityWithCrazyCompositeKey.hbm.xml b/test/org/hibernate/test/hql/EntityWithCrazyCompositeKey.hbm.xml new file mode 100644 index 0000000000..952fd09493 --- /dev/null +++ b/test/org/hibernate/test/hql/EntityWithCrazyCompositeKey.hbm.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/hql/EntityWithCrazyCompositeKey.java b/test/org/hibernate/test/hql/EntityWithCrazyCompositeKey.java new file mode 100644 index 0000000000..ccdfcb9651 --- /dev/null +++ b/test/org/hibernate/test/hql/EntityWithCrazyCompositeKey.java @@ -0,0 +1,28 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of EntityWithCrazyCompositeKey. + * + * @author Steve Ebersole + */ +public class EntityWithCrazyCompositeKey { + private CrazyCompositeKey id; + private String name; + + public CrazyCompositeKey getId() { + return id; + } + + public void setId(CrazyCompositeKey id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/hql/FooBarCopy.hbm.xml b/test/org/hibernate/test/hql/FooBarCopy.hbm.xml new file mode 100644 index 0000000000..78d7ce3ed2 --- /dev/null +++ b/test/org/hibernate/test/hql/FooBarCopy.hbm.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/hql/HQLSuite.java b/test/org/hibernate/test/hql/HQLSuite.java new file mode 100644 index 0000000000..6fe569de8b --- /dev/null +++ b/test/org/hibernate/test/hql/HQLSuite.java @@ -0,0 +1,29 @@ +// $Id$ +package org.hibernate.test.hql; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * The full suite of tests against the Antlr grammar + * + * @author Steve Ebersole + */ +public class HQLSuite { + + public static Test suite() { + TestSuite suite = new TestSuite( "Antlr HQL grammar tests" ); + suite.addTest( HQLTest.suite() ); + suite.addTest( ASTParserLoadingTest.suite() ); + suite.addTest( BulkManipulationTest.suite() ); + suite.addTest( WithClauseTest.suite() ); +// suite.addTest( ASTQueryTranslatorTest.suite() ); + suite.addTest( EJBQLTest.suite() ); + suite.addTest( HqlParserTest.suite() ); + suite.addTest( ScrollableCollectionFetchingTest.suite() ); + suite.addTest( ClassicTranslatorTest.suite() ); + suite.addTest( CriteriaHQLAlignmentTest.suite() ); + suite.addTest( CriteriaClassicAggregationReturnTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/hql/HQLTest.java b/test/org/hibernate/test/hql/HQLTest.java new file mode 100644 index 0000000000..3da775cfa2 --- /dev/null +++ b/test/org/hibernate/test/hql/HQLTest.java @@ -0,0 +1,1352 @@ +//$Id$ +package org.hibernate.test.hql; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import antlr.RecognitionException; +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.QueryException; +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.Oracle8iDialect; +import org.hibernate.dialect.Oracle9Dialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.query.HQLQueryPlan; +import org.hibernate.engine.query.ReturnMetadata; +import org.hibernate.hql.QueryTranslator; +import org.hibernate.hql.QueryTranslatorFactory; +import org.hibernate.hql.ast.ASTQueryTranslatorFactory; +import org.hibernate.hql.ast.DetailedSemanticException; +import org.hibernate.hql.ast.QuerySyntaxException; +import org.hibernate.hql.ast.QueryTranslatorImpl; +import org.hibernate.hql.ast.tree.ConstructorNode; +import org.hibernate.hql.ast.tree.DotNode; +import org.hibernate.hql.ast.tree.FromReferenceNode; +import org.hibernate.hql.ast.tree.IndexNode; +import org.hibernate.hql.ast.tree.SelectClause; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Tests cases where the AST based query translator and the 'classic' query translator generate identical SQL. + * + * @author Gavin King + */ +public class HQLTest extends QueryTranslatorTestCase { + + public HQLTest(String x) { + super( x ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( HQLTest.class ); + } + + public boolean createSchema() { + return false; + } + + public boolean recreateSchemaAfterFailure() { + return false; + } + + protected void prepareTest() throws Exception { + super.prepareTest(); + SelectClause.VERSION2_SQL = true; + DotNode.REGRESSION_STYLE_JOIN_SUPPRESSION = true; + DotNode.ILLEGAL_COLL_DEREF_EXCP_BUILDER = new DotNode.IllegalCollectionDereferenceExceptionBuilder() { + public QueryException buildIllegalCollectionDereferenceException(String propertyName, FromReferenceNode lhs) { + throw new QueryException( "illegal syntax near collection: " + propertyName ); + } + }; + } + + protected void cleanupTest() throws Exception { + SelectClause.VERSION2_SQL = false; + DotNode.REGRESSION_STYLE_JOIN_SUPPRESSION = false; + DotNode.ILLEGAL_COLL_DEREF_EXCP_BUILDER = DotNode.DEF_ILLEGAL_COLL_DEREF_EXCP_BUILDER; + super.cleanupTest(); + } + + //FAILING TESTS: + + public void testInvalidCollectionDereferencesFail() { + // should fail with the same exceptions (because of the DotNode.ILLEGAL_COLL_DEREF_EXCP_BUILDER) + assertTranslation( "from Animal a where a.offspring.description = 'xyz'" ); + assertTranslation( "from Animal a where a.offspring.father.description = 'xyz'" ); + } + + public void testSubComponentReferences() { + assertTranslation( "select c.address.zip.code from ComponentContainer c" ); + assertTranslation( "select c.address.zip from ComponentContainer c" ); + assertTranslation( "select c.address from ComponentContainer c" ); + } + + public void testManyToAnyReferences() { + assertTranslation( "from PropertySet p where p.someSpecificProperty.id is not null" ); + assertTranslation( "from PropertySet p join p.generalProperties gp where gp.id is not null" ); + } + + public void testJoinFetchCollectionOfValues() { + assertTranslation( "select h from Human as h join fetch h.nickNames" ); + } + + public void testCollectionJoinsInSubselect() { + // caused by some goofiness in FromElementFactory that tries to + // handle correlated subqueries (but fails miserably) even though this + // is not a correlated subquery. HHH-1248 + assertTranslation( + "select a.id, a.description" + + " from Animal a" + + " left join a.offspring" + + " where a in (" + + " select a1 from Animal a1" + + " left join a1.offspring o" + + " where a1.id=1" + + ")" + ); + assertTranslation( + "select h.id, h.description" + + " from Human h" + + " left join h.friends" + + " where h in (" + + " select h1" + + " from Human h1" + + " left join h1.friends f" + + " where h1.id=1" + + ")" + ); + } + + public void testEmptyInListFailureExpected() { + assertTranslation( "select a from Animal a where a.description in ()" ); + } + + public void testDateTimeArithmeticReturnTypesAndParameterGuessing() { + QueryTranslatorImpl translator = createNewQueryTranslator( "select o.orderDate - o.orderDate from Order o" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] ); + translator = createNewQueryTranslator( "select o.orderDate + 2 from Order o" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.CALENDAR_DATE, translator.getReturnTypes()[0] ); + translator = createNewQueryTranslator( "select o.orderDate -2 from Order o" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.CALENDAR_DATE, translator.getReturnTypes()[0] ); + + translator = createNewQueryTranslator( "from Order o where o.orderDate > ?" ); + assertEquals( "incorrect expected param type", Hibernate.CALENDAR_DATE, translator.getParameterTranslations().getOrdinalParameterExpectedType( 1 ) ); + + translator = createNewQueryTranslator( "select o.orderDate + ? from Order o" ); + assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length ); + assertEquals( "incorrect return type", Hibernate.CALENDAR_DATE, translator.getReturnTypes()[0] ); + assertEquals( "incorrect expected param type", Hibernate.DOUBLE, translator.getParameterTranslations().getOrdinalParameterExpectedType( 1 ) ); + + } + + public void testReturnMetadata() { + HQLQueryPlan plan = createQueryPlan( "from Animal a" ); + check( plan.getReturnMetadata(), false, true ); + + plan = createQueryPlan( "select a as animal from Animal a" ); + check( plan.getReturnMetadata(), false, false ); + + plan = createQueryPlan( "from java.lang.Object" ); + check( plan.getReturnMetadata(), true, true ); + + plan = createQueryPlan( "select o as entity from java.lang.Object o" ); + check( plan.getReturnMetadata(), true, false ); + } + + private void check( + ReturnMetadata returnMetadata, + boolean expectingEmptyTypes, + boolean expectingEmptyAliases) { + assertNotNull( "null return metadata", returnMetadata ); + assertNotNull( "null return metadata - types", returnMetadata ); + assertEquals( "unexpected return size", 1, returnMetadata.getReturnTypes().length ); + if ( expectingEmptyTypes ) { + assertNull( "non-empty types", returnMetadata.getReturnTypes()[0] ); + } + else { + assertNotNull( "empty types", returnMetadata.getReturnTypes()[0] ); + } + if ( expectingEmptyAliases ) { + assertNull( "non-empty aliases", returnMetadata.getReturnAliases() ); + } + else { + assertNotNull( "empty aliases", returnMetadata.getReturnAliases() ); + assertNotNull( "empty aliases", returnMetadata.getReturnAliases()[0] ); + } + } + + public void testImplicitJoinsAlongWithCartesianProduct() { + DotNode.useThetaStyleImplicitJoins = true; + assertTranslation( "select foo.foo from Foo foo, Foo foo2" ); + assertTranslation( "select foo.foo.foo from Foo foo, Foo foo2" ); + DotNode.useThetaStyleImplicitJoins = false; + } + + public void testSubselectBetween() { + assertTranslation("from Animal x where (select max(a.bodyWeight) from Animal a) between :min and :max"); + assertTranslation("from Animal x where (select max(a.description) from Animal a) like 'big%'"); + assertTranslation("from Animal x where (select max(a.bodyWeight) from Animal a) is not null"); + assertTranslation("from Animal x where exists (select max(a.bodyWeight) from Animal a)"); + assertTranslation("from Animal x where (select max(a.bodyWeight) from Animal a) in (1,2,3)"); + } + + public void testFetchOrderBy() { + assertTranslation("from Animal a left outer join fetch a.offspring where a.mother.id = :mid order by a.description"); + } + + public void testCollectionOrderBy() { + assertTranslation("from Animal a join a.offspring o order by a.description"); + assertTranslation("from Animal a join fetch a.offspring order by a.description"); + assertTranslation("from Animal a join fetch a.offspring o order by o.description"); + assertTranslation("from Animal a join a.offspring o order by a.description, o.description"); + } + + public void testExpressionWithParamInFunction() { + assertTranslation("from Animal a where abs(a.bodyWeight-:param) < 2.0"); + assertTranslation("from Animal a where abs(:param - a.bodyWeight) < 2.0"); + assertTranslation("from Animal where abs(:x - :y) < 2.0"); + assertTranslation("from Animal where lower(upper(:foo)) like 'f%'"); + if ( ! ( getDialect() instanceof SybaseDialect ) ) { + // SybaseDialect maps the length function -> len; classic translator does not consider that *when nested* + assertTranslation("from Animal a where abs(abs(a.bodyWeight - 1.0 + :param) * abs(length('ffobar')-3)) = 3.0"); + } + if ( !( getDialect() instanceof MySQLDialect || getDialect() instanceof SybaseDialect ) ) { + assertTranslation("from Animal where lower(upper('foo') || upper(:bar)) like 'f%'"); + } + if ( getDialect() instanceof PostgreSQLDialect ) { + return; + } + assertTranslation("from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0"); + } + + public void testCompositeKeysWithPropertyNamedId() { + assertTranslation( "select e.id.id from EntityWithCrazyCompositeKey e" ); + assertTranslation( "select max(e.id.id) from EntityWithCrazyCompositeKey e" ); + } + + public void testMaxindexHqlFunctionInElementAccessorFailureExpected() { + //TODO: broken SQL + // steve (2005.10.06) - this is perfect SQL, but fairly different from the old parser + // tested : HSQLDB (1.8), Oracle8i + assertTranslation( "select c from ContainerX c where c.manyToMany[ maxindex(c.manyToMany) ].count = 2" ); + assertTranslation( "select c from Container c where c.manyToMany[ maxIndex(c.manyToMany) ].count = 2" ); + } + + public void testMultipleElementAccessorOperatorsFailureExpected() throws Exception { + //TODO: broken SQL + // steve (2005.10.06) - Yes, this is all hosed ;) + assertTranslation( "select c from ContainerX c where c.oneToMany[ c.manyToMany[0].count ].name = 's'" ); + assertTranslation( "select c from ContainerX c where c.manyToMany[ c.oneToMany[0].count ].name = 's'" ); + } + + /*public void testSelectMaxElements() throws Exception { + //TODO: this is almost correct, but missing a select-clause column alias! + assertTranslation("select max( elements(one.manies) ) from org.hibernate.test.legacy.One one"); + }*/ + + public void testKeyManyToOneJoinFailureExpected() { + //TODO: new parser generates unnecessary joins (though the query results are correct) + assertTranslation( "from Order o left join fetch o.lineItems li left join fetch li.product p" ); + assertTranslation( "from Outer o where o.id.master.id.sup.dudu is not null" ); + assertTranslation( "from Outer o where o.id.master.id.sup.dudu is not null" ); + } + + public void testDuplicateExplicitJoinFailureExpected() throws Exception { + //very minor issue with select clause: + assertTranslation( "from Animal a join a.mother m1 join a.mother m2" ); + assertTranslation( "from Zoo zoo join zoo.animals an join zoo.mammals m" ); + assertTranslation( "from Zoo zoo join zoo.mammals an join zoo.mammals m" ); + } + + // TESTS THAT FAIL ONLY ON DIALECTS WITH THETA-STYLE OUTERJOINS: + + public void testIndexWithExplicitJoin() throws Exception { + //TODO: broken on dialects with theta-style outerjoins: + // steve (2005.10.06) - this works perfectly for me on Oracle8i + assertTranslation( "from Zoo zoo join zoo.animals an where zoo.mammals[ index(an) ] = an" ); + assertTranslation( "from Zoo zoo join zoo.mammals dog where zoo.mammals[ index(dog) ] = dog" ); + assertTranslation( "from Zoo zoo join zoo.mammals dog where dog = zoo.mammals[ index(dog) ]" ); + } + + public void testOneToManyMapIndex() throws Exception { + //TODO: this breaks on dialects with theta-style outerjoins: + // steve (2005.10.06) - this works perfectly for me on Oracle8i + assertTranslation( "from Zoo zoo where zoo.mammals['dog'].description like '%black%'" ); + assertTranslation( "from Zoo zoo where zoo.mammals['dog'].father.description like '%black%'" ); + assertTranslation( "from Zoo zoo where zoo.mammals['dog'].father.id = 1234" ); + assertTranslation( "from Zoo zoo where zoo.animals['1234'].description like '%black%'" ); + } + + public void testExplicitJoinMapIndex() throws Exception { + //TODO: this breaks on dialects with theta-style outerjoins: + // steve (2005.10.06) - this works perfectly for me on Oracle8i + assertTranslation( "from Zoo zoo, Dog dog where zoo.mammals['dog'] = dog" ); + assertTranslation( "from Zoo zoo join zoo.mammals dog where zoo.mammals['dog'] = dog" ); + } + + public void testIndexFunction() throws Exception { + // Instead of doing the pre-processor trick like the existing QueryTranslator, this + // is handled by MethodNode. + // steve (2005.10.06) - this works perfectly for me on Oracle8i + //TODO: broken on dialects with theta-style outerjoins: + assertTranslation( "from Zoo zoo join zoo.mammals dog where index(dog) = 'dog'" ); + assertTranslation( "from Zoo zoo join zoo.animals an where index(an) = '1234'" ); + } + + public void testSelectCollectionOfValues() throws Exception { + //TODO: broken on dialects with theta-style joins + ///old parser had a bug where the collection element was not included in return types! + // steve (2005.10.06) - this works perfectly for me on Oracle8i + assertTranslation( "select baz, date from Baz baz join baz.stringDateMap date where index(date) = 'foo'" ); + } + + public void testCollectionOfValues() throws Exception { + //old parser had a bug where the collection element was not returned! + //TODO: broken on dialects with theta-style joins + // steve (2005.10.06) - this works perfectly for me on Oracle8i + assertTranslation( "from Baz baz join baz.stringDateMap date where index(date) = 'foo'" ); + } + + public void testHHH719() throws Exception { + assertTranslation("from Baz b order by org.bazco.SpecialFunction(b.id)"); + assertTranslation("from Baz b order by anypackage.anyFunction(b.id)"); + } + + + //PASSING TESTS: + + public void testParameterListExpansion() { + assertTranslation( "from Animal as animal where animal.id in (:idList_1, :idList_2)" ); + } + + public void testComponentManyToOneDereferenceShortcut() { + assertTranslation( "from Zoo z where z.address.stateProvince.id is null" ); + } + + public void testNestedCollectionImplicitJoins() { + // HHH-770 + assertTranslation( "select h.friends.offspring from Human h" ); + } + + public void testExplicitJoinsInSubquery() { + // test for HHH-557, + // TODO : this passes regardless because the only difference between the two sqls is one extra comma + // (commas are eaten by the tokenizer during asserTranslation when building the token maps). + assertTranslation( + "from org.hibernate.test.hql.Animal as animal " + + "where animal.id in (" + + " select a.id " + + " from org.hibernate.test.hql.Animal as a " + + " left join a.mother as mo" + + ")" + ); + } + + public void testImplicitJoinsInGroupBy() { + assertTranslation( + "select o.mother.bodyWeight, count(distinct o) " + + "from Animal an " + + " join an.offspring as o " + + "group by o.mother.bodyWeight" + ); + } + + public void testCrazyIdFieldNames() { + DotNode.useThetaStyleImplicitJoins = true; + // only regress against non-scalar forms as there appears to be a bug in the classic translator + // in regards to this issue also. Specifically, it interprets the wrong return type, though it gets + // the sql "correct" :/ + + String hql = "select e.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e where e.heresAnotherCrazyIdFieldName is not null"; + assertTranslation( hql, new HashMap(), false, ( String ) null ); + + hql = "select e.heresAnotherCrazyIdFieldName.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e where e.heresAnotherCrazyIdFieldName is not null"; + assertTranslation( hql, new HashMap(), false, ( String ) null ); + + DotNode.useThetaStyleImplicitJoins = false; + } + + public void testSizeFunctionAndProperty() { + assertTranslation("from Animal a where a.offspring.size > 0"); + assertTranslation("from Animal a join a.offspring where a.offspring.size > 1"); + assertTranslation("from Animal a where size(a.offspring) > 0"); + assertTranslation("from Animal a join a.offspring o where size(a.offspring) > 1"); + assertTranslation("from Animal a where size(a.offspring) > 1 and size(a.offspring) < 100"); + + assertTranslation("from Human a where a.family.size > 0"); + assertTranslation("from Human a join a.family where a.family.size > 1"); + assertTranslation("from Human a where size(a.family) > 0"); + assertTranslation("from Human a join a.family o where size(a.family) > 1"); + assertTranslation("from Human a where a.family.size > 0 and a.family.size < 100"); +} + + // Do the simplest test first! + public void testFromOnly() throws Exception { + // 2004-06-21 [jsd] This test now works with the new AST based QueryTranslatorImpl. + assertTranslation( "from Animal" ); + assertTranslation( "from Model" ); + } + + public void testJoinPathEndingInValueCollection() { + assertTranslation( "select h from Human as h join h.nickNames as nn where h.nickName=:nn1 and (nn=:nn2 or nn=:nn3)" ); + } + + public void testSerialJoinPathEndingInValueCollection() { + // HHH-242 + assertTranslation( "select h from Human as h join h.friends as f join f.nickNames as nn where h.nickName=:nn1 and (nn=:nn2 or nn=:nn3)" ); + } + + public void testImplicitJoinContainedByCollectionFunction() { + // HHH-281 : Implied joins in a collection function (i.e., indices or elements) + assertTranslation( "from Human as h where 'shipping' in indices(h.father.addresses)" ); + assertTranslation( "from Human as h where 'shipping' in indices(h.father.father.addresses)" ); + assertTranslation( "from Human as h where 'sparky' in elements(h.father.nickNames)" ); + assertTranslation( "from Human as h where 'sparky' in elements(h.father.father.nickNames)" ); + } + + + public void testImpliedJoinInSubselectFrom() { + // HHH-276 : Implied joins in a from in a subselect. + assertTranslation( "from Animal a where exists( from a.mother.offspring )" ); + } + + public void testSubselectImplicitJoins() { + // HHH-276 : Implied joins in a from in a subselect. + assertTranslation( "from Simple s where s = some( select sim from Simple sim where sim.other.count=s.other.count )" ); + } + + + public void testCollectionOfValuesSize() throws Exception { + //SQL *was* missing a comma + assertTranslation( "select size(baz.stringDateMap) from org.hibernate.test.legacy.Baz baz" ); + } + + public void testCollectionFunctions() throws Exception { + //these are both broken, a join that belongs in the subselect finds its way into the main query + assertTranslation( "from Zoo zoo where size(zoo.animals) > 100" ); + assertTranslation( "from Zoo zoo where maxindex(zoo.mammals) = 'dog'" ); + } + + public void testImplicitJoinInExplicitJoin() throws Exception { + assertTranslation( "from Animal an inner join an.mother.mother gm" ); + assertTranslation( "from Animal an inner join an.mother.mother.mother ggm" ); + assertTranslation( "from Animal an inner join an.mother.mother.mother.mother gggm" ); + } + + public void testImpliedManyToManyProperty() throws Exception { + //missing a table join (SQL correct for a one-to-many, not for a many-to-many) + assertTranslation( "select c from ContainerX c where c.manyToMany[0].name = 's'" ); + } + + public void testCollectionSize() throws Exception { + //SQL is correct, query spaces *was* missing a table + assertTranslation( "select size(zoo.animals) from Zoo zoo" ); + } + + /*public void testCollectionIndexFunctionsInSelect() throws Exception { + assertTranslation("select maxindex(zoo.animals) from Zoo zoo"); + assertTranslation("select minindex(zoo.animals) from Zoo zoo"); + assertTranslation("select indices(zoo.animals) from Zoo zoo"); + } + + public void testCollectionElementFunctionsInSelect() throws Exception { + assertTranslation("select maxelement(zoo.animals) from Zoo zoo"); + assertTranslation("select minelement(zoo.animals) from Zoo zoo"); + assertTranslation("select elements(zoo.animals) from Zoo zoo"); + }*/ + + public void testFetchCollectionOfValues() throws Exception { + assertTranslation( "from Baz baz left join fetch baz.stringSet" ); + } + + public void testFetchList() throws Exception { + assertTranslation( "from User u join fetch u.permissions" ); + } + + public void testCollectionFetchWithExplicitThetaJoin() { + assertTranslation( "select m from Master m1, Master m left join fetch m.details where m.name=m1.name" ); + } + + /*public void testListElementFunctionInSelect() throws Exception { + //wrong pk column in select clause! (easy fix?) + assertTranslation("select maxelement(u.permissions) from User u"); + assertTranslation("select elements(u.permissions) from User u"); + }*/ + + public void testListElementFunctionInWhere() throws Exception { + assertTranslation( "from User u where 'read' in elements(u.permissions)" ); + assertTranslation( "from User u where 'write' <> all elements(u.permissions)" ); + } + + /*public void testManyToManyElementFunctionInSelect() throws Exception { + assertTranslation("select maxelement(human.friends) from Human human"); + assertTranslation("select elements(human.friends) from Human human"); + }*/ + + public void testManyToManyMaxElementFunctionInWhere() throws Exception { + //completely broken!! + assertTranslation( "from Human human where 5 = maxelement(human.friends)" ); + } + + public void testCollectionIndexFunctionsInWhere() throws Exception { + assertTranslation( "from Zoo zoo where 4 = maxindex(zoo.animals)" ); + assertTranslation( "from Zoo zoo where 2 = minindex(zoo.animals)" ); + } + + public void testCollectionIndicesInWhere() throws Exception { + assertTranslation( "from Zoo zoo where 4 > some indices(zoo.animals)" ); + assertTranslation( "from Zoo zoo where 4 > all indices(zoo.animals)" ); + } + + public void testIndicesInWhere() throws Exception { + assertTranslation( "from Zoo zoo where 4 in indices(zoo.animals)" ); + assertTranslation( "from Zoo zoo where exists indices(zoo.animals)" ); + } + + public void testCollectionElementInWhere() throws Exception { + assertTranslation( "from Zoo zoo where 4 > some elements(zoo.animals)" ); + assertTranslation( "from Zoo zoo where 4 > all elements(zoo.animals)" ); + } + + public void testElementsInWhere() throws Exception { + assertTranslation( "from Zoo zoo where 4 in elements(zoo.animals)" ); + assertTranslation( "from Zoo zoo where exists elements(zoo.animals)" ); + } + + public void testNull() throws Exception { + assertTranslation( "from Human h where h.nickName is null" ); + assertTranslation( "from Human h where h.nickName is not null" ); + } + + public void testSubstitutions() throws Exception { + Map replacements = buildTrueFalseReplacementMapForDialect(); + replacements.put("yes", "'Y'"); + assertTranslation( "from Human h where h.pregnant = true", replacements ); + assertTranslation( "from Human h where h.pregnant = yes", replacements ); + assertTranslation( "from Human h where h.pregnant = foo", replacements ); + } + + public void testWhere() throws Exception { + assertTranslation( "from Animal an where an.bodyWeight > 10" ); + // 2004-06-26 [jsd] This one requires NOT GT => LE transform. + assertTranslation( "from Animal an where not an.bodyWeight > 10" ); + assertTranslation( "from Animal an where an.bodyWeight between 0 and 10" ); + assertTranslation( "from Animal an where an.bodyWeight not between 0 and 10" ); + assertTranslation( "from Animal an where sqrt(an.bodyWeight)/2 > 10" ); + // 2004-06-27 [jsd] Recognize 'is null' properly. Generate 'and' and 'or' as well. + assertTranslation( "from Animal an where (an.bodyWeight > 10 and an.bodyWeight < 100) or an.bodyWeight is null" ); + } + + public void testEscapedQuote() throws Exception { + assertTranslation( "from Human h where h.nickName='1 ov''tha''few'"); + } + + public void testCaseWhenElse() { + assertTranslation( "from Human h where case when h.nickName='1ovthafew' then 'Gavin' when h.nickName='turin' then 'Christian' else h.nickName end = h.name.first" ); + } + + public void testCaseExprWhenElse() { + assertTranslation( "from Human h where case h.nickName when '1ovthafew' then 'Gavin' when 'turin' then 'Christian' else h.nickName end = h.name.first" ); + } + + public void testInvalidHql() throws Exception { + Exception newException = compileBadHql( "from Animal foo where an.bodyWeight > 10", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "select an.name from Animal foo", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "from Animal foo where an.verybogus > 10", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "select an.boguspropertyname from Animal foo", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "select an.name", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "from Animal an where (((an.bodyWeight > 10 and an.bodyWeight < 100)) or an.bodyWeight is null", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "from Animal an where an.bodyWeight is null where an.bodyWeight is null", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "from where name='foo'", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "from NonexistentClass where name='foo'", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "select new FOO_BOGUS_Animal(an.description, an.bodyWeight) from Animal an", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + newException = compileBadHql( "select new Animal(an.description, an.bodyWeight, 666) from Animal an", false ); + assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException ); + + } + + public void testWhereBetween() throws Exception { + // 2004-08-31 [jsd] This "just worked"! Woohoo! + assertTranslation( "from Animal an where an.bodyWeight between 1 and 10" ); + } + + public void testConcatenation() { + if ( getDialect() instanceof MySQLDialect || getDialect() instanceof SybaseDialect ) { + // MySQL uses concat(x, y, z) + // SQL Server replaces '||' with '+' + // + // this is syntax checked in {@link ASTParserLoadingTest#testConcatenation} + return; + } + assertTranslation("from Human h where h.nickName = '1' || 'ov' || 'tha' || 'few'"); + } + + public void testWhereLike() throws Exception { + assertTranslation( "from Animal a where a.description like '%black%'" ); + assertTranslation( "from Animal an where an.description like '%fat%'" ); + assertTranslation( "from Animal an where lower(an.description) like '%fat%'" ); + } + + public void testWhereIn() throws Exception { + assertTranslation( "from Animal an where an.description in ('fat', 'skinny')" ); + } + + public void testLiteralInFunction() throws Exception { + assertTranslation( "from Animal an where an.bodyWeight > abs(5)" ); + assertTranslation( "from Animal an where an.bodyWeight > abs(-5)" ); + } + + public void testExpressionInFunction() throws Exception { + assertTranslation( "from Animal an where an.bodyWeight > abs(3-5)" ); + assertTranslation( "from Animal an where an.bodyWeight > abs(3/5)" ); + assertTranslation( "from Animal an where an.bodyWeight > abs(3+5)" ); + assertTranslation( "from Animal an where an.bodyWeight > abs(3*5)" ); + SQLFunction concat = getSessionFactoryImplementor().getSqlFunctionRegistry().findSQLFunction( "concat"); + List list = new ArrayList(); list.add("'fat'"); list.add("'skinny'"); + assertTranslation( "from Animal an where an.description = " + concat.render(list, getSessionFactoryImplementor()) ); + } + + public void testNotOrWhereClause() { + assertTranslation( "from Simple s where 'foo'='bar' or not 'foo'='foo'" ); + assertTranslation( "from Simple s where 'foo'='bar' or not ('foo'='foo')" ); + assertTranslation( "from Simple s where not ( 'foo'='bar' or 'foo'='foo' )" ); + assertTranslation( "from Simple s where not ( 'foo'='bar' and 'foo'='foo' )" ); + assertTranslation( "from Simple s where not ( 'foo'='bar' and 'foo'='foo' ) or not ('x'='y')" ); + assertTranslation( "from Simple s where not ( 'foo'='bar' or 'foo'='foo' ) and not ('x'='y')" ); + assertTranslation( "from Simple s where not ( 'foo'='bar' or 'foo'='foo' ) and 'x'='y'" ); + assertTranslation( "from Simple s where not ( 'foo'='bar' and 'foo'='foo' ) or 'x'='y'" ); + assertTranslation( "from Simple s where 'foo'='bar' and 'foo'='foo' or not 'x'='y'" ); + assertTranslation( "from Simple s where 'foo'='bar' or 'foo'='foo' and not 'x'='y'" ); + assertTranslation( "from Simple s where ('foo'='bar' and 'foo'='foo') or 'x'='y'" ); + assertTranslation( "from Simple s where ('foo'='bar' or 'foo'='foo') and 'x'='y'" ); + assertTranslation( "from Simple s where not( upper( s.name ) ='yada' or 1=2 or 'foo'='bar' or not('foo'='foo') or 'foo' like 'bar' )" ); + } + + public void testComplexExpressionInFunction() throws Exception { + assertTranslation( "from Animal an where an.bodyWeight > abs((3-5)/4)" ); + } + + public void testStandardFunctions() throws Exception { + assertTranslation( "from Animal where current_date = current_time" ); + assertTranslation( "from Animal a where upper(a.description) = 'FAT'" ); + assertTranslation( "select lower(a.description) from Animal a" ); + } + + public void testOrderBy() throws Exception { + assertTranslation( "from Animal an order by an.bodyWeight" ); + assertTranslation( "from Animal an order by an.bodyWeight asc" ); + assertTranslation( "from Animal an order by an.bodyWeight desc" ); + assertTranslation( "from Animal an order by sqrt(an.bodyWeight*4)/2" ); + assertTranslation( "from Animal an order by an.mother.bodyWeight" ); + assertTranslation( "from Animal an order by an.bodyWeight, an.description" ); + assertTranslation( "from Animal an order by an.bodyWeight asc, an.description desc" ); + if ( getDialect() instanceof HSQLDialect || getDialect() instanceof DB2Dialect ) { + assertTranslation( "from Human h order by sqrt(h.bodyWeight), year(h.birthdate)" ); + } + } + + public void testGroupByFunction() { + if ( getDialect() instanceof Oracle9Dialect ) return; + if ( getDialect() instanceof Oracle8iDialect ) return; // the new hiearchy... + if ( getDialect() instanceof PostgreSQLDialect ) return; + assertTranslation( "select count(*) from Human h group by year(h.birthdate)" ); + assertTranslation( "select count(*) from Human h group by trunc( sqrt(h.bodyWeight*4)/2 )" ); + assertTranslation( "select count(*) from Human h group by year(sysdate)" ); + } + + + public void testPolymorphism() throws Exception { + Map replacements = buildTrueFalseReplacementMapForDialect(); + assertTranslation( "from Mammal" ); + assertTranslation( "from Dog" ); + assertTranslation( "from Mammal m where m.pregnant = false and m.bodyWeight > 10", replacements ); + assertTranslation( "from Dog d where d.pregnant = false and d.bodyWeight > 10", replacements ); + } + + private Map buildTrueFalseReplacementMapForDialect() { + HashMap replacements = new HashMap(); + try { + String dialectTrueRepresentation = getDialect().toBooleanValueString( true ); + // if this call succeeds, then the dialect is saying to represent true/false as int values... + Integer.parseInt( dialectTrueRepresentation ); + replacements.put( "true", "1" ); + replacements.put( "false", "0" ); + } + catch( NumberFormatException nfe ) { + // the Integer#parseInt call failed... + } + return replacements; + } + + public void testTokenReplacement() throws Exception { + Map replacements = buildTrueFalseReplacementMapForDialect(); + assertTranslation( "from Mammal m where m.pregnant = false and m.bodyWeight > 10", replacements ); + } + + public void testProduct() throws Exception { + Map replacements = buildTrueFalseReplacementMapForDialect(); + assertTranslation( "from Animal, Animal" ); + assertTranslation( "from Animal x, Animal y where x.bodyWeight = y.bodyWeight" ); + assertTranslation( "from Animal x, Mammal y where x.bodyWeight = y.bodyWeight and not y.pregnant = true", replacements ); + assertTranslation( "from Mammal, Mammal" ); + } + + public void testJoinedSubclassProduct() throws Exception { + assertTranslation( "from PettingZoo, PettingZoo" ); //product of two subclasses + } + + public void testProjectProduct() throws Exception { + assertTranslation( "select x from Human x, Human y where x.nickName = y.nickName" ); + assertTranslation( "select x, y from Human x, Human y where x.nickName = y.nickName" ); + } + + public void testExplicitEntityJoins() throws Exception { + assertTranslation( "from Animal an inner join an.mother mo" ); + assertTranslation( "from Animal an left outer join an.mother mo" ); + assertTranslation( "from Animal an left outer join fetch an.mother" ); + } + + public void testMultipleExplicitEntityJoins() throws Exception { + assertTranslation( "from Animal an inner join an.mother mo inner join mo.mother gm" ); + assertTranslation( "from Animal an left outer join an.mother mo left outer join mo.mother gm" ); + assertTranslation( "from Animal an inner join an.mother m inner join an.father f" ); + assertTranslation( "from Animal an left join fetch an.mother m left join fetch an.father f" ); + } + + public void testMultipleExplicitJoins() throws Exception { + assertTranslation( "from Animal an inner join an.mother mo inner join an.offspring os" ); + assertTranslation( "from Animal an left outer join an.mother mo left outer join an.offspring os" ); + } + + public void testExplicitEntityJoinsWithRestriction() throws Exception { + assertTranslation( "from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" ); + } + + public void testIdProperty() throws Exception { + assertTranslation( "from Animal a where a.mother.id = 12" ); + } + + public void testSubclassAssociation() throws Exception { + assertTranslation( "from DomesticAnimal da join da.owner o where o.nickName = 'Gavin'" ); + assertTranslation( "from DomesticAnimal da left join fetch da.owner" ); + assertTranslation( "from Human h join h.pets p where p.pregnant = 1" ); + assertTranslation( "from Human h join h.pets p where p.bodyWeight > 100" ); + assertTranslation( "from Human h left join fetch h.pets" ); + } + + public void testExplicitCollectionJoins() throws Exception { + assertTranslation( "from Animal an inner join an.offspring os" ); + assertTranslation( "from Animal an left outer join an.offspring os" ); + } + + public void testExplicitOuterJoinFetch() throws Exception { + assertTranslation( "from Animal an left outer join fetch an.offspring" ); + } + + public void testExplicitOuterJoinFetchWithSelect() throws Exception { + assertTranslation( "select an from Animal an left outer join fetch an.offspring" ); + } + + public void testExplicitJoins() throws Exception { + Map replacements = buildTrueFalseReplacementMapForDialect(); + assertTranslation( "from Zoo zoo join zoo.mammals mam where mam.pregnant = true and mam.description like '%white%'", replacements ); + assertTranslation( "from Zoo zoo join zoo.animals an where an.description like '%white%'" ); + } + + /** + * Test for HHH-559 + */ + public void testMultibyteCharacterConstant() throws Exception { + assertTranslation( "from Zoo zoo join zoo.animals an where an.description like '%\u4e2d%'" ); + } + + public void testImplicitJoins() throws Exception { + // Two dots... + assertTranslation( "from Animal an where an.mother.bodyWeight > ?" ); + assertTranslation( "from Animal an where an.mother.bodyWeight > 10" ); + assertTranslation( "from Dog dog where dog.mother.bodyWeight > 10" ); + // Three dots... + assertTranslation( "from Animal an where an.mother.mother.bodyWeight > 10" ); + // The new QT doesn't throw an exception here, so this belongs in ASTQueryTranslator test. [jsd] +// assertTranslation( "from Animal an where an.offspring.mother.bodyWeight > 10" ); + // Is not null (unary postfix operator) + assertTranslation( "from Animal an where an.mother is not null" ); + // ID property shortut (no implicit join) + assertTranslation( "from Animal an where an.mother.id = 123" ); + } + + public void testImplicitJoinInSelect() { + assertTranslation( "select foo, foo.long from Foo foo" ); + DotNode.useThetaStyleImplicitJoins = true; + assertTranslation( "select foo.foo from Foo foo" ); + assertTranslation( "select foo, foo.foo from Foo foo" ); + assertTranslation( "select foo.foo from Foo foo where foo.foo is not null" ); + DotNode.useThetaStyleImplicitJoins = false; + } + + public void testSelectExpressions() { + DotNode.useThetaStyleImplicitJoins = true; + assertTranslation( "select an.mother.mother from Animal an" ); + assertTranslation( "select an.mother.mother.mother from Animal an" ); + assertTranslation( "select an.mother.mother.bodyWeight from Animal an" ); + assertTranslation( "select an.mother.zoo.id from Animal an" ); + assertTranslation( "select user.human.zoo.id from User user" ); + assertTranslation( "select u.userName, u.human.name.first from User u" ); + assertTranslation( "select u.human.name.last, u.human.name.first from User u" ); + assertTranslation( "select bar.baz.name from Bar bar" ); + assertTranslation( "select bar.baz.name, bar.baz.count from Bar bar" ); + DotNode.useThetaStyleImplicitJoins = false; + } + + public void testSelectStandardFunctionsNoParens() throws Exception { + assertTranslation( "select current_date, current_time, current_timestamp from Animal" ); + } + + public void testMapIndex() throws Exception { + assertTranslation( "from User u where u.permissions['hibernate']='read'" ); + } + + /*public void testCollectionFunctionsInSelect() { + //sql is correct, just different order in select clause + assertTranslation("select baz, size(baz.stringSet), count( distinct elements(baz.stringSet) ), max( elements(baz.stringSet) ) from Baz baz group by baz"); + } + + public void testSelectElements() throws Exception { + assertTranslation( "select elements(fum1.friends) from org.hibernate.test.legacy.Fum fum1" ); + assertTranslation( "select elements(one.manies) from org.hibernate.test.legacy.One one" ); + }*/ + + public void testNamedParameters() throws Exception { + assertTranslation( "from Animal an where an.mother.bodyWeight > :weight" ); + } + + // Second set of examples.... + + public void testClassProperty() throws Exception { + // This test causes failures on theta-join dialects because the SQL is different. + // The queries are semantically the same however. + if ( getDialect() instanceof Oracle9Dialect ) return; + if ( getDialect() instanceof Oracle8iDialect ) return; + assertTranslation( "from Animal a where a.mother.class = Reptile" ); + } + + public void testComponent() throws Exception { + assertTranslation( "from Human h where h.name.first = 'Gavin'" ); + } + + public void testSelectEntity() throws Exception { + assertTranslation( "select an from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" ); + assertTranslation( "select mo, an from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" ); + } + + public void testValueAggregate() { + assertTranslation( "select max(p), min(p) from User u join u.permissions p" ); + } + + public void testAggregation() throws Exception { + assertTranslation( "select count(an) from Animal an" ); + assertTranslation( "select count(*) from Animal an" ); + assertTranslation( "select count(distinct an) from Animal an" ); + assertTranslation( "select count(distinct an.id) from Animal an" ); + assertTranslation( "select count(all an.id) from Animal an" ); + } + + public void testSelectProperty() throws Exception { + assertTranslation( "select an.bodyWeight, mo.bodyWeight from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" ); + } + + public void testSelectEntityProperty() throws Exception { + DotNode.useThetaStyleImplicitJoins = true; + assertTranslation( "select an.mother from Animal an" ); + assertTranslation( "select an, an.mother from Animal an" ); + DotNode.useThetaStyleImplicitJoins = false; + } + + public void testSelectDistinctAll() throws Exception { + assertTranslation( "select distinct an.description, an.bodyWeight from Animal an" ); + assertTranslation( "select all an from Animal an" ); + } + + public void testSelectAssociatedEntityId() throws Exception { + assertTranslation( "select an.mother.id from Animal an" ); + } + + public void testGroupBy() throws Exception { + assertTranslation( "select an.mother.id, max(an.bodyWeight) from Animal an group by an.mother.id" ); + assertTranslation( "select an.mother.id, max(an.bodyWeight) from Animal an group by an.mother.id having max(an.bodyWeight)>1.0" ); + } + + public void testGroupByMultiple() throws Exception { + assertTranslation( "select s.id, s.count, count(t), max(t.date) from org.hibernate.test.legacy.Simple s, org.hibernate.test.legacy.Simple t where s.count = t.count group by s.id, s.count order by s.count" ); + } + + public void testManyToMany() throws Exception { + assertTranslation( "from Human h join h.friends f where f.nickName = 'Gavin'" ); + assertTranslation( "from Human h join h.friends f where f.bodyWeight > 100" ); + } + + public void testManyToManyElementFunctionInWhere() throws Exception { + assertTranslation( "from Human human where human in elements(human.friends)" ); + assertTranslation( "from Human human where human = some elements(human.friends)" ); + } + + public void testManyToManyElementFunctionInWhere2() throws Exception { + assertTranslation( "from Human h1, Human h2 where h2 in elements(h1.family)" ); + assertTranslation( "from Human h1, Human h2 where 'father' in indices(h1.family)" ); + } + + public void testManyToManyFetch() throws Exception { + assertTranslation( "from Human h left join fetch h.friends" ); + } + + public void testManyToManyIndexAccessor() throws Exception { + // From ParentChildTest.testCollectionQuery() + assertTranslation( "select c from ContainerX c, Simple s where c.manyToMany[2] = s" ); + assertTranslation( "select s from ContainerX c, Simple s where c.manyToMany[2] = s" ); + assertTranslation( "from ContainerX c, Simple s where c.manyToMany[2] = s" ); + //would be nice to have: + //assertTranslation( "select c.manyToMany[2] from ContainerX c" ); + } + + public void testSelectNew() throws Exception { + assertTranslation( "select new Animal(an.description, an.bodyWeight) from Animal an" ); + assertTranslation( "select new org.hibernate.test.hql.Animal(an.description, an.bodyWeight) from Animal an" ); + } + + public void testSimpleCorrelatedSubselect() throws Exception { + assertTranslation( "from Animal a where a.bodyWeight = (select o.bodyWeight from a.offspring o)" ); + assertTranslation( "from Animal a where a = (from a.offspring o)" ); + } + + public void testSimpleUncorrelatedSubselect() throws Exception { + assertTranslation( "from Animal a where a.bodyWeight = (select an.bodyWeight from Animal an)" ); + assertTranslation( "from Animal a where a = (from Animal an)" ); + } + + public void testSimpleCorrelatedSubselect2() throws Exception { + assertTranslation( "from Animal a where a = (select o from a.offspring o)" ); + assertTranslation( "from Animal a where a in (select o from a.offspring o)" ); + } + + public void testSimpleUncorrelatedSubselect2() throws Exception { + assertTranslation( "from Animal a where a = (select an from Animal an)" ); + assertTranslation( "from Animal a where a in (select an from Animal an)" ); + } + + public void testUncorrelatedSubselect2() throws Exception { + assertTranslation( "from Animal a where a.bodyWeight = (select max(an.bodyWeight) from Animal an)" ); + } + + public void testCorrelatedSubselect2() throws Exception { + assertTranslation( "from Animal a where a.bodyWeight > (select max(o.bodyWeight) from a.offspring o)" ); + } + + public void testManyToManyJoinInSubselect() throws Exception { + DotNode.useThetaStyleImplicitJoins = true; + assertTranslation( "select foo from Foo foo where foo in (select elt from Baz baz join baz.fooArray elt)" ); + DotNode.useThetaStyleImplicitJoins = false; + } + + public void testImplicitJoinInSubselect() throws Exception { + assertTranslation( "from Animal a where a = (select an.mother from Animal an)" ); + assertTranslation( "from Animal a where a.id = (select an.mother.id from Animal an)" ); + } + + public void testManyToOneSubselect() { + //TODO: the join in the subselect also shows up in the outer query! + assertTranslation( "from Animal a where 'foo' in (select m.description from a.mother m)" ); + } + + public void testPositionalParameters() throws Exception { + assertTranslation( "from Animal an where an.bodyWeight > ?" ); + } + + public void testKeywordPropertyName() throws Exception { + assertTranslation( "from Glarch g order by g.order asc" ); + assertTranslation( "select g.order from Glarch g where g.order = 3" ); + } + + public void testJavaConstant() throws Exception { + assertTranslation( "from org.hibernate.test.legacy.Category c where c.name = org.hibernate.test.legacy.Category.ROOT_CATEGORY" ); + assertTranslation( "from org.hibernate.test.legacy.Category c where c.id = org.hibernate.test.legacy.Category.ROOT_ID" ); + // todo : additional desired functionality + //assertTranslation( "from Category c where c.name = Category.ROOT_CATEGORY" ); + //assertTranslation( "select c.name, Category.ROOT_ID from Category as c"); + } + + public void testClassName() throws Exception { + // The Zoo reference is OK; Zoo is discriminator-based; + // the old parser could handle these correctly + // + // However, the Animal one ares not; Animal is joined subclassing; + // the old parser does not handle thee correctly. The new parser + // previously did not handle them correctly in that same way. So they + // used to pass regression even though the output was bogus SQL... + // + // I have moved the Animal ones (plus duplicating the Zoo one) + // to ASTParserLoadingTest for syntax checking. + assertTranslation( "from Zoo zoo where zoo.class = PettingZoo" ); +// assertTranslation( "from DomesticAnimal an where an.class = Dog" ); +// assertTranslation( "from Animal an where an.class = Dog" ); + } + + public void testSelectDialectFunction() throws Exception { + // From SQLFunctionsTest.testDialectSQLFunctions... + if ( getDialect() instanceof HSQLDialect ) { + assertTranslation( "select mod(s.count, 2) from org.hibernate.test.legacy.Simple as s where s.id = 10" ); + //assertTranslation( "from org.hibernate.test.legacy.Simple as s where mod(s.count, 2) = 0" ); + } + assertTranslation( "select upper(human.name.first) from Human human" ); + assertTranslation( "from Human human where lower(human.name.first) like 'gav%'" ); + assertTranslation( "select upper(a.description) from Animal a" ); + assertTranslation( "select max(a.bodyWeight) from Animal a" ); + } + + public void testTwoJoins() throws Exception { + assertTranslation( "from Human human join human.friends, Human h join h.mother" ); + assertTranslation( "from Human human join human.friends f, Animal an join an.mother m where f=m" ); + assertTranslation( "from Baz baz left join baz.fooToGlarch, Bar bar join bar.foo" ); + } + + public void testToOneToManyManyJoinSequence() throws Exception { + assertTranslation( "from Dog d join d.owner h join h.friends f where f.name.first like 'joe%'" ); + } + + public void testToOneToManyJoinSequence() throws Exception { + assertTranslation( "from Animal a join a.mother m join m.offspring" ); + assertTranslation( "from Dog d join d.owner m join m.offspring" ); + assertTranslation( "from Animal a join a.mother m join m.offspring o where o.bodyWeight > a.bodyWeight" ); + } + + public void testSubclassExplicitJoin() throws Exception { + assertTranslation( "from DomesticAnimal da join da.owner o where o.nickName = 'gavin'" ); + assertTranslation( "from DomesticAnimal da join da.owner o where o.bodyWeight > 0" ); + } + + public void testMultipleExplicitCollectionJoins() throws Exception { + assertTranslation( "from Animal an inner join an.offspring os join os.offspring gc" ); + assertTranslation( "from Animal an left outer join an.offspring os left outer join os.offspring gc" ); + } + + public void testSelectDistinctComposite() throws Exception { + // This is from CompositeElementTest.testHandSQL. + assertTranslation( "select distinct p from org.hibernate.test.compositeelement.Parent p join p.children c where c.name like 'Child%'" ); + } + + public void testDotComponent() throws Exception { + // from FumTest.testListIdentifiers() + assertTranslation( "select fum.id from org.hibernate.test.legacy.Fum as fum where not fum.fum='FRIEND'" ); + } + + public void testOrderByCount() throws Exception { + assertTranslation( "from Animal an group by an.zoo.id order by an.zoo.id, count(*)" ); + } + + public void testHavingCount() throws Exception { + assertTranslation( "from Animal an group by an.zoo.id having count(an.zoo.id) > 1" ); + } + + public void selectWhereElements() throws Exception { + assertTranslation( "select foo from Foo foo, Baz baz where foo in elements(baz.fooArray)" ); + } + + public void testCollectionOfComponents() throws Exception { + assertTranslation( "from Baz baz inner join baz.components comp where comp.name='foo'" ); + } + + public void testNestedComponentIsNull() { + // From MapTest... + assertTranslation( "from Commento c where c.marelo.commento.mcompr is null" ); + } + + public void testOneToOneJoinedFetch() throws Exception { + // From OneToOneTest.testOneToOneOnSubclass + assertTranslation( "from org.hibernate.test.onetoone.joined.Person p join fetch p.address left join fetch p.mailingAddress" ); + } + + public void testSubclassImplicitJoin() throws Exception { + assertTranslation( "from DomesticAnimal da where da.owner.nickName like 'Gavin%'" ); + assertTranslation( "from DomesticAnimal da where da.owner.nickName = 'gavin'" ); + assertTranslation( "from DomesticAnimal da where da.owner.bodyWeight > 0" ); + } + + public void testComponent2() throws Exception { + assertTranslation( "from Dog dog where dog.owner.name.first = 'Gavin'" ); + } + + public void testOneToOne() throws Exception { + assertTranslation( "from User u where u.human.nickName='Steve'" ); + assertTranslation( "from User u where u.human.name.first='Steve'" ); + } + + public void testSelectClauseImplicitJoin() throws Exception { + //assertTranslation( "select d.owner.mother from Dog d" ); //bug in old qt + assertTranslation( "select d.owner.mother.description from Dog d" ); + //assertTranslation( "select d.owner.mother from Dog d, Dog h" ); + } + + public void testFromClauseImplicitJoin() throws Exception { + assertTranslation( "from DomesticAnimal da join da.owner.mother m where m.bodyWeight > 10" ); + } + + public void testJoinedSubclassWithOrCondition() { + assertTranslation( "from Animal an where (an.bodyWeight > 10 and an.bodyWeight < 100) or an.bodyWeight is null" ); + } + + public void testImplicitJoinInFrom() { + assertTranslation( "from Human h join h.mother.mother.offspring o" ); + } + + public void testDuplicateImplicitJoinInSelect() { + // This test causes failures on theta-join dialects because the SQL is different. The old parser + // duplicates the condition, whereas the new parser does not. The queries are semantically the + // same however. + if ( getDialect() instanceof Oracle9Dialect ) return; + if ( getDialect() instanceof Oracle8iDialect ) return; + assertTranslation( "select an.mother.bodyWeight from Animal an join an.mother m where an.mother.bodyWeight > 10" ); + assertTranslation( "select an.mother.bodyWeight from Animal an where an.mother.bodyWeight > 10" ); + //assertTranslation("select an.mother from Animal an where an.mother.bodyWeight is not null"); + assertTranslation( "select an.mother.bodyWeight from Animal an order by an.mother.bodyWeight" ); + } + + public void testConstructorNode() throws Exception { + ConstructorNode n = new ConstructorNode(); + assertNull( n.getFromElement() ); + assertFalse( n.isReturnableEntity() ); + } + + public void testIndexNode() throws Exception { + IndexNode n = new IndexNode(); + Exception ex = null; + try { + n.setScalarColumnText( 0 ); + } + catch ( UnsupportedOperationException e ) { + ex = e; + } + assertNotNull( ex ); + } + + public void testExceptions() throws Exception { + DetailedSemanticException dse = new DetailedSemanticException( "test" ); + dse.printStackTrace(); + dse.printStackTrace( new PrintWriter( new StringWriter() ) ); + QuerySyntaxException qse = QuerySyntaxException.convert( new RecognitionException( "test" ), "from bozo b where b.clown = true" ); + assertNotNull( qse.getMessage() ); + } + + public void testSelectProperty2() throws Exception { + assertTranslation( "select an, mo.bodyWeight from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" ); + assertTranslation( "select an, mo, an.bodyWeight, mo.bodyWeight from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" ); + } + + public void testSubclassWhere() throws Exception { + // TODO: The classic QT generates lots of extra parens, etc. + assertTranslation( "from PettingZoo pz1, PettingZoo pz2 where pz1.id = pz2.id" ); + assertTranslation( "from PettingZoo pz1, PettingZoo pz2 where pz1.id = pz2" ); + assertTranslation( "from PettingZoo pz where pz.id > 0 " ); + } + + public void testNestedImplicitJoinsInSelect() throws Exception { + // NOTE: This test is not likely to generate the exact SQL because of the where clause. The synthetic + // theta style joins come out differently in the new QT. + // From FooBarTest.testQuery() + // Missing the foo2_ join, and foo3_ should include subclasses, but it doesn't. +// assertTranslation("select foo.foo.foo.foo.string from org.hibernate.test.legacy.Foo foo where foo.foo.foo = 'bar'"); + assertTranslation( "select foo.foo.foo.foo.string from org.hibernate.test.legacy.Foo foo" ); + } + + public void testNestedComponent() throws Exception { + // From FooBarTest.testQuery() + //an extra set of parens in new SQL + assertTranslation( "from org.hibernate.test.legacy.Foo foo where foo.component.subcomponent.name='bar'" ); + } + + public void testNull2() throws Exception { + //old parser generates useless extra parens + assertTranslation( "from Human h where not( h.nickName is null )" ); + assertTranslation( "from Human h where not( h.nickName is not null )" ); + } + + public void testUnknownFailureFromMultiTableTest() { + assertTranslation( "from Lower s where s.yetanother.name='name'" ); + } + + public void testJoinInSubselect() throws Exception { + //new parser uses ANSI-style inner join syntax + DotNode.useThetaStyleImplicitJoins = true; + assertTranslation( "from Animal a where a in (select m from Animal an join an.mother m)" ); + assertTranslation( "from Animal a where a in (select o from Animal an join an.offspring o)" ); + DotNode.useThetaStyleImplicitJoins = false; + } + + public void testJoinedSubclassImplicitJoin() throws Exception { + // From MultiTableTest.testQueries() + // TODO: This produces the proper from clause now, but the parens in the where clause are different. + assertTranslation( "from org.hibernate.test.legacy.Lower s where s.yetanother.name='name'" ); + } + + public void testProjectProductJoinedSubclass() throws Exception { + // TODO: The old QT generates the discriminator and the theta join in a strange order, and with two extra sets of parens, this is okay, right? + assertTranslation( "select zoo from Zoo zoo, PettingZoo pz where zoo=pz" ); + assertTranslation( "select zoo, pz from Zoo zoo, PettingZoo pz where zoo=pz" ); + } + + public void testCorrelatedSubselect1() throws Exception { + // The old translator generates the theta join before the condition in the sub query. + // TODO: Decide if we want to bother generating the theta join in the same order (non simple). + assertTranslation( "from Animal a where exists (from a.offspring o where o.bodyWeight>10)" ); + } + + public void testOuterAliasInSubselect() { + assertTranslation( "from Human h where h = (from Animal an where an = h)" ); + } + + public void testFetch() throws Exception { + assertTranslation( "from Zoo zoo left join zoo.mammals" ); + assertTranslation( "from Zoo zoo left join fetch zoo.mammals" ); + } + + public void testOneToManyElementFunctionInWhere() throws Exception { + assertTranslation( "from Zoo zoo where 'dog' in indices(zoo.mammals)" ); + assertTranslation( "from Zoo zoo, Dog dog where dog in elements(zoo.mammals)" ); + } + + /*public void testManyToManyElementFunctionInSelect() throws Exception { + assertTranslation("select elements(zoo.mammals) from Zoo zoo"); + assertTranslation("select indices(zoo.mammals) from Zoo zoo"); + }*/ + + public void testManyToManyInJoin() throws Exception { + assertTranslation( "select x.id from Human h1 join h1.family x" ); + //assertTranslation("select index(h2) from Human h1 join h1.family h2"); + } + + public void testManyToManyInSubselect() throws Exception { + assertTranslation( "from Human h1, Human h2 where h2 in (select x.id from h1.family x)" ); + assertTranslation( "from Human h1, Human h2 where 'father' in indices(h1.family)" ); + } + + public void testOneToManyIndexAccess() throws Exception { + assertTranslation( "from Zoo zoo where zoo.mammals['dog'] is not null" ); + } + + public void testImpliedSelect() throws Exception { + assertTranslation( "select zoo from Zoo zoo" ); + assertTranslation( "from Zoo zoo" ); + assertTranslation( "from Zoo zoo join zoo.mammals m" ); + assertTranslation( "from Zoo" ); + assertTranslation( "from Zoo zoo join zoo.mammals" ); + } + + public void testVectorSubselect() { + assertTranslation( "from Animal a where ('foo', 'bar') in (select m.description, m.bodyWeight from a.mother m)" ); + } + + public void testWierdSubselectImplicitJoinStuff() { + //note that the new qt used to eliminate unnecessary join, but no more + assertTranslation("from Simple s where s = some( select sim from Simple sim where sim.other.count=s.other.count ) and s.other.count > 0"); + } + + /*public void testSelectElementsOfCollectionOfValues() throws Exception { + // From FooBarTest.testQuery() + // TODO: This produces the where clause in a different order, but it seems okay. + assertTranslation("select foo.component.name, elements(foo.component.importantDates) from org.hibernate.test.legacy.Foo foo where foo.foo.id=?"); + }*/ + + //public void testMultiTableElements() throws Exception { + /* + HQL : select elements(ls.bag), elements(ls.set) from org.hibernate.test.legacy.Lower ls + OLD SQL: + select top2_.id1_ as col_0_0_, top4_.id1_ as col_1_0_ + from leafsubclass lower0_ inner join rootclass lower0_1_ on lower0_.id__=lower0_1_.id1_, simple_simple bag1_, rootclass top2_, rootclass set3_, rootclass top4_ + where lower0_1_.id1_ is not null and lower0_.id__=bag1_.simple1 and bag1_.simple2=top2_.id1_ and lower0_.id__=set3_.parent and set3_.id1_=top4_.id1_ + */ + + //assertTranslation("select elements(ls.bag), elements(ls.set) from org.hibernate.test.legacy.Lower ls"); + //} + + public void testCollectionsInSelect2() throws Exception { + // This one looks okay now, it just generates extra parens in the where clause. + assertTranslation( "select foo.string from Bar bar left join bar.baz.fooArray foo where bar.string = foo.string" ); + } + + + //public void testCollectionsInSelect() throws Exception { + // From FooBarTest.testCollectionsInSelect + /* + HQL : select baz, baz.stringSet.size, count( distinct elements(baz.stringSet) ), max( elements(baz.stringSet) ) from org.hibernate.test.legacy.Baz baz group by baz + OLD SQL: + select + baz0_.baz_id_column_ as baz_id_c1_, baz0_.count_count as count_co2_37_, baz0_.name_b as name_b37_, baz0_.foo as foo37_, baz0_.superBaz as superBaz37_, baz0_.str as str37_, baz0_.baz_id_column_ as col_0_0_, + count(*) as col_1_0_, + count(distinct stringset2_.element) as col_2_0_, max(stringset3_.element) as col_3_0_ + from baz baz0_, stringSet stringset1_, stringSet stringset2_, stringSet stringset3_ + where baz0_.baz_id_column_=stringset1_.id_ and baz0_.baz_id_column_=stringset2_.id_ and baz0_.baz_id_column_=stringset3_.id_ + group by baz0_.baz_id_column_ + + NEW SQL: + select + // TODO: Remove the extra 'id' column select. + baz0_.baz_id_column_ as col_0_0_, + // TODO: Figure out how the classic translator knows to use count(*) + (select count(*) from stringSet stringset1_ where baz0_.baz_id_column_=stringset1_.id_) as col_1_0_, + // This is also correct. + count(distinct stringset2_.element) as col_2_0_, max(stringset3_.element) as col_3_0_, + // The properties of baz are correct, they're just in the wrong place. + baz0_.baz_id_column_ as baz_id_c1_, baz0_.count_count as count_co2_37_, baz0_.name_b as name_b37_, baz0_.foo as foo37_, baz0_.superBaz as superBaz37_, baz0_.str as str37_ +// FROM is okay. + from baz baz0_ stringSet stringset1_, stringSet stringset3_, stringSet stringset2_ +// WHERE is okay. + where (baz0_.baz_id_column_=stringset1_.id_ and baz0_.baz_id_column_=stringset2_.id_ baz0_.baz_id_column_=stringset3_.id_) +// GROUP BY is okay. + group by baz0_.baz_id_column_ + */ + //assertTranslation( "select baz, size(baz.stringSet), count( distinct elements(baz.stringSet) ), max( elements(baz.stringSet) ) from org.hibernate.test.legacy.Baz baz group by baz"); + + //} + + public void testAssociationPropertyWithoutAlias() throws Exception { + // The classic translator doesn't do this right, so don't bother asserting. + compileWithAstQueryTranslator("from Animal where zoo is null", false); + } + + private void compileWithAstQueryTranslator(String hql, boolean scalar) { + Map replacements = new HashMap(); + QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); + SessionFactoryImplementor factory = getSessionFactoryImplementor(); + QueryTranslator newQueryTranslator = ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory ); + newQueryTranslator.compile( replacements, scalar ); + } + + public void testComponentNoAlias() throws Exception { + // The classic translator doesn't do this right, so don't bother asserting. + compileWithAstQueryTranslator( "from Human where name.first = 'Gavin'", false); + } + +} diff --git a/test/org/hibernate/test/hql/HeresAnotherCrazyIdFieldName.java b/test/org/hibernate/test/hql/HeresAnotherCrazyIdFieldName.java new file mode 100644 index 0000000000..fbe6bffd46 --- /dev/null +++ b/test/org/hibernate/test/hql/HeresAnotherCrazyIdFieldName.java @@ -0,0 +1,35 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of HeresAnotherCrazyIdFieldName. + * + * @author Steve Ebersole + */ +public class HeresAnotherCrazyIdFieldName { + private Long heresAnotherCrazyIdFieldName; + private String name; + + public HeresAnotherCrazyIdFieldName() { + } + + public HeresAnotherCrazyIdFieldName(String name) { + this.name = name; + } + + public Long getHeresAnotherCrazyIdFieldName() { + return heresAnotherCrazyIdFieldName; + } + + public void setHeresAnotherCrazyIdFieldName(Long heresAnotherCrazyIdFieldName) { + this.heresAnotherCrazyIdFieldName = heresAnotherCrazyIdFieldName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/hql/HqlParserTest.java b/test/org/hibernate/test/hql/HqlParserTest.java new file mode 100644 index 0000000000..5872f8f3c2 --- /dev/null +++ b/test/org/hibernate/test/hql/HqlParserTest.java @@ -0,0 +1,1081 @@ +// $Id$ +package org.hibernate.test.hql; + + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import antlr.RecognitionException; +import antlr.TokenStreamException; +import antlr.collections.AST; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.hibernate.hql.ast.HqlParser; +import org.hibernate.hql.ast.tree.Node; +import org.hibernate.hql.ast.util.ASTIterator; +import org.hibernate.hql.ast.util.ASTPrinter; + +/** + * Tests the HQL parser on various inputs, just makes sure that the first phase of the parser + * works properly (i.e. no unexpected syntax errors). + */ +public class HqlParserTest extends TestCase { + + /** + * Standard JUnit test case constructor. + * + * @param name The name of the test case. + */ + public HqlParserTest(String name) { + super( name ); + } + + public void testUnion() throws Exception { + parse("from Animal a where a in (from Cat union from Dog) "); + } + + /** + * Section 9.2 - from * + */ + public void testDocoExamples92() throws Exception { + parse( "from eg.Cat" ); + parse( "from eg.Cat as cat" ); + parse( "from eg.Cat cat" ); + parse( "from Formula, Parameter" ); + parse( "from Formula as form, Parameter as param" ); + } + + /** + * Section 9.3 - Associations and joins * + */ + public void testDocoExamples93() throws Exception { + parse( "from eg.Cat as cat inner join cat.mate as mate left outer join cat.kittens as kitten" ); + parse( "from eg.Cat as cat left join cat.mate.kittens as kittens" ); + parse( "from Formula form full join form.parameter param" ); + parse( "from eg.Cat as cat join cat.mate as mate left join cat.kittens as kitten" ); + parse( "from eg.Cat as cat\ninner join fetch cat.mate\nleft join fetch cat.kittens" ); + } + + /** + * Section 9.4 - Select * + */ + public void testDocoExamples94() throws Exception { + parse( "select mate from eg.Cat as cat inner join cat.mate as mate" ); + parse( "select cat.mate from eg.Cat cat" ); + parse( "select elements(cat.kittens) from eg.Cat cat" ); + parse( "select cat.name from eg.DomesticCat cat where cat.name like 'fri%'" ); + parse( "select cust.name.firstName from Customer as cust" ); + parse( "select mother, offspr, mate.name from eg.DomesticCat\n" + + " as mother inner join mother.mate as mate left outer join\n" + + "mother.kittens as offspr" ); + parse( "select new Family(mother, mate, offspr)\n" + + "from eg.DomesticCat as mother\n" + + "join mother.mate as mate\n" + + "left join mother.kittens as offspr\n" ); + } + + /** + * Section 9.5 - Aggregate functions * + */ + public void testDocoExamples95() throws Exception { + parse( "select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)\n" + + "from eg.Cat cat" ); + parse( "select cat, count( elements(cat.kittens) )\n" + + " from eg.Cat cat group by cat" ); + parse( "select distinct cat.name from eg.Cat cat" ); + parse( "select count(distinct cat.name), count(cat) from eg.Cat cat" ); + } + + /** + * Section 9.6 - Polymorphism * + */ + public void testDocoExamples96() throws Exception { + parse( "from eg.Cat as cat" ); + parse( "from java.lang.Object o" ); + parse( "from eg.Named n, eg.Named m where n.name = m.name" ); + } + + /** + * Section 9.7 - Where * + */ + public void testDocoExamples97() throws Exception { + parse( "from eg.Cat as cat where cat.name='Fritz'" ); + parse( "select foo\n" + + "from eg.Foo foo, eg.Bar bar\n" + + "where foo.startDate = bar.date\n" ); + parse( "from eg.Cat cat where cat.mate.name is not null" ); + parse( "from eg.Cat cat, eg.Cat rival where cat.mate = rival.mate" ); + parse( "select cat, mate\n" + + "from eg.Cat cat, eg.Cat mate\n" + + "where cat.mate = mate" ); + parse( "from eg.Cat as cat where cat.id = 123" ); + parse( "from eg.Cat as cat where cat.mate.id = 69" ); + parse( "from bank.Person person\n" + + "where person.id.country = 'AU'\n" + + "and person.id.medicareNumber = 123456" ); + parse( "from bank.Account account\n" + + "where account.owner.id.country = 'AU'\n" + + "and account.owner.id.medicareNumber = 123456" ); + parse( "from eg.Cat cat where cat.class = eg.DomesticCat" ); + parse( "from eg.AuditLog log, eg.Payment payment\n" + + "where log.item.class = 'eg.Payment' and log.item.id = payment.id" ); + } + + /** + * Section 9.8 - Expressions * + */ + public void testDocoExamples98() throws Exception { + parse( "from eg.DomesticCat cat where cat.name between 'A' and 'B'" ); + parse( "from eg.DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )" ); + parse( "from eg.DomesticCat cat where cat.name not between 'A' and 'B'" ); + parse( "from eg.DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )" ); + parse( "from eg.Cat cat where cat.kittens.size > 0" ); + parse( "from eg.Cat cat where size(cat.kittens) > 0" ); +// This is a little odd. I'm not sure whether 'current' is a keyword. +// parse("from Calendar cal where cal.holidays.maxElement > current date"); +// Using the token 'order' as both a keyword and an identifier works now, but +// the second instance causes some problems because order is valid in the second instance. +// parse("from Order order where maxindex(order.items) > 100"); +// parse("from Order order where minelement(order.items) > 10000"); + parse( "from Order ord where maxindex(ord.items) > 100" ); + parse( "from Order ord where minelement(ord.items) > 10000" ); + + parse( "select mother from eg.Cat as mother, eg.Cat as kit\n" + + "where kit in elements(foo.kittens)" ); + parse( "select p from eg.NameList list, eg.Person p\n" + + "where p.name = some elements(list.names)" ); + parse( "from eg.Cat cat where exists elements(cat.kittens)" ); + parse( "from eg.Player p where 3 > all elements(p.scores)" ); + parse( "from eg.Show show where 'fizard' in indices(show.acts)" ); + + // Yet another example of the pathological 'order' token. +// parse("from Order order where order.items[0].id = 1234"); +// parse("select person from Person person, Calendar calendar\n" +// + "where calendar.holidays['national day'] = person.birthDay\n" +// + "and person.nationality.calendar = calendar"); +// parse("select item from Item item, Order order\n" +// + "where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11"); +// parse("select item from Item item, Order order\n" +// + "where order.items[ maxindex(order.items) ] = item and order.id = 11"); + + parse( "from Order ord where ord.items[0].id = 1234" ); + parse( "select person from Person person, Calendar calendar\n" + + "where calendar.holidays['national day'] = person.birthDay\n" + + "and person.nationality.calendar = calendar" ); + parse( "select item from Item item, Order ord\n" + + "where ord.items[ ord.deliveredItemIndices[0] ] = item and ord.id = 11" ); + parse( "select item from Item item, Order ord\n" + + "where ord.items[ maxindex(ord.items) ] = item and ord.id = 11" ); + + parse( "select item from Item item, Order ord\n" + + "where ord.items[ size(ord.items) - 1 ] = item" ); + + parse( "from eg.DomesticCat cat where upper(cat.name) like 'FRI%'" ); + + parse( "select cust from Product prod, Store store\n" + + "inner join store.customers cust\n" + + "where prod.name = 'widget'\n" + + "and store.location.name in ( 'Melbourne', 'Sydney' )\n" + + "and prod = all elements(cust.currentOrder.lineItems)" ); + + } + + public void testDocoExamples99() throws Exception { + parse( "from eg.DomesticCat cat\n" + + "order by cat.name asc, cat.weight desc, cat.birthdate" ); + } + + public void testDocoExamples910() throws Exception { + parse( "select cat.color, sum(cat.weight), count(cat)\n" + + "from eg.Cat cat group by cat.color" ); + parse( "select foo.id, avg( elements(foo.names) ), max( indices(foo.names) )\n" + + "from eg.Foo foo group by foo.id" ); + parse( "select cat.color, sum(cat.weight), count(cat)\n" + + "from eg.Cat cat group by cat.color\n" + + "having cat.color in (eg.Color.TABBY, eg.Color.BLACK)" ); + parse( "select cat from eg.Cat cat join cat.kittens kitten\n" + + "group by cat having avg(kitten.weight) > 100\n" + + "order by count(kitten) asc, sum(kitten.weight) desc" ); + } + + public void testDocoExamples911() throws Exception { + parse( "from eg.Cat as fatcat where fatcat.weight > (\n" + + "select avg(cat.weight) from eg.DomesticCat cat)" ); + parse( "from eg.DomesticCat as cat where cat.name = some (\n" + + "select name.nickName from eg.Name as name)\n" ); + parse( "from eg.Cat as cat where not exists (\n" + + "from eg.Cat as mate where mate.mate = cat)" ); + parse( "from eg.DomesticCat as cat where cat.name not in (\n" + + "select name.nickName from eg.Name as name)" ); + } + + public void testDocoExamples912() throws Exception { + parse( "select ord.id, sum(price.amount), count(item)\n" + + "from Order as ord join ord.lineItems as item\n" + + "join item.product as product, Catalog as catalog\n" + + "join catalog.prices as price\n" + + "where ord.paid = false\n" + + "and ord.customer = :customer\n" + + "and price.product = product\n" + + "and catalog.effectiveDate < sysdate\n" + + "and catalog.effectiveDate >= all (\n" + + "select cat.effectiveDate from Catalog as cat where cat.effectiveDate < sysdate)\n" + + "group by ord\n" + + "having sum(price.amount) > :minAmount\n" + + "order by sum(price.amount) desc" ); + + parse( "select ord.id, sum(price.amount), count(item)\n" + + "from Order as ord join ord.lineItems as item join item.product as product,\n" + + "Catalog as catalog join catalog.prices as price\n" + + "where ord.paid = false and ord.customer = :customer\n" + + "and price.product = product and catalog = :currentCatalog\n" + + "group by ord having sum(price.amount) > :minAmount\n" + + "order by sum(price.amount) desc" ); + + parse( "select count(payment), status.name \n" + + "from Payment as payment \n" + + " join payment.currentStatus as status\n" + + " join payment.statusChanges as statusChange\n" + + "where payment.status.name <> PaymentStatus.AWAITING_APPROVAL\n" + + " or (\n" + + " statusChange.timeStamp = ( \n" + + " select max(change.timeStamp) \n" + + " from PaymentStatusChange change \n" + + " where change.payment = payment\n" + + " )\n" + + " and statusChange.user <> :currentUser\n" + + " )\n" + + "group by status.name, status.sortOrder\n" + + "order by status.sortOrder" ); + parse( "select count(payment), status.name \n" + + "from Payment as payment\n" + + " join payment.currentStatus as status\n" + + "where payment.status.name <> PaymentStatus.AWAITING_APPROVAL\n" + + " or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser\n" + + "group by status.name, status.sortOrder\n" + + "order by status.sortOrder" ); + parse( "select account, payment\n" + + "from Account as account\n" + + " left outer join account.payments as payment\n" + + "where :currentUser in elements(account.holder.users)\n" + + " and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)\n" + + "order by account.type.sortOrder, account.accountNumber, payment.dueDate" ); + parse( "select account, payment\n" + + "from Account as account\n" + + " join account.holder.users as user\n" + + " left outer join account.payments as payment\n" + + "where :currentUser = user\n" + + " and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)\n" + + "order by account.type.sortOrder, account.accountNumber, payment.dueDate" ); + } + + public void testExamples1() throws Exception { + parse( "select new org.hibernate.test.S(s.count, s.address)\n" + + "from s in class Simple" ); + parse( "select s.name, sysdate, trunc(s.pay), round(s.pay) from s in class Simple" ); + parse( "select round(s.pay, 2) from s" ); + parse( "select abs(round(s.pay)) from s in class Simple" ); + parse( "select trunc(round(sysdate)) from s in class Simple" ); + } + + public void testArrayExpr() throws Exception { + parse( "from Order ord where ord.items[0].id = 1234" ); + } + + public void testMultipleActualParameters() throws Exception { + parse( "select round(s.pay, 2) from s" ); + } + + public void testMultipleFromClasses() throws Exception { + parse( "FROM eg.mypackage.Cat qat, com.toadstool.Foo f" ); + parse( "FROM eg.mypackage.Cat qat, org.jabberwocky.Dipstick" ); + } + + public void testFromWithJoin() throws Exception { + parse( "FROM eg.mypackage.Cat qat, com.toadstool.Foo f join net.sf.blurb.Blurb" ); + parse( "FROM eg.mypackage.Cat qat left join com.multijoin.JoinORama , com.toadstool.Foo f join net.sf.blurb.Blurb" ); + } + + public void testSelect() throws Exception { + parse( "SELECT f FROM eg.mypackage.Cat qat, com.toadstool.Foo f join net.sf.blurb.Blurb" ); + parse( "SELECT DISTINCT bar FROM eg.mypackage.Cat qat left join com.multijoin.JoinORama as bar, com.toadstool.Foo f join net.sf.blurb.Blurb" ); + parse( "SELECT count(*) FROM eg.mypackage.Cat qat" ); + parse( "SELECT avg(qat.weight) FROM eg.mypackage.Cat qat" ); + } + + public void testWhere() throws Exception { + parse( "FROM eg.mypackage.Cat qat where qat.name like '%fluffy%' or qat.toes > 5" ); + parse( "FROM eg.mypackage.Cat qat where not qat.name like '%fluffy%' or qat.toes > 5" ); + parse( "FROM eg.mypackage.Cat qat where not qat.name not like '%fluffy%'" ); + parse( "FROM eg.mypackage.Cat qat where qat.name in ('crater','bean','fluffy')" ); + parse( "FROM eg.mypackage.Cat qat where qat.name not in ('crater','bean','fluffy')" ); + parse( "from Animal an where sqrt(an.bodyWeight)/2 > 10" ); + parse( "from Animal an where (an.bodyWeight > 10 and an.bodyWeight < 100) or an.bodyWeight is null" ); + } + + public void testGroupBy() throws Exception { + parse( "FROM eg.mypackage.Cat qat group by qat.breed" ); + parse( "FROM eg.mypackage.Cat qat group by qat.breed, qat.eyecolor" ); + } + + public void testOrderBy() throws Exception { + parse( "FROM eg.mypackage.Cat qat order by avg(qat.toes)" ); + parse( "from Animal an order by sqrt(an.bodyWeight)/2" ); + } + + public void testDoubleLiteral() throws Exception { + parse( "from eg.Cat as tinycat where fatcat.weight < 3.1415" ); + parse( "from eg.Cat as enormouscat where fatcat.weight > 3.1415e3" ); + } + + public void testComplexConstructor() throws Exception { + parse( "select new Foo(count(bar)) from bar" ); + parse( "select new Foo(count(bar),(select count(*) from doofus d where d.gob = 'fat' )) from bar" ); + } + + + public void testInNotIn() throws Exception { + parse( "from foo where foo.bar in ('a' , 'b', 'c')" ); + parse( "from foo where foo.bar not in ('a' , 'b', 'c')" ); + } + + public void testOperatorPrecedence() throws Exception { + parse( "from foo where foo.bar = 123 + foo.baz * foo.not" ); + parse( "from foo where foo.bar like 'testzzz' || foo.baz or foo.bar in ('duh', 'gob')" ); + } + + /** + * Tests HQL generated by the other unit tests. + * + * @throws Exception if the HQL could not be parsed. + */ + public void testUnitTestHql() throws Exception { + parse( "select foo from foo in class org.hibernate.test.Foo, fee in class org.hibernate.test.Fee where foo.dependent = fee order by foo.string desc, foo.component.count asc, fee.id" ); + parse( "select foo.foo, foo.dependent from foo in class org.hibernate.test.Foo order by foo.foo.string desc, foo.component.count asc, foo.dependent.id" ); + parse( "select foo from foo in class org.hibernate.test.Foo order by foo.dependent.id, foo.dependent.fi" ); + parse( "SELECT one FROM one IN CLASS org.hibernate.test.One ORDER BY one.value ASC" ); + parse( "SELECT many.one FROM many IN CLASS org.hibernate.test.Many ORDER BY many.one.value ASC, many.one.id" ); + parse( "select foo.id from org.hibernate.test.Foo foo where foo.joinedProp = 'foo'" ); + parse( "from org.hibernate.test.Foo foo inner join fetch foo.foo" ); + parse( "from org.hibernate.test.Baz baz left outer join fetch baz.fooToGlarch" ); + parse( "select foo.foo.foo.string from foo in class org.hibernate.test.Foo where foo.foo = 'bar'" ); + parse( "select foo.foo.foo.foo.string from foo in class org.hibernate.test.Foo where foo.foo.foo = 'bar'" ); + parse( "select foo.foo.foo.string from foo in class org.hibernate.test.Foo where foo.foo.foo.foo.string = 'bar'" ); + parse( "select foo.string from foo in class org.hibernate.test.Foo where foo.foo.foo = 'bar' and foo.foo.foo.foo = 'baz'" ); + parse( "select foo.string from foo in class org.hibernate.test.Foo where foo.foo.foo.foo.string = 'a' and foo.foo.string = 'b'" ); + parse( "from org.hibernate.test.Foo as foo where foo.component.glarch.name is not null" ); + parse( "from org.hibernate.test.Foo as foo left outer join foo.component.glarch as glarch where glarch.name = 'foo'" ); + parse( "from org.hibernate.test.Foo" ); + parse( "from org.hibernate.test.Foo foo left outer join foo.foo" ); + parse( "from org.hibernate.test.Foo, org.hibernate.test.Bar" ); + parse( "from org.hibernate.test.Baz baz left join baz.fooToGlarch, org.hibernate.test.Bar bar join bar.foo" ); + parse( "from org.hibernate.test.Baz baz left join baz.fooToGlarch join baz.fooSet" ); + parse( "from org.hibernate.test.Baz baz left join baz.fooToGlarch join fetch baz.fooSet foo left join fetch foo.foo" ); + parse( "from foo in class org.hibernate.test.Foo where foo.string='osama bin laden' and foo.boolean = true order by foo.string asc, foo.component.count desc" ); + parse( "from foo in class org.hibernate.test.Foo where foo.string='osama bin laden' order by foo.string asc, foo.component.count desc" ); + parse( "select foo.foo from foo in class org.hibernate.test.Foo" ); + parse( "from foo in class org.hibernate.test.Foo where foo.component.count is null order by foo.component.count" ); + parse( "from foo in class org.hibernate.test.Foo where foo.component.name='foo'" ); + parse( "select distinct foo.component.name, foo.component.name from foo in class org.hibernate.test.Foo where foo.component.name='foo'" ); + parse( "select distinct foo.component.name, foo.id from foo in class org.hibernate.test.Foo where foo.component.name='foo'" ); + parse( "from foo in class org.hibernate.test.Foo where foo.id=?" ); + parse( "from foo in class org.hibernate.test.Foo where foo.key=?" ); + parse( "select foo.foo from foo in class org.hibernate.test.Foo where foo.string='fizard'" ); + parse( "from foo in class org.hibernate.test.Foo where foo.component.subcomponent.name='bar'" ); + parse( "select foo.foo from foo in class org.hibernate.test.Foo where foo.foo.id=?" ); + parse( "from foo in class org.hibernate.test.Foo where foo.foo = ?" ); + parse( "from bar in class org.hibernate.test.Bar where bar.string='a string' or bar.string='a string'" ); + parse( "select foo.component.name, elements(foo.component.importantDates) from foo in class org.hibernate.test.Foo where foo.foo.id=?" ); + parse( "select max(elements(foo.component.importantDates)) from foo in class org.hibernate.test.Foo group by foo.id" ); + parse( "select foo.foo.foo.foo from foo in class org.hibernate.test.Foo, foo2 in class org.hibernate.test.Foo where foo = foo2.foo and not not ( not foo.string='fizard' ) and foo2.string between 'a' and (foo.foo.string) and ( foo2.string in ( 'fiz', 'blah') or 1=1 )" ); + parse( "from foo in class org.hibernate.test.Foo where foo.string='from BoogieDown -tinsel town =!@#$^&*())'" ); + parse( "from foo in class org.hibernate.test.Foo where not foo.string='foo''bar'" ); // Added quote quote is an escape + parse( "from foo in class org.hibernate.test.Foo where foo.component.glarch.next is null" ); + parse( " from bar in class org.hibernate.test.Bar where bar.baz.count=667 and bar.baz.count!=123 and not bar.baz.name='1-E-1'" ); + parse( " from i in class org.hibernate.test.Bar where i.baz.name='Bazza'" ); + parse( "select count(distinct foo.foo) from foo in class org.hibernate.test.Foo" ); + parse( "select count(foo.foo.boolean) from foo in class org.hibernate.test.Foo" ); + parse( "select count(*), foo.int from foo in class org.hibernate.test.Foo group by foo.int" ); + parse( "select sum(foo.foo.int) from foo in class org.hibernate.test.Foo" ); + parse( "select count(foo) from foo in class org.hibernate.test.Foo where foo.id=?" ); + parse( "from foo in class org.hibernate.test.Foo where foo.boolean = ?" ); + parse( "select new Foo(fo.x) from org.hibernate.test.Fo fo" ); + parse( "select new Foo(fo.integer) from org.hibernate.test.Foo fo" ); + parse( "select new Foo(fo.x) from org.hibernate.test.Foo fo" ); + parse( "select foo.long, foo.component.name, foo, foo.foo from foo in class org.hibernate.test.Foo" ); + parse( "select avg(foo.float), max(foo.component.name), count(distinct foo.id) from foo in class org.hibernate.test.Foo" ); + parse( "select foo.long, foo.component, foo, foo.foo from foo in class org.hibernate.test.Foo" ); + parse( "from o in class org.hibernate.test.MoreStuff" ); + parse( "from o in class org.hibernate.test.Many" ); + parse( "from o in class org.hibernate.test.Fee" ); + parse( "from o in class org.hibernate.test.Qux" ); + parse( "from o in class org.hibernate.test.Y" ); + parse( "from o in class org.hibernate.test.Fumm" ); + parse( "from o in class org.hibernate.test.X" ); + parse( "from o in class org.hibernate.test.Simple" ); + parse( "from o in class org.hibernate.test.Location" ); + parse( "from o in class org.hibernate.test.Holder" ); + parse( "from o in class org.hibernate.test.Part" ); + parse( "from o in class org.hibernate.test.Baz" ); + parse( "from o in class org.hibernate.test.Vetoer" ); + parse( "from o in class org.hibernate.test.Sortable" ); + parse( "from o in class org.hibernate.test.Contained" ); + parse( "from o in class org.hibernate.test.Stuff" ); + parse( "from o in class org.hibernate.test.Immutable" ); + parse( "from o in class org.hibernate.test.Container" ); + parse( "from o in class org.hibernate.test.X$XX" ); + parse( "from o in class org.hibernate.test.One" ); + parse( "from o in class org.hibernate.test.Foo" ); + parse( "from o in class org.hibernate.test.Fo" ); + parse( "from o in class org.hibernate.test.Glarch" ); + parse( "from o in class org.hibernate.test.Fum" ); + parse( "from n in class org.hibernate.test.Holder" ); + parse( "from n in class org.hibernate.test.Baz" ); + parse( "from n in class org.hibernate.test.Bar" ); + parse( "from n in class org.hibernate.test.Glarch" ); + parse( "from n in class org.hibernate.test.Holder where n.name is not null" ); + parse( "from n in class org.hibernate.test.Baz where n.name is not null" ); + parse( "from n in class org.hibernate.test.Bar where n.name is not null" ); + parse( "from n in class org.hibernate.test.Glarch where n.name is not null" ); + parse( "from n in class org.hibernate.test.Holder" ); + parse( "from n in class org.hibernate.test.Baz" ); + parse( "from n in class org.hibernate.test.Bar" ); + parse( "from n in class org.hibernate.test.Glarch" ); + parse( "from n0 in class org.hibernate.test.Holder, n1 in class org.hibernate.test.Holder where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Baz, n1 in class org.hibernate.test.Holder where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Bar, n1 in class org.hibernate.test.Holder where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Glarch, n1 in class org.hibernate.test.Holder where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Holder, n1 in class org.hibernate.test.Baz where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Baz, n1 in class org.hibernate.test.Baz where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Bar, n1 in class org.hibernate.test.Baz where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Glarch, n1 in class org.hibernate.test.Baz where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Holder, n1 in class org.hibernate.test.Bar where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Baz, n1 in class org.hibernate.test.Bar where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Bar, n1 in class org.hibernate.test.Bar where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Glarch, n1 in class org.hibernate.test.Bar where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Holder, n1 in class org.hibernate.test.Glarch where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Baz, n1 in class org.hibernate.test.Glarch where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Bar, n1 in class org.hibernate.test.Glarch where n0.name = n1.name" ); + parse( "from n0 in class org.hibernate.test.Glarch, n1 in class org.hibernate.test.Glarch where n0.name = n1.name" ); + parse( "from n in class org.hibernate.test.Holder where n.name = :name" ); + parse( "from o in class org.hibernate.test.MoreStuff" ); + parse( "from o in class org.hibernate.test.Many" ); + parse( "from o in class org.hibernate.test.Fee" ); + parse( "from o in class org.hibernate.test.Qux" ); + parse( "from o in class org.hibernate.test.Y" ); + parse( "from o in class org.hibernate.test.Fumm" ); + parse( "from o in class org.hibernate.test.X" ); + parse( "from o in class org.hibernate.test.Simple" ); + parse( "from o in class org.hibernate.test.Location" ); + parse( "from o in class org.hibernate.test.Holder" ); + parse( "from o in class org.hibernate.test.Part" ); + parse( "from o in class org.hibernate.test.Baz" ); + parse( "from o in class org.hibernate.test.Vetoer" ); + parse( "from o in class org.hibernate.test.Sortable" ); + parse( "from o in class org.hibernate.test.Contained" ); + parse( "from o in class org.hibernate.test.Stuff" ); + parse( "from o in class org.hibernate.test.Immutable" ); + parse( "from o in class org.hibernate.test.Container" ); + parse( "from o in class org.hibernate.test.X$XX" ); + parse( "from o in class org.hibernate.test.One" ); + parse( "from o in class org.hibernate.test.Foo" ); + parse( "from o in class org.hibernate.test.Fo" ); + parse( "from o in class org.hibernate.test.Glarch" ); + parse( "from o in class org.hibernate.test.Fum" ); + parse( "select baz.code, min(baz.count) from baz in class org.hibernate.test.Baz group by baz.code" ); + parse( "selecT baz from baz in class org.hibernate.test.Baz where baz.stringDateMap['foo'] is not null or baz.stringDateMap['bar'] = ?" ); + parse( "select baz from baz in class org.hibernate.test.Baz where baz.stringDateMap['now'] is not null" ); + parse( "select baz from baz in class org.hibernate.test.Baz where baz.stringDateMap['now'] is not null and baz.stringDateMap['big bang'] < baz.stringDateMap['now']" ); + parse( "select index(date) from org.hibernate.test.Baz baz join baz.stringDateMap date" ); + parse( "from foo in class org.hibernate.test.Foo where foo.integer not between 1 and 5 and foo.string not in ('cde', 'abc') and foo.string is not null and foo.integer<=3" ); + parse( "from org.hibernate.test.Baz baz inner join baz.collectionComponent.nested.foos foo where foo.string is null" ); + parse( "from org.hibernate.test.Baz baz inner join baz.fooSet where '1' in (from baz.fooSet foo where foo.string is not null)" ); + parse( "from org.hibernate.test.Baz baz where 'a' in elements(baz.collectionComponent.nested.foos) and 1.0 in elements(baz.collectionComponent.nested.floats)" ); + parse( "from org.hibernate.test.Foo foo join foo.foo where foo.foo in ('1','2','3')" ); + parse( "select foo.foo from org.hibernate.test.Foo foo where foo.foo in ('1','2','3')" ); + parse( "select foo.foo.string from org.hibernate.test.Foo foo where foo.foo in ('1','2','3')" ); + parse( "select foo.foo.string from org.hibernate.test.Foo foo where foo.foo.string in ('1','2','3')" ); + parse( "select foo.foo.long from org.hibernate.test.Foo foo where foo.foo.string in ('1','2','3')" ); + parse( "select count(*) from org.hibernate.test.Foo foo where foo.foo.string in ('1','2','3') or foo.foo.long in (1,2,3)" ); + parse( "select count(*) from org.hibernate.test.Foo foo where foo.foo.string in ('1','2','3') group by foo.foo.long" ); + parse( "from org.hibernate.test.Foo foo1 left join foo1.foo foo2 left join foo2.foo where foo1.string is not null" ); + parse( "from org.hibernate.test.Foo foo1 left join foo1.foo.foo where foo1.string is not null" ); + parse( "from org.hibernate.test.Foo foo1 left join foo1.foo foo2 left join foo1.foo.foo foo3 where foo1.string is not null" ); + parse( "select foo.formula from org.hibernate.test.Foo foo where foo.formula > 0" ); + parse( "from org.hibernate.test.Foo as foo join foo.foo as foo2 where foo2.id >'a' or foo2.id <'a'" ); + parse( "from org.hibernate.test.Holder" ); + parse( "from org.hibernate.test.Baz baz left outer join fetch baz.manyToAny" ); + parse( "from org.hibernate.test.Baz baz join baz.manyToAny" ); + parse( "select baz from org.hibernate.test.Baz baz join baz.manyToAny a where index(a) = 0" ); + parse( "select bar from org.hibernate.test.Bar bar where bar.baz.stringDateMap['now'] is not null" ); + parse( "select bar from org.hibernate.test.Bar bar join bar.baz b where b.stringDateMap['big bang'] < b.stringDateMap['now'] and b.stringDateMap['now'] is not null" ); + parse( "select bar from org.hibernate.test.Bar bar where bar.baz.stringDateMap['big bang'] < bar.baz.stringDateMap['now'] and bar.baz.stringDateMap['now'] is not null" ); + parse( "select foo.string, foo.component, foo.id from org.hibernate.test.Bar foo" ); + parse( "select elements(baz.components) from org.hibernate.test.Baz baz" ); + parse( "select bc.name from org.hibernate.test.Baz baz join baz.components bc" ); + parse( "from org.hibernate.test.Foo foo where foo.integer < 10 order by foo.string" ); + parse( "from org.hibernate.test.Fee" ); + parse( "from org.hibernate.test.Holder h join h.otherHolder oh where h.otherHolder.name = 'bar'" ); + parse( "from org.hibernate.test.Baz baz join baz.fooSet foo join foo.foo.foo foo2 where foo2.string = 'foo'" ); + parse( "from org.hibernate.test.Baz baz join baz.fooArray foo join foo.foo.foo foo2 where foo2.string = 'foo'" ); + parse( "from org.hibernate.test.Baz baz join baz.stringDateMap date where index(date) = 'foo'" ); + parse( "from org.hibernate.test.Baz baz join baz.topGlarchez g where index(g) = 'A'" ); + parse( "select index(g) from org.hibernate.test.Baz baz join baz.topGlarchez g" ); + parse( "from org.hibernate.test.Baz baz left join baz.stringSet" ); + parse( "from org.hibernate.test.Baz baz join baz.stringSet str where str='foo'" ); + parse( "from org.hibernate.test.Baz baz left join fetch baz.stringSet" ); + parse( "from org.hibernate.test.Baz baz join baz.stringSet string where string='foo'" ); + parse( "from org.hibernate.test.Baz baz inner join baz.components comp where comp.name='foo'" ); + parse( "from org.hibernate.test.Glarch g inner join g.fooComponents comp where comp.fee is not null" ); + parse( "from org.hibernate.test.Glarch g inner join g.fooComponents comp join comp.fee fee where fee.count > 0" ); + parse( "from org.hibernate.test.Glarch g inner join g.fooComponents comp where comp.fee.count is not null" ); + parse( "from org.hibernate.test.Baz baz left join fetch baz.fooBag" ); + parse( "from org.hibernate.test.Glarch" ); + parse( "from org.hibernate.test.Fee" ); + parse( "from org.hibernate.test.Baz baz left join fetch baz.sortablez order by baz.name asc" ); + parse( "from org.hibernate.test.Baz baz order by baz.name asc" ); + parse( "from org.hibernate.test.Foo foo, org.hibernate.test.Baz baz left join fetch baz.fees" ); + parse( "from org.hibernate.test.Foo foo, org.hibernate.test.Bar bar" ); + parse( "from org.hibernate.test.Foo foo" ); + parse( "from org.hibernate.test.Foo foo, org.hibernate.test.Bar bar, org.hibernate.test.Bar bar2" ); + parse( "from org.hibernate.test.X x" ); + parse( "from org.hibernate.test.Foo foo" ); + parse( "select distinct foo from org.hibernate.test.Foo foo" ); + parse( "from org.hibernate.test.Glarch g where g.multiple.glarch=g and g.multiple.count=12" ); + parse( "from org.hibernate.test.Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like 'Bar %'" ); + parse( "select bar, b from org.hibernate.test.Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like 'Bar%'" ); + parse( "select bar, b from org.hibernate.test.Bar bar left join bar.baz baz left join baz.cascadingBars b where ( bar.name in (:nameList0_, :nameList1_, :nameList2_) or bar.name in (:nameList0_, :nameList1_, :nameList2_) ) and bar.string = :stringVal" ); + parse( "select bar, b from org.hibernate.test.Bar bar inner join bar.baz baz inner join baz.cascadingBars b where bar.name like 'Bar%'" ); + parse( "select bar, b from org.hibernate.test.Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like :name and b.name like :name" ); + parse( "select bar from org.hibernate.test.Bar as bar where bar.x > ? or bar.short = 1 or bar.string = 'ff ? bb'" ); + parse( "select bar from org.hibernate.test.Bar as bar where bar.string = ' ? ' or bar.string = '?'" ); + parse( "from org.hibernate.test.Baz baz, baz.fooArray foo" ); + parse( "from s in class org.hibernate.test.Stuff where s.foo.id = ? and s.id.id = ? and s.moreStuff.id.intId = ? and s.moreStuff.id.stringId = ?" ); + parse( "from s in class org.hibernate.test.Stuff where s.foo.id = ? and s.id.id = ? and s.moreStuff.name = ?" ); + parse( "from s in class org.hibernate.test.Stuff where s.foo.string is not null" ); + parse( "from s in class org.hibernate.test.Stuff where s.foo > '0' order by s.foo" ); + parse( "from ms in class org.hibernate.test.MoreStuff" ); + parse( "from foo in class org.hibernate.test.Foo" ); + parse( "from fee in class org.hibernate.test.Fee" ); + parse( "select new Result(foo.string, foo.long, foo.integer) from foo in class org.hibernate.test.Foo" ); + parse( "select new Result( baz.name, foo.long, count(elements(baz.fooArray)) ) from org.hibernate.test.Baz baz join baz.fooArray foo group by baz.name, foo.long" ); + parse( "select new Result( baz.name, max(foo.long), count(foo) ) from org.hibernate.test.Baz baz join baz.fooArray foo group by baz.name" ); + parse( "select max( elements(bar.baz.fooArray) ) from org.hibernate.test.Bar as bar" ); + parse( "from org.hibernate.test.Baz baz left join baz.fooToGlarch join fetch baz.fooArray foo left join fetch foo.foo" ); + parse( "select baz.name from org.hibernate.test.Bar bar inner join bar.baz baz inner join baz.fooSet foo where baz.name = bar.string" ); + parse( "SELECT baz.name FROM org.hibernate.test.Bar AS bar INNER JOIN bar.baz AS baz INNER JOIN baz.fooSet AS foo WHERE baz.name = bar.string" ); + parse( "select baz.name from org.hibernate.test.Bar bar join bar.baz baz left outer join baz.fooSet foo where baz.name = bar.string" ); + parse( "select baz.name from org.hibernate.test.Bar bar, bar.baz baz, baz.fooSet foo where baz.name = bar.string" ); + parse( "SELECT baz.name FROM org.hibernate.test.Bar AS bar, bar.baz AS baz, baz.fooSet AS foo WHERE baz.name = bar.string" ); + parse( "select baz.name from org.hibernate.test.Bar bar left join bar.baz baz left join baz.fooSet foo where baz.name = bar.string" ); + parse( "select foo.string from org.hibernate.test.Bar bar left join bar.baz.fooSet foo where bar.string = foo.string" ); + parse( "select baz.name from org.hibernate.test.Bar bar left join bar.baz baz left join baz.fooArray foo where baz.name = bar.string" ); + parse( "select foo.string from org.hibernate.test.Bar bar left join bar.baz.fooArray foo where bar.string = foo.string" ); + parse( "select foo from bar in class org.hibernate.test.Bar inner join bar.baz as baz inner join baz.fooSet as foo" ); + parse( "select foo from bar in class org.hibernate.test.Bar inner join bar.baz.fooSet as foo" ); + parse( "select foo from bar in class org.hibernate.test.Bar, bar.baz as baz, baz.fooSet as foo" ); + parse( "select foo from bar in class org.hibernate.test.Bar, bar.baz.fooSet as foo" ); + parse( "from org.hibernate.test.Bar bar join bar.baz.fooArray foo" ); + parse( "from bar in class org.hibernate.test.Bar, foo in elements( bar.baz.fooArray )" ); + parse( "select one.id, elements(one.manies) from one in class org.hibernate.test.One" ); + parse( "select max( elements(one.manies) ) from one in class org.hibernate.test.One" ); + parse( "select one, elements(one.manies) from one in class org.hibernate.test.One" ); + parse( "select one, max(elements(one.manies)) from one in class org.hibernate.test.One group by one" ); + parse( "select elements(baz.fooArray) from baz in class org.hibernate.test.Baz where baz.id=?" ); + parse( "select elements(baz.fooArray) from baz in class org.hibernate.test.Baz where baz.id=?" ); + parse( "select indices(baz.fooArray) from baz in class org.hibernate.test.Baz where baz.id=?" ); + parse( "select baz, max(elements(baz.timeArray)) from baz in class org.hibernate.test.Baz group by baz" ); + parse( "select baz, baz.stringSet.size, count(distinct elements(baz.stringSet)), max(elements(baz.stringSet)) from baz in class org.hibernate.test.Baz group by baz" ); + parse( "select max( elements(baz.timeArray) ) from baz in class org.hibernate.test.Baz where baz.id=?" ); + parse( "select max(elements(baz.stringSet)) from baz in class org.hibernate.test.Baz where baz.id=?" ); + parse( "select size(baz.stringSet) from baz in class org.hibernate.test.Baz where baz.id=?" ); + parse( "from org.hibernate.test.Foo foo where foo.component.glarch.id is not null" ); + parse( "from baz in class org.hibernate.test.Baz" ); + parse( "select elements(baz.stringArray) from baz in class org.hibernate.test.Baz" ); + parse( "from foo in class org.hibernate.test.Foo" ); + parse( "select elements(baz.stringList) from baz in class org.hibernate.test.Baz" ); + parse( "select count(*) from org.hibernate.test.Bar" ); + parse( "select count(*) from b in class org.hibernate.test.Bar" ); + parse( "from g in class org.hibernate.test.Glarch" ); + parse( "select baz, baz from baz in class org.hibernate.test.Baz" ); + parse( "select baz from baz in class org.hibernate.test.Baz order by baz" ); + parse( "from bar in class org.hibernate.test.Bar" ); + parse( "from g in class org.hibernate.test.Glarch" ); + parse( "from f in class org.hibernate.test.Foo" ); + parse( "from o in class org.hibernate.test.One" ); + parse( "from q in class org.hibernate.test.Qux" ); + parse( "select foo from foo in class org.hibernate.test.Foo where foo.string='foo bar'" ); + parse( "from foo in class org.hibernate.test.Foo order by foo.string, foo.date" ); + parse( "from foo in class org.hibernate.test.Foo where foo.class='B'" ); + parse( "from foo in class org.hibernate.test.Foo where foo.class=Bar" ); + parse( "select bar from bar in class org.hibernate.test.Bar, foo in class org.hibernate.test.Foo where bar.string = foo.string and not bar=foo" ); + parse( "from foo in class org.hibernate.test.Foo where foo.string='foo bar'" ); + parse( "select foo from foo in class org.hibernate.test.Foo" ); + parse( "from bar in class org.hibernate.test.Bar where bar.barString='bar bar'" ); + parse( "from t in class org.hibernate.test.Trivial" ); + parse( "from foo in class org.hibernate.test.Foo where foo.date = ?" ); + parse( "from o in class org.hibernate.test.MoreStuff" ); + parse( "from o in class org.hibernate.test.Many" ); + parse( "from o in class org.hibernate.test.Fee" ); + parse( "from o in class org.hibernate.test.Qux" ); + parse( "from o in class org.hibernate.test.Y" ); + parse( "from o in class org.hibernate.test.Fumm" ); + parse( "from o in class org.hibernate.test.X" ); + parse( "from o in class org.hibernate.test.Simple" ); + parse( "from o in class org.hibernate.test.Location" ); + parse( "from o in class org.hibernate.test.Holder" ); + parse( "from o in class org.hibernate.test.Part" ); + parse( "from o in class org.hibernate.test.Baz" ); + parse( "from o in class org.hibernate.test.Vetoer" ); + parse( "from o in class org.hibernate.test.Sortable" ); + parse( "from o in class org.hibernate.test.Contained" ); + parse( "from o in class org.hibernate.test.Stuff" ); + parse( "from o in class org.hibernate.test.Immutable" ); + parse( "from o in class org.hibernate.test.Container" ); + parse( "from o in class org.hibernate.test.X$XX" ); + parse( "from o in class org.hibernate.test.One" ); + parse( "from o in class org.hibernate.test.Foo" ); + parse( "from o in class org.hibernate.test.Fo" ); + parse( "from o in class org.hibernate.test.Glarch" ); + parse( "from o in class org.hibernate.test.Fum" ); + parse( "from q in class org.hibernate.test.Qux where q.stuff is null" ); + parse( "from q in class org.hibernate.test.Qux where q.stuff=?" ); + parse( "from q in class org.hibernate.test.Qux" ); + parse( "from g in class org.hibernate.test.Glarch where g.version=2" ); + parse( "from g in class org.hibernate.test.Glarch where g.next is not null" ); + parse( "from g in class org.hibernate.test.Glarch order by g.order asc" ); + parse( "from foo in class org.hibernate.test.Foo order by foo.string asc" ); + parse( "select parent, child from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child" ); + parse( "select count(distinct child.id), count(distinct parent.id) from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child" ); + parse( "select child.id, parent.id, child.long from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child" ); + parse( "select child.id, parent.id, child.long, child, parent.foo from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child" ); + parse( "select parent, child from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child and parent.string='a string'" ); + parse( "from fee in class org.hibernate.test.Fee" ); + parse( "from org.hibernate.test.Foo foo where foo.custom.s1 = 'one'" ); + parse( "from im in class org.hibernate.test.Immutable where im = ?" ); + parse( "from foo in class org.hibernate.test.Foo" ); + parse( "from foo in class org.hibernate.test.Foo where foo.char='X'" ); + parse( "select elements(baz.stringArray) from baz in class org.hibernate.test.Baz" ); + parse( "select distinct elements(baz.stringArray) from baz in class org.hibernate.test.Baz" ); + parse( "select elements(baz.fooArray) from baz in class org.hibernate.test.Baz" ); + parse( "from foo in class org.hibernate.test.Fo" ); + parse( "from foo in class org.hibernate.test.Foo where foo.dependent.qux.foo.string = 'foo2'" ); + parse( "from org.hibernate.test.Bar bar where bar.object.id = ? and bar.object.class = ?" ); + parse( "select one from org.hibernate.test.One one, org.hibernate.test.Bar bar where bar.object.id = one.id and bar.object.class = 'O'" ); + parse( "from l in class org.hibernate.test.Location where l.countryCode = 'AU' and l.description='foo bar'" ); + parse( "from org.hibernate.test.Bar bar" ); + parse( "From org.hibernate.test.Bar bar" ); + parse( "From org.hibernate.test.Foo foo" ); + parse( "from o in class org.hibernate.test.Baz" ); + parse( "from o in class org.hibernate.test.Foo" ); + parse( "from f in class org.hibernate.test.Foo" ); + parse( "select fum.id from fum in class org.hibernate.test.Fum where not fum.fum='FRIEND'" ); + parse( "select fum.id from fum in class org.hibernate.test.Fum where not fum.fum='FRIEND'" ); + parse( "from fum in class org.hibernate.test.Fum where not fum.fum='FRIEND'" ); + parse( "from fo in class org.hibernate.test.Fo where fo.id.string like 'an instance of fo'" ); + parse( "from org.hibernate.test.Inner" ); + parse( "from org.hibernate.test.Outer o where o.id.detailId = ?" ); + parse( "from org.hibernate.test.Outer o where o.id.master.id.sup.dudu is not null" ); + parse( "from org.hibernate.test.Outer o where o.id.master.id.sup.id.akey is not null" ); + parse( "select o.id.master.id.sup.dudu from org.hibernate.test.Outer o where o.id.master.id.sup.dudu is not null" ); + parse( "select o.id.master.id.sup.id.akey from org.hibernate.test.Outer o where o.id.master.id.sup.id.akey is not null" ); + parse( "from org.hibernate.test.Outer o where o.id.master.bla = ''" ); + parse( "from org.hibernate.test.Outer o where o.id.master.id.one = ''" ); + parse( "from org.hibernate.test.Inner inn where inn.id.bkey is not null and inn.backOut.id.master.id.sup.id.akey > 'a'" ); + parse( "from org.hibernate.test.Outer as o left join o.id.master m left join m.id.sup where o.bubu is not null" ); + parse( "from org.hibernate.test.Outer as o left join o.id.master.id.sup s where o.bubu is not null" ); + parse( "from org.hibernate.test.Outer as o left join o.id.master m left join o.id.master.id.sup s where o.bubu is not null" ); + parse( "select fum1.fo from fum1 in class org.hibernate.test.Fum where fum1.fo.fum is not null" ); + parse( "from fum1 in class org.hibernate.test.Fum where fum1.fo.fum is not null order by fum1.fo.fum" ); + parse( "select elements(fum1.friends) from fum1 in class org.hibernate.test.Fum" ); + parse( "from fum1 in class org.hibernate.test.Fum, fr in elements( fum1.friends )" ); + parse( "select new Jay(eye) from org.hibernate.test.Eye eye" ); + parse( "from org.hibernate.test.Category cat where cat.name='new foo'" ); + parse( "from org.hibernate.test.Category cat where cat.name='new sub'" ); + parse( "from org.hibernate.test.Up up order by up.id2 asc" ); + parse( "from org.hibernate.test.Down down" ); + parse( "from org.hibernate.test.Up up" ); + parse( "from m in class org.hibernate.test.Master" ); + parse( "from s in class org.hibernate.test.Several" ); + parse( "from s in class org.hibernate.test.Single" ); + parse( "\n" + + " from d in class \n" + + " org.hibernate.test.Detail\n" + + " " ); + parse( "from c in class org.hibernate.test.Category where c.name = org.hibernate.test.Category.ROOT_CATEGORY" ); + parse( "select c from c in class org.hibernate.test.Container, s in class org.hibernate.test.Simple where c.oneToMany[2] = s" ); + parse( "select c from c in class org.hibernate.test.Container, s in class org.hibernate.test.Simple where c.manyToMany[2] = s" ); + parse( "select c from c in class org.hibernate.test.Container, s in class org.hibernate.test.Simple where s = c.oneToMany[2]" ); + parse( "select c from c in class org.hibernate.test.Container, s in class org.hibernate.test.Simple where s = c.manyToMany[2]" ); + parse( "select c from c in class org.hibernate.test.Container where c.oneToMany[0].name = 's'" ); + parse( "select c from c in class org.hibernate.test.Container where c.manyToMany[0].name = 's'" ); + parse( "select c from c in class org.hibernate.test.Container where 's' = c.oneToMany[2 - 2].name" ); + parse( "select c from c in class org.hibernate.test.Container where 's' = c.manyToMany[(3+1)/4-1].name" ); + parse( "select c from c in class org.hibernate.test.Container where c.manyToMany[ maxindex(c.manyToMany) ].count = 2" ); + parse( "select c from c in class org.hibernate.test.Container where c.oneToMany[ c.manyToMany[0].count ].name = 's'" ); + parse( "select c from org.hibernate.test.Container c where c.manyToMany[ c.oneToMany[0].count ].name = 's'" ); + parse( "select count(comp.name) from org.hibernate.test.Container c join c.components comp" ); + parse( "from org.hibernate.test.Parent p left join fetch p.child" ); + parse( "from org.hibernate.test.Parent p join p.child c where c.x > 0" ); + parse( "from org.hibernate.test.Child c join c.parent p where p.x > 0" ); + parse( "from org.hibernate.test.Child" ); + parse( "from org.hibernate.test.MoreStuff" ); + parse( "from org.hibernate.test.Many" ); + parse( "from org.hibernate.test.Fee" ); + parse( "from org.hibernate.test.Qux" ); + parse( "from org.hibernate.test.Fumm" ); + parse( "from org.hibernate.test.Parent" ); + parse( "from org.hibernate.test.Simple" ); + parse( "from org.hibernate.test.Holder" ); + parse( "from org.hibernate.test.Part" ); + parse( "from org.hibernate.test.Baz" ); + parse( "from org.hibernate.test.Vetoer" ); + parse( "from org.hibernate.test.Sortable" ); + parse( "from org.hibernate.test.Contained" ); + parse( "from org.hibernate.test.Circular" ); + parse( "from org.hibernate.test.Stuff" ); + parse( "from org.hibernate.test.Immutable" ); + parse( "from org.hibernate.test.Container" ); + parse( "from org.hibernate.test.One" ); + parse( "from org.hibernate.test.Foo" ); + parse( "from org.hibernate.test.Fo" ); + parse( "from org.hibernate.test.Glarch" ); + parse( "from org.hibernate.test.Fum" ); + parse( "from org.hibernate.test.Glarch g" ); + parse( "from org.hibernate.test.Part" ); + parse( "from org.hibernate.test.Baz baz join baz.parts" ); + parse( "from c in class org.hibernate.test.Child where c.parent.count=66" ); + parse( "from org.hibernate.test.Parent p join p.child c where p.count=66" ); + parse( "select c, c.parent from c in class org.hibernate.test.Child order by c.parent.count" ); + parse( "select c, c.parent from c in class org.hibernate.test.Child where c.parent.count=66 order by c.parent.count" ); + parse( "select c, c.parent, c.parent.count from c in class org.hibernate.test.Child order by c.parent.count" ); + parse( "FROM p IN CLASS org.hibernate.test.Parent WHERE p.count = ?" ); + parse( "select count(*) from org.hibernate.test.Container as c join c.components as ce join ce.simple as s where ce.name='foo'" ); + parse( "select c, s from org.hibernate.test.Container as c join c.components as ce join ce.simple as s where ce.name='foo'" ); + parse( "from s in class org.hibernate.test.Simple" ); + parse( "from m in class org.hibernate.test.Many" ); + parse( "from o in class org.hibernate.test.One" ); + parse( "from c in class org.hibernate.test.Container" ); + parse( "from o in class org.hibernate.test.Child" ); + parse( "from o in class org.hibernate.test.MoreStuff" ); + parse( "from o in class org.hibernate.test.Many" ); + parse( "from o in class org.hibernate.test.Fee" ); + parse( "from o in class org.hibernate.test.Qux" ); + parse( "from o in class org.hibernate.test.Fumm" ); + parse( "from o in class org.hibernate.test.Parent" ); + parse( "from o in class org.hibernate.test.Simple" ); + parse( "from o in class org.hibernate.test.Holder" ); + parse( "from o in class org.hibernate.test.Part" ); + parse( "from o in class org.hibernate.test.Baz" ); + parse( "from o in class org.hibernate.test.Vetoer" ); + parse( "from o in class org.hibernate.test.Sortable" ); + parse( "from o in class org.hibernate.test.Contained" ); + parse( "from o in class org.hibernate.test.Circular" ); + parse( "from o in class org.hibernate.test.Stuff" ); + parse( "from o in class org.hibernate.test.Immutable" ); + parse( "from o in class org.hibernate.test.Container" ); + parse( "from o in class org.hibernate.test.One" ); + parse( "from o in class org.hibernate.test.Foo" ); + parse( "from o in class org.hibernate.test.Fo" ); + parse( "from o in class org.hibernate.test.Glarch" ); + parse( "from o in class org.hibernate.test.Fum" ); + parse( "from c in class org.hibernate.test.C2 where 1=1 or 1=1" ); + parse( "from b in class org.hibernate.test.B" ); + parse( "from a in class org.hibernate.test.A" ); + parse( "from b in class org.hibernate.test.B" ); + parse( "from org.hibernate.test.E e join e.reverse as b where b.count=1" ); + parse( "from org.hibernate.test.E e join e.as as b where b.count=1" ); + parse( "from org.hibernate.test.B" ); + parse( "from org.hibernate.test.C1" ); + parse( "from org.hibernate.test.C2" ); + parse( "from org.hibernate.test.E e, org.hibernate.test.A a where e.reverse = a.forward and a = ?" ); + parse( "from org.hibernate.test.E e join fetch e.reverse" ); + parse( "from org.hibernate.test.E e" ); + parse( "select max(s.count) from s in class org.hibernate.test.Simple" ); + parse( "select new org.hibernate.test.S(s.count, s.address) from s in class org.hibernate.test.Simple" ); + parse( "select max(s.count) from s in class org.hibernate.test.Simple" ); + parse( "select count(*) from s in class org.hibernate.test.Simple" ); + parse( "from s in class org.hibernate.test.Simple where s.name=:name and s.count=:count" ); + parse( "from s in class org.hibernate.test.Simple where s.name in (:several0_, :several1_)" ); + parse( "from s in class org.hibernate.test.Simple where s.name in (:stuff0_, :stuff1_)" ); + parse( "from org.hibernate.test.Simple s where s.name=?" ); + parse( "from org.hibernate.test.Simple s where s.name=:name" ); + parse( "from s in class org.hibernate.test.Simple where upper( s.name ) ='SIMPLE 1'" ); + parse( "from s in class org.hibernate.test.Simple where not( upper( s.name ) ='yada' or 1=2 or 'foo'='bar' or not('foo'='foo') or 'foo' like 'bar' )" ); + parse( "from s in class org.hibernate.test.Simple where lower( s.name || ' foo' ) ='simple 1 foo'" ); + parse( "from s in class org.hibernate.test.Simple where upper( s.other.name ) ='SIMPLE 2'" ); + parse( "from s in class org.hibernate.test.Simple where not ( upper( s.other.name ) ='SIMPLE 2' )" ); + parse( "select distinct s from s in class org.hibernate.test.Simple where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2" ); + parse( "select s from s in class org.hibernate.test.Simple where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2 order by s.other.count" ); + parse( "select sum(s.count) from s in class org.hibernate.test.Simple group by s.count having sum(s.count) > 10" ); + parse( "select s.count from s in class org.hibernate.test.Simple group by s.count having s.count = 12" ); + parse( "select s.id, s.count, count(t), max(t.date) from s in class org.hibernate.test.Simple, t in class org.hibernate.test.Simple where s.count = t.count group by s.id, s.count order by s.count" ); + parse( "from s in class org.hibernate.test.Simple" ); + parse( "from s in class org.hibernate.test.Simple where s.name = ?" ); + parse( "from s in class org.hibernate.test.Simple where s.name = ? and upper(s.name) = ?" ); + parse( "from s in class org.hibernate.test.Simple where s.name = :foo and upper(s.name) = :bar or s.count=:count or s.count=:count + 1" ); + parse( "select s.id from s in class org.hibernate.test.Simple" ); + parse( "select all s, s.other from s in class org.hibernate.test.Simple where s = :s" ); + parse( "from s in class org.hibernate.test.Simple where s.name in (:name_list0_, :name_list1_) and s.count > :count" ); + parse( "from org.hibernate.test.Simple s" ); + parse( "from org.hibernate.test.Simple s" ); + parse( "from org.hibernate.test.Assignable" ); + parse( "from org.hibernate.test.Category" ); + parse( "from org.hibernate.test.Simple" ); + parse( "from org.hibernate.test.A" ); + parse( "from foo in class org.hibernate.test.Foo where foo.string=?" ); + parse( "from foo in class org.hibernate.test.Foo" ); + parse( "from org.hibernate.test.Po po, org.hibernate.test.Lower low where low.mypo = po" ); + parse( "from org.hibernate.test.Po po join po.set as sm where sm.amount > 0" ); + parse( "from org.hibernate.test.Po po join po.top as low where low.foo = 'po'" ); + parse( "from org.hibernate.test.SubMulti sm join sm.children smc where smc.name > 'a'" ); + parse( "select s, ya from org.hibernate.test.Lower s join s.yetanother ya" ); + parse( "from org.hibernate.test.Lower s1 join s1.bag s2" ); + parse( "from org.hibernate.test.Lower s1 left join s1.bag s2" ); + parse( "select s, a from org.hibernate.test.Lower s join s.another a" ); + parse( "select s, a from org.hibernate.test.Lower s left join s.another a" ); + parse( "from org.hibernate.test.Top s, org.hibernate.test.Lower ls" ); + parse( "from org.hibernate.test.Lower ls join ls.set s where s.name > 'a'" ); + parse( "from org.hibernate.test.Po po join po.list sm where sm.name > 'a'" ); + parse( "from org.hibernate.test.Lower ls inner join ls.another s where s.name is not null" ); + parse( "from org.hibernate.test.Lower ls where ls.other.another.name is not null" ); + parse( "from org.hibernate.test.Multi m where m.derived like 'F%'" ); + parse( "from org.hibernate.test.SubMulti m where m.derived like 'F%'" ); + parse( "select s from org.hibernate.test.SubMulti as sm join sm.children as s where s.amount>-1 and s.name is null" ); + parse( "select elements(sm.children) from org.hibernate.test.SubMulti as sm" ); + parse( "select distinct sm from org.hibernate.test.SubMulti as sm join sm.children as s where s.amount>-1 and s.name is null" ); + parse( "select distinct s from s in class org.hibernate.test.SubMulti where s.moreChildren[1].amount < 1.0" ); + parse( "from s in class org.hibernate.test.TrivialClass where s.id = 2" ); + parse( "select s.count from s in class org.hibernate.test.Top" ); + parse( "from s in class org.hibernate.test.Lower where s.another.name='name'" ); + parse( "from s in class org.hibernate.test.Lower where s.yetanother.name='name'" ); + parse( "from s in class org.hibernate.test.Lower where s.yetanother.name='name' and s.yetanother.foo is null" ); + parse( "from s in class org.hibernate.test.Top where s.count=1" ); + parse( "select s.count from s in class org.hibernate.test.Top, ls in class org.hibernate.test.Lower where ls.another=s" ); + parse( "select elements(ls.bag), elements(ls.set) from ls in class org.hibernate.test.Lower" ); + parse( "from s in class org.hibernate.test.Lower" ); + parse( "from s in class org.hibernate.test.Top" ); + parse( "from sm in class org.hibernate.test.SubMulti" ); + parse( "select\n" + + "\n" + + "s from s in class org.hibernate.test.Top where s.count>0" ); + parse( "from m in class org.hibernate.test.Multi where m.count>0 and m.extraProp is not null" ); + parse( "from m in class org.hibernate.test.Top where m.count>0 and m.name is not null" ); + parse( "from m in class org.hibernate.test.Lower where m.other is not null" ); + parse( "from m in class org.hibernate.test.Multi where m.other.id = 1" ); + parse( "from m in class org.hibernate.test.SubMulti where m.amount > 0.0" ); + parse( "from m in class org.hibernate.test.Multi" ); + parse( "from m in class org.hibernate.test.Multi where m.class = SubMulti" ); + parse( "from m in class org.hibernate.test.Top where m.class = Multi" ); + parse( "from s in class org.hibernate.test.Top" ); + parse( "from ls in class org.hibernate.test.Lower" ); + parse( "from ls in class org.hibernate.test.Lower, s in elements(ls.bag) where s.id is not null" ); + parse( "from ls in class org.hibernate.test.Lower, s in elements(ls.set) where s.id is not null" ); + parse( "from o in class org.hibernate.test.Top" ); + parse( "from o in class org.hibernate.test.Po" ); + parse( "from ChildMap cm where cm.parent is not null" ); + parse( "from ParentMap cm where cm.child is not null" ); + parse( "from org.hibernate.test.Componentizable" ); + } + + public void testUnnamedParameter() throws Exception { + parse( "select foo, bar from org.hibernate.test.Foo foo left outer join foo.foo bar where foo = ?" ); // Added '?' as a valid expression. + } + + public void testInElements() throws Exception { + parse( "from bar in class org.hibernate.test.Bar, foo in elements(bar.baz.fooArray)" ); // Added collectionExpr as a valid 'in' clause. + } + + public void testDotElements() throws Exception { + parse( "select distinct foo from baz in class org.hibernate.test.Baz, foo in elements(baz.fooArray)" ); + parse( "select foo from baz in class org.hibernate.test.Baz, foo in elements(baz.fooSet)" ); + parse( "select foo from baz in class org.hibernate.test.Baz, foo in elements(baz.fooArray)" ); + parse( "from org.hibernate.test.Baz baz where 'b' in elements(baz.collectionComponent.nested.foos) and 1.0 in elements(baz.collectionComponent.nested.floats)" ); + } + + public void testSelectAll() throws Exception { + parse( "select all s, s.other from s in class org.hibernate.test.Simple where s = :s" ); + } + + public void testNot() throws Exception { + // Cover NOT optimization in HqlParser + parse( "from eg.Cat cat where not ( cat.kittens.size < 1 )" ); + parse( "from eg.Cat cat where not ( cat.kittens.size > 1 )" ); + parse( "from eg.Cat cat where not ( cat.kittens.size >= 1 )" ); + parse( "from eg.Cat cat where not ( cat.kittens.size <= 1 )" ); + parse( "from eg.DomesticCat cat where not ( cat.name between 'A' and 'B' ) " ); + parse( "from eg.DomesticCat cat where not ( cat.name not between 'A' and 'B' ) " ); + parse( "from eg.Cat cat where not ( not cat.kittens.size <= 1 )" ); + parse( "from eg.Cat cat where not not ( not cat.kittens.size <= 1 )" ); + } + + public void testOtherSyntax() throws Exception { + parse( "select bar from org.hibernate.test.Bar bar order by ((bar.x - :valueX)*(bar.x - :valueX))" ); + parse( "from bar in class org.hibernate.test.Bar, foo in elements(bar.baz.fooSet)" ); + parse( "from one in class org.hibernate.test.One, many in elements(one.manies) where one.id = 1 and many.id = 1" ); + parse( "from org.hibernate.test.Inner _inner join _inner.middles middle" ); + parse( "FROM m IN CLASS org.hibernate.test.Master WHERE NOT EXISTS ( FROM d IN elements(m.details) WHERE NOT d.i=5 )" ); + parse( "FROM m IN CLASS org.hibernate.test.Master WHERE NOT 5 IN ( SELECT d.i FROM d IN elements(m.details) )" ); + parse( "SELECT m FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" ); + parse( "SELECT m FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" ); + parse( "SELECT m.id FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" ); + // I'm not sure about these... [jsd] +// parse("select bar.string, foo.string from bar in class org.hibernate.test.Bar inner join bar.baz as baz inner join elements(baz.fooSet) as foo where baz.name = 'name'"); +// parse("select bar.string, foo.string from bar in class org.hibernate.test.Bar, bar.baz as baz, elements(baz.fooSet) as foo where baz.name = 'name'"); +// parse("select count(*) where this.amount>-1 and this.name is null"); +// parse("from sm in class org.hibernate.test.SubMulti where exists sm.children.elements"); + } + + public void testEjbqlExtensions() throws Exception { + parse( "select object(a) from Animal a where a.mother member of a.offspring" ); + parse( "select object(a) from Animal a where a.mother member a.offspring" ); //no member of + parse( "select object(a) from Animal a where a.offspring is empty" ); + } + + public void testEmptyFilter() throws Exception { + parseFilter( "" ); // Blank is a legitimate filter. + } + + public void testOrderByFilter() throws Exception { + parseFilter( "order by this.id" ); + } + + public void testRestrictionFilter() throws Exception { + parseFilter( "where this.name = ?" ); + } + + public void testNoFrom() throws Exception { + System.out.println( "***** This test ensures that an error is detected ERROR MESSAGES ARE OKAY! *****" ); + HqlParser parser = HqlParser.getInstance( "" ); + parser.setFilter( false ); + parser.statement(); + assertEquals( "Parser allowed no FROM clause!", 1, parser.getParseErrorHandler().getErrorCount() ); + System.out.println( "***** END OF ERROR TEST *****" ); + } + + public void testHB1042() throws Exception { + parse( "select x from fmc_web.pool.Pool x left join x.containers c0 where (upper(x.name) = upper(':') and c0.id = 1)" ); + } + + public void testKeywordInPath() throws Exception { + // The keyword 'order' used as a property name. + parse( "from Customer c where c.order.status = 'argh'" ); + // The keyword 'order' and 'count' used as a property name. + parse( "from Customer c where c.order.count > 3" ); + // The keywords 'where', 'order' and 'count' used as a property name. + parse( "select c.where from Customer c where c.order.count > 3" ); + parse( "from Interval i where i.end <:end" ); + parse( "from Letter l where l.case = :case" ); + } + + public void testPathologicalKeywordAsIdentifier() throws Exception { + // Super evil badness... a legitimate keyword! + parse( "from Order order" ); + //parse( "from Order order join order.group" ); + parse( "from X x order by x.group.by.from" ); + parse( "from Order x order by x.order.group.by.from" ); + parse( "select order.id from Order order" ); + parse( "select order from Order order" ); + parse( "from Order order where order.group.by.from is not null" ); + parse( "from Order order order by order.group.by.from" ); + // Okay, now this is getting silly. + parse( "from Group as group group by group.by.from" ); + } + + public void testHHH354() throws Exception { + parse( "from Foo f where f.full = 'yep'"); + } + + public void testWhereAsIdentifier() throws Exception { + // 'where' as a package name + parse( "from where.Order" ); + } + + public void testEjbqlKeywordsAsIdentifier() throws Exception { + parse( "from org.hibernate.test.Bar bar where bar.object.id = ? and bar.object.class = ?" ); + } + + public void testConstructorIn() throws Exception { + parse( "from org.hibernate.test.Bar bar where (b.x, b.y, b.z) in (select foo, bar, baz from org.hibernate.test.Foo)" ); + } + + public void testMultiByteCharacters() throws Exception { + parse ("from User user where user.name like '%nn\u4e2dnn%'"); + // Test for HHH-558 + parse ("from User user where user.\u432d like '%\u4e2d%'"); + parse ("from \u432d \u432d where \u432d.name like '%fred%'"); + } + + public void testHHH719() throws Exception { + // Some SQLs have function names with package qualifiers. + parse("from Foo f order by com.fooco.SpecialFunction(f.id)"); + } + + public void testHHH1107() throws Exception { + parse("from Animal where zoo.address.street = '123 Bogus St.'"); + } + + + public void testHHH1247() throws Exception { + parse("select distinct user.party from com.itf.iceclaims.domain.party.user.UserImpl user inner join user.party.$RelatedWorkgroups relatedWorkgroups where relatedWorkgroups.workgroup.id = :workgroup and relatedWorkgroups.effectiveTime.start <= :datesnow and relatedWorkgroups.effectiveTime.end > :dateenow "); + } + public void testLineAndColumnNumber() throws Exception { + AST ast = doParse("from Foo f\nwhere f.name = 'fred'",false); + // Find some of the nodes and check line and column values. + ASTIterator iter = new ASTIterator(ast); + boolean foundFoo = false; + boolean foundName = false; + while (iter.hasNext()) + { + AST n = iter.nextNode(); + if ("Foo".equals(n.getText())) + { + if (foundFoo) + fail("Already found 'Foo'!"); + foundFoo = true; + Node node = (Node)n; + assertEquals(1,node.getLine()); + assertEquals(6,node.getColumn()); + } + else if ("name".equals(n.getText())) + { + if (foundName) + fail("Already found 'name'!"); + foundName = true; + Node node = (Node)n; + assertEquals(2,node.getLine()); + assertEquals(9,node.getColumn()); + } + } + assertTrue(foundFoo); + assertTrue(foundName); + } + + private void parseFilter(String input) throws TokenStreamException, RecognitionException { + doParse( input, true ); + } + + private void parse(String input) throws RecognitionException, TokenStreamException { + doParse( input, false ); + } + + private AST doParse(String input, boolean filter) throws RecognitionException, TokenStreamException { + System.out.println( "input: ->" + ASTPrinter.escapeMultibyteChars(input) + "<-" ); + HqlParser parser = HqlParser.getInstance( input ); + parser.setFilter( filter ); + parser.statement(); + AST ast = parser.getAST(); + System.out.println( "AST : " + ast.toStringTree() + "" ); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + parser.showAst( ast, new PrintStream( baos ) ); + System.out.println( baos.toString() ); + assertEquals( "At least one error occurred during parsing!", 0, parser.getParseErrorHandler().getErrorCount() ); + return ast; + } + + public static Test suite() { + return new TestSuite( HqlParserTest.class ); + } +} diff --git a/test/org/hibernate/test/hql/Human.java b/test/org/hibernate/test/hql/Human.java new file mode 100755 index 0000000000..1dda24c56c --- /dev/null +++ b/test/org/hibernate/test/hql/Human.java @@ -0,0 +1,126 @@ +//$Id$ +package org.hibernate.test.hql; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * @author Gavin King + */ +public class Human extends Mammal { + private Name name; + private String nickName; + private Collection friends; + private Collection pets; + private Map family; + private double height; + + private BigInteger bigIntegerValue; + private BigDecimal bigDecimalValue; + private int intValue; + private float floatValue; + + private Set nickNames; + private Map addresses; + + public Collection getFriends() { + return friends; + } + + public void setFriends(Collection friends) { + this.friends = friends; + } + + public Collection getPets() { + return pets; + } + + public void setPets(Collection pets) { + this.pets = pets; + } + + public Name getName() { + return name; + } + + public void setName(Name name) { + this.name = name; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public double getHeight() { + return height; + } + public void setHeight(double height) { + this.height = height; + } + + public Map getFamily() { + return family; + } + + + public void setFamily(Map family) { + this.family = family; + } + + public Set getNickNames() { + return nickNames; + } + + public void setNickNames(Set nickNames) { + this.nickNames = nickNames; + } + + public Map getAddresses() { + return addresses; + } + + public void setAddresses(Map addresses) { + this.addresses = addresses; + } + + public BigDecimal getBigDecimalValue() { + return bigDecimalValue; + } + + public void setBigDecimalValue(BigDecimal bigDecimalValue) { + this.bigDecimalValue = bigDecimalValue; + } + + public BigInteger getBigIntegerValue() { + return bigIntegerValue; + } + + public void setBigIntegerValue(BigInteger bigIntegerValue) { + this.bigIntegerValue = bigIntegerValue; + } + + public float getFloatValue() { + return floatValue; + } + + public void setFloatValue(float floatValue) { + this.floatValue = floatValue; + } + + public int getIntValue() { + return intValue; + } + + public void setIntValue(int intValue) { + this.intValue = intValue; + } + + +} diff --git a/test/org/hibernate/test/hql/IntegerVersioned.java b/test/org/hibernate/test/hql/IntegerVersioned.java new file mode 100644 index 0000000000..979eccfd7d --- /dev/null +++ b/test/org/hibernate/test/hql/IntegerVersioned.java @@ -0,0 +1,36 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of IntegerVersioned. + * + * @author Steve Ebersole + */ +public class IntegerVersioned { + private Long id; + private int version = -1; + private String name; + + public IntegerVersioned() { + } + + public IntegerVersioned(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public int getVersion() { + return version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/hql/Joiner.java b/test/org/hibernate/test/hql/Joiner.java new file mode 100644 index 0000000000..55190c7e89 --- /dev/null +++ b/test/org/hibernate/test/hql/Joiner.java @@ -0,0 +1,37 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of Joiner. + * + * @author Steve Ebersole + */ +public class Joiner { + private Long id; + private String name; + private String joinedName; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getJoinedName() { + return joinedName; + } + + public void setJoinedName(String joinedName) { + this.joinedName = joinedName; + } +} diff --git a/test/org/hibernate/test/hql/KeyManyToOneEntity.hbm.xml b/test/org/hibernate/test/hql/KeyManyToOneEntity.hbm.xml new file mode 100644 index 0000000000..062f565a94 --- /dev/null +++ b/test/org/hibernate/test/hql/KeyManyToOneEntity.hbm.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/hql/KeyManyToOneEntity.java b/test/org/hibernate/test/hql/KeyManyToOneEntity.java new file mode 100644 index 0000000000..cee4306ed9 --- /dev/null +++ b/test/org/hibernate/test/hql/KeyManyToOneEntity.java @@ -0,0 +1,52 @@ +// $Id$ +package org.hibernate.test.hql; + +import java.io.Serializable; + +/** + * Implementation of KeyManyToOneEntity. + * + * @author Steve Ebersole + */ +public class KeyManyToOneEntity { + private Id id; + private String name; + + public KeyManyToOneEntity(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static class Id implements Serializable { + private KeyManyToOneKeyEntity key1; + private String key2; + + public Id(KeyManyToOneKeyEntity key1, String key2) { + this.key1 = key1; + this.key2 = key2; + } + + public KeyManyToOneKeyEntity getKey1() { + return key1; + } + + public void setKey1(KeyManyToOneKeyEntity key1) { + this.key1 = key1; + } + + public String getKey2() { + return key2; + } + + public void setKey2(String key2) { + this.key2 = key2; + } + } +} diff --git a/test/org/hibernate/test/hql/KeyManyToOneKeyEntity.java b/test/org/hibernate/test/hql/KeyManyToOneKeyEntity.java new file mode 100644 index 0000000000..3c80becff9 --- /dev/null +++ b/test/org/hibernate/test/hql/KeyManyToOneKeyEntity.java @@ -0,0 +1,24 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of KeyManyToOneKeyEntity. + * + * @author Steve Ebersole + */ +public class KeyManyToOneKeyEntity { + private Long id; + private String name; + + public KeyManyToOneKeyEntity(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/hql/Lizard.java b/test/org/hibernate/test/hql/Lizard.java new file mode 100644 index 0000000000..81c3e6b0bd --- /dev/null +++ b/test/org/hibernate/test/hql/Lizard.java @@ -0,0 +1,9 @@ +//$Id$ +package org.hibernate.test.hql; + +/** + * @author Gavin King + */ +public class Lizard extends Reptile { + +} diff --git a/test/org/hibernate/test/hql/Mammal.java b/test/org/hibernate/test/hql/Mammal.java new file mode 100644 index 0000000000..62ab0a4ee5 --- /dev/null +++ b/test/org/hibernate/test/hql/Mammal.java @@ -0,0 +1,30 @@ +//$Id$ +package org.hibernate.test.hql; + +import java.util.Date; + +/** + * @author Gavin King + */ +public class Mammal extends Animal { + private boolean pregnant; + private Date birthdate; + + public boolean isPregnant() { + return pregnant; + } + + public void setPregnant(boolean pregnant) { + this.pregnant = pregnant; + } + + public Date getBirthdate() { + return birthdate; + } + + + public void setBirthdate(Date birthdate) { + this.birthdate = birthdate; + } + +} diff --git a/test/org/hibernate/test/hql/MoreCrazyIdFieldNameStuffEntity.java b/test/org/hibernate/test/hql/MoreCrazyIdFieldNameStuffEntity.java new file mode 100644 index 0000000000..158f73718a --- /dev/null +++ b/test/org/hibernate/test/hql/MoreCrazyIdFieldNameStuffEntity.java @@ -0,0 +1,44 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of MoreCrazyIdFieldNameStuffEntity. + * + * @author Steve Ebersole + */ +public class MoreCrazyIdFieldNameStuffEntity { + private Long moreCrazyIdFieldNameStuffEntity; + private HeresAnotherCrazyIdFieldName heresAnotherCrazyIdFieldName; // silly ain't it ;) + private String name; + + public MoreCrazyIdFieldNameStuffEntity() { + } + + public MoreCrazyIdFieldNameStuffEntity(String name) { + this.name = name; + } + + public Long getMoreCrazyIdFieldNameStuffEntity() { + return moreCrazyIdFieldNameStuffEntity; + } + + public void setMoreCrazyIdFieldNameStuffEntity(Long moreCrazyIdFieldNameStuffEntity) { + this.moreCrazyIdFieldNameStuffEntity = moreCrazyIdFieldNameStuffEntity; + } + + public HeresAnotherCrazyIdFieldName getHeresAnotherCrazyIdFieldName() { + return heresAnotherCrazyIdFieldName; + } + + public void setHeresAnotherCrazyIdFieldName(HeresAnotherCrazyIdFieldName heresAnotherCrazyIdFieldName) { + this.heresAnotherCrazyIdFieldName = heresAnotherCrazyIdFieldName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/hql/Name.java b/test/org/hibernate/test/hql/Name.java new file mode 100755 index 0000000000..eee06ae6fb --- /dev/null +++ b/test/org/hibernate/test/hql/Name.java @@ -0,0 +1,47 @@ +//$Id$ +package org.hibernate.test.hql; + +/** + * @author Gavin King + */ +public class Name { + private String first; + private Character initial; + private String last; + + protected Name() {} + + public Name(String first, Character initial, String last) { + this.first = first; + this.initial = initial; + this.last = last; + } + + public Name(String first, char initial, String last) { + this( first, new Character( initial ), last ); + } + + public String getFirst() { + return first; + } + + public void setFirst(String first) { + this.first = first; + } + + public Character getInitial() { + return initial; + } + + public void setInitial(Character initial) { + this.initial = initial; + } + + public String getLast() { + return last; + } + + public void setLast(String last) { + this.last = last; + } +} diff --git a/test/org/hibernate/test/hql/PettingZoo.java b/test/org/hibernate/test/hql/PettingZoo.java new file mode 100755 index 0000000000..afe9167fe9 --- /dev/null +++ b/test/org/hibernate/test/hql/PettingZoo.java @@ -0,0 +1,9 @@ +//$Id$ +package org.hibernate.test.hql; + +/** + * @author Gavin King + */ +public class PettingZoo extends Zoo { + +} diff --git a/test/org/hibernate/test/hql/Pickup.java b/test/org/hibernate/test/hql/Pickup.java new file mode 100644 index 0000000000..20a9e9bef8 --- /dev/null +++ b/test/org/hibernate/test/hql/Pickup.java @@ -0,0 +1,10 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of Pickup. + * + * @author Steve Ebersole + */ +public class Pickup extends Truck { +} diff --git a/test/org/hibernate/test/hql/QueryTranslatorTestCase.java b/test/org/hibernate/test/hql/QueryTranslatorTestCase.java new file mode 100644 index 0000000000..60993a8b59 --- /dev/null +++ b/test/org/hibernate/test/hql/QueryTranslatorTestCase.java @@ -0,0 +1,546 @@ +// $Id$ +package org.hibernate.test.hql; + +import java.sql.Connection; +import java.sql.ParameterMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeMap; + +import junit.framework.ComparisonFailure; + +import org.hibernate.EntityMode; +import org.hibernate.MappingException; +import org.hibernate.QueryException; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.classic.Session; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.query.HQLQueryPlan; +import org.hibernate.hql.QueryTranslator; +import org.hibernate.hql.QueryTranslatorFactory; +import org.hibernate.hql.ast.ASTQueryTranslatorFactory; +import org.hibernate.hql.ast.HqlToken; +import org.hibernate.hql.ast.QueryTranslatorImpl; +import org.hibernate.hql.ast.util.ASTPrinter; +import org.hibernate.hql.classic.ClassicQueryTranslatorFactory; +import org.hibernate.type.Type; +import org.hibernate.type.TypeFactory; +import org.hibernate.util.StringHelper; + +/** + * Test case superclass for testing QueryTranslator implementations. + * + * @author josh Dec 6, 2004 8:21:21 AM + */ +public abstract class QueryTranslatorTestCase extends FunctionalTestCase { + + public QueryTranslatorTestCase(String x) { + super( x ); + // Create an instance of HqlToken, so that it will have an entry point outside the package. This + // will stop IDEA's code inspector from suggesting that HqlToken should be package local. + new HqlToken(); + } + + public String[] getMappings() { + return new String[] { + "hql/Animal.hbm.xml", + "hql/EntityWithCrazyCompositeKey.hbm.xml", + "hql/CrazyIdFieldNames.hbm.xml", + "hql/SimpleEntityWithAssociation.hbm.xml", + "hql/ComponentContainer.hbm.xml", + "batchfetch/ProductLine.hbm.xml", + "cid/Customer.hbm.xml", + "cid/Order.hbm.xml", + "cid/LineItem.hbm.xml", + "cid/Product.hbm.xml", + "legacy/Baz.hbm.xml", + "legacy/Category.hbm.xml", + "legacy/Commento.hbm.xml", + "legacy/Container.hbm.xml", + "legacy/Custom.hbm.xml", + "legacy/Eye.hbm.xml", + "legacy/Fee.hbm.xml", + "legacy/FooBar.hbm.xml", + "legacy/Fum.hbm.xml", + "legacy/Glarch.hbm.xml", + "legacy/Holder.hbm.xml", + "legacy/Many.hbm.xml", + "legacy/Marelo.hbm.xml", + "legacy/MasterDetail.hbm.xml", + "legacy/Middle.hbm.xml", + "legacy/Multi.hbm.xml", + "legacy/Nameable.hbm.xml", + "legacy/One.hbm.xml", + "legacy/Qux.hbm.xml", + "legacy/Simple.hbm.xml", + "legacy/SingleSeveral.hbm.xml", + "legacy/WZ.hbm.xml", + "legacy/UpDown.hbm.xml", + "compositeelement/Parent.hbm.xml", + "onetoone/joined/Person.hbm.xml", + "any/Properties.hbm.xml" + }; + } + + public boolean createSchema() { + return false; + } + + public boolean recreateSchemaAfterFailure() { + return false; + } + + public void assertTranslation(String hql) throws QueryException, MappingException { + assertTranslation( hql, null ); + } + + public void assertTranslation(String hql, boolean scalar) throws QueryException, MappingException { + assertTranslation( hql, null, scalar, null ); + } + + protected void assertTranslation(String hql, Map replacements) { + ComparisonFailure cf = null; + try { + assertTranslation( hql, replacements, false, null ); + } + catch ( ComparisonFailure e ) { + e.printStackTrace(); + cf = e; + } + if ("false".equals(System.getProperty("org.hibernate.test.hql.SkipScalarQuery","false"))) { + // Run the scalar translation anyway, even if there was a comparison failure. + assertTranslation( hql, replacements, true, null ); + } + if (cf != null) + throw cf; + } + + protected void runClassicTranslator(String hql) throws Exception { + SessionFactoryImplementor factory = getSessionFactoryImplementor(); + Map replacements = new HashMap(); + QueryTranslator oldQueryTranslator = null; + try { + QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory(); + oldQueryTranslator = classic.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory ); + oldQueryTranslator.compile( replacements, false ); + } + catch ( Exception e ) { + e.printStackTrace(); + throw e; + } + String oldsql = oldQueryTranslator.getSQLString(); + System.out.println( "HQL : " + hql ); + System.out.println( "OLD SQL: " + oldsql ); + } + + protected void assertTranslation(String hql, Map replacements, boolean scalar, String sql) { + SessionFactoryImplementor factory = getSessionFactoryImplementor(); + + // Create an empty replacements map if we don't have one. + if ( replacements == null ) { + replacements = new HashMap(); + } + + // steve -> note that the empty maps here represent the currently enabled filters... + QueryTranslator oldQueryTranslator = null; + Exception oldException = null; + try { + System.out.println("Compiling with classic QueryTranslator..."); + QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory(); + oldQueryTranslator = classic.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory ); + oldQueryTranslator.compile( replacements, scalar ); + } + catch ( QueryException e ) { + oldException = e; + } + catch ( MappingException e ) { + oldException = e; + } + + QueryTranslator newQueryTranslator = null; + Exception newException = null; + try { + System.out.println("Compiling with AST QueryTranslator..."); + newQueryTranslator = createNewQueryTranslator( hql, replacements, scalar ); + } + catch ( QueryException e ) { + newException = e; + } + catch ( MappingException e ) { + newException = e; + } + + // If the old QT threw an exception, the new one should too. + if ( oldException != null ) { +// oldException.printStackTrace(); + assertNotNull( "New query translator did *NOT* throw an exception, the old one did : " + oldException, newException ); + assertEquals( oldException.getMessage(), newException.getMessage() ); + return; // Don't bother with the rest of the assertions. + } + else if ( newException != null ) { + newException.printStackTrace(); + assertNull( "Old query translator did not throw an exception, the new one did", newException ); + } + + // -- check all of the outputs -- + checkSql( oldQueryTranslator, newQueryTranslator, hql, scalar, sql ); + checkQuerySpaces( oldQueryTranslator, newQueryTranslator ); + checkReturnedTypes( oldQueryTranslator, newQueryTranslator ); + checkColumnNames( oldQueryTranslator, newQueryTranslator ); + + } + + protected QueryTranslatorImpl createNewQueryTranslator(String hql, Map replacements, boolean scalar) { + SessionFactoryImplementor factory = getSessionFactoryImplementor(); + return createNewQueryTranslator( hql, replacements, scalar, factory ); + } + + private QueryTranslatorImpl createNewQueryTranslator(String hql, Map replacements, boolean scalar, SessionFactoryImplementor factory) { + QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); + QueryTranslatorImpl newQueryTranslator = ( QueryTranslatorImpl ) ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory ); + newQueryTranslator.compile( replacements, scalar ); + return newQueryTranslator; + } + + protected QueryTranslatorImpl createNewQueryTranslator(String hql) { + return createNewQueryTranslator( hql, new HashMap(), false ); + } + + protected QueryTranslatorImpl createNewQueryTranslator(String hql, SessionFactoryImplementor sfimpl) { + return createNewQueryTranslator( hql, new HashMap(), false, sfimpl ); + } + + protected HQLQueryPlan createQueryPlan(String hql, boolean scalar) { + return new HQLQueryPlan( hql, scalar, Collections.EMPTY_MAP, getSessionFactoryImplementor() ); + } + + protected HQLQueryPlan createQueryPlan(String hql) { + return createQueryPlan( hql, false ); + } + + protected SessionFactoryImplementor getSessionFactoryImplementor() { + SessionFactoryImplementor factory = ( SessionFactoryImplementor ) getSessions(); + if ( factory == null ) { + throw new NullPointerException( "Unable to create factory!" ); + } + return factory; + } + + private void checkColumnNames(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) { + // Check the column names. + + String[][] oldColumnNames = oldQueryTranslator.getColumnNames(); + String[][] newColumnNames = newQueryTranslator.getColumnNames(); + /*assertEquals( "Column name array is not the right length!", oldColumnNames.length, newColumnNames.length ); + for ( int i = 0; i < oldColumnNames.length; i++ ) { + assertEquals( "Column name array [" + i + "] is not the right length!", oldColumnNames[i].length, newColumnNames[i].length ); + for ( int j = 0; j < oldColumnNames[i].length; j++ ) { + assertEquals( "Column name [" + i + "," + j + "]", oldColumnNames[i][j], newColumnNames[i][j] ); + } + }*/ + } + + private void checkReturnedTypes(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) { + // Check the returned types for a regression. + Type[] oldReturnTypes = oldQueryTranslator.getReturnTypes(); + Type[] returnTypes = newQueryTranslator.getReturnTypes(); + assertEquals( "Return types array is not the right length!", oldReturnTypes.length, returnTypes.length ); + for ( int i = 0; i < returnTypes.length; i++ ) { + assertNotNull( returnTypes[i] ); + assertNotNull( oldReturnTypes[i] ); + assertEquals( "Returned types did not match!", oldReturnTypes[i].getReturnedClass(), returnTypes[i].getReturnedClass() ); + System.out.println("returnedType[" + i + "] = " + returnTypes[i] + " oldReturnTypes[" + i + "] = " + oldReturnTypes[i]); + } + } + + private void checkQuerySpaces(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) { + // Check the query spaces for a regression. + Set oldQuerySpaces = oldQueryTranslator.getQuerySpaces(); + Set querySpaces = newQueryTranslator.getQuerySpaces(); + assertEquals( "Query spaces is not the right size!", oldQuerySpaces.size(), querySpaces.size() ); + for ( Iterator iterator = oldQuerySpaces.iterator(); iterator.hasNext(); ) { + Object o = iterator.next(); + assertTrue( "New query space does not contain " + o + "!", querySpaces.contains( o ) ); + } + } + + protected Exception compileBadHql(String hql, boolean scalar) { + QueryTranslator newQueryTranslator; + Map replacements = null; + Exception newException = null; + SessionFactoryImplementor factory = getSessionFactoryImplementor(); + try { + QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); + newQueryTranslator = ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory ); + newQueryTranslator.compile( replacements, scalar ); + } + catch ( QueryException e ) { + newException = e; + } + catch ( MappingException e ) { + newException = e; + } + assertNotNull( "Expected exception from compilation of '" + hql + "'!", newException ); + return newException; + } + + private void checkSql(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator, String hql, boolean scalar, String sql) { + + String oldsql = oldQueryTranslator.getSQLString(); + String newsql = newQueryTranslator.getSQLString(); + System.out.println( "HQL : " + ASTPrinter.escapeMultibyteChars(hql) ); + System.out.println( "OLD SQL: " + ASTPrinter.escapeMultibyteChars(oldsql) ); + System.out.println( "NEW SQL: " + ASTPrinter.escapeMultibyteChars(newsql) ); + if ( sql == null ) { + // Check the generated SQL. ASTPrinter.escapeMultibyteChars( + assertSQLEquals( "SQL is not the same as the old SQL (scalar=" + scalar + ")", oldsql, newsql ); + } + else { + assertSQLEquals( "SQL is not the same as the expected SQL (scalar=" + scalar + ")", sql, newsql ); + } + } + + private void assertSQLEquals(String message, String oldsql, String newsql) { + Map oldMap = getTokens(oldsql); + Map newMap = getTokens(newsql); + if ( !oldMap.equals(newMap) ) { + assertEquals(message, oldsql, newsql); + } + + //String oldsqlStripped = stripExtraSpaces( oldsql ); + //String newsqlStripped = stripExtraSpaces( newsql ); + //assertEquals( message, oldsqlStripped, newsqlStripped ); + } + + + private Map getTokens(String sql) { + Map result = new TreeMap(); + if (sql==null) return result; + result.put( "=", new Integer( StringHelper.countUnquoted(sql, '=') ) ); + StringTokenizer tokenizer = new StringTokenizer( sql, "(),= " ); + while ( tokenizer.hasMoreTokens() ) { + String fragment = tokenizer.nextToken(); + /*if ( "on".equals(fragment) ) fragment = "and"; + if ( "join".equals(fragment) || "inner".equals(fragment) ) continue;*/ + Integer count = (Integer) result.get(fragment); + if ( count==null ) { + count = new Integer(1); + } + else { + count = new Integer( count.intValue() + 1 ); + } + result.put(fragment, count); + } + return result; + } + + private String stripExtraSpaces(String string) { + if ( string == null ) { + return null; + } + + StringBuffer buffer = new StringBuffer( string.length() ); + char[] chars = string.toCharArray(); + int length = chars.length; + boolean wasSpace = false; + for ( int i = 0; i < length; i++ ) { + boolean isSpace = chars[i] == ' '; + if ( wasSpace && isSpace ) { + continue; + } + else { + buffer.append( chars[i] ); + } + + wasSpace = isSpace; + } +// StringTokenizer tokenizer = new StringTokenizer( string.trim(), " " ); +// while ( tokenizer.hasMoreTokens() ) { +// final String fragment = tokenizer.nextToken(); +// buffer.append( fragment ); +// buffer.append( " " ); +// } +// + return buffer.toString(); + } + + private void checkSqlByResultSet( + QueryTranslator oldQueryTranslator, + QueryTranslator newQueryTranslator, + Object[] binds + ) { + String oldsql = oldQueryTranslator.getSQLString(); + String newsql = newQueryTranslator.getSQLString(); + + Session session = openSession(); + Connection connection = session.connection(); + + PreparedStatement oldps = null; + PreparedStatement newps = null; + ResultSet oldrs = null; + ResultSet newrs = null; + + try { + try { + oldps = connection.prepareStatement( oldsql ); + } + catch( Throwable t ) { + fail( "Unable to prepare sql generated by old parser : " + t ); + } + try { + newps = connection.prepareStatement( newsql ); + } + catch( Throwable t ) { + fail( "Unable to prepare sql generated by new parser : " + t ); + } + + checkBinds(oldps, newps, binds); + + try { + oldrs = executeQuery( oldps, binds ); + } + catch( Throwable t ) { + fail( "Unable to execute sql generated by old parser : " + t ); + } + + try { + newrs = executeQuery( newps, binds ); + } + catch( Throwable t ) { + fail( "Unable to execute sql generated by new parser : " + t ); + } + + checkResults( oldrs, newrs ); + } + finally { + // make *sure* the sql resources get cleaned up + release(oldrs); + release(newrs); + release(oldps); + release(newps); + release(session); + } + } + + private void checkBinds(PreparedStatement oldps, PreparedStatement newps, Object[] binds) { + // Make sure the binds "feel" ok + try { + ParameterMetaData oldBindMetaData = oldps.getParameterMetaData(); + ParameterMetaData newBindMetaData = newps.getParameterMetaData(); + + assertEquals( "Different bind parameter count", oldBindMetaData.getParameterCount(), newBindMetaData.getParameterCount() ); + assertEquals( "Incorrect number of binds passed in", oldBindMetaData.getParameterCount(), binds == null ? 0 : binds.length ); + + for ( int i = 0, max = oldBindMetaData.getParameterCount(); i < max; i++ ) { + assertEquals( "Different bind types", oldBindMetaData.getParameterType(i), newBindMetaData.getParameterType(i) ); + } + } + catch( Throwable t ) { + fail( "SQLException comparing binds : " + t ); + } + } + + private ResultSet executeQuery(PreparedStatement ps, Object[] binds) throws SQLException { + if ( binds != null ) { + for ( int i = 0, max = binds.length; i < max; i++ ) { + ps.setObject( i, binds[i] ); + } + } + + return ps.executeQuery(); + } + + private void checkResults(ResultSet oldrs, ResultSet newrs) { + ResultSetMetaData oldmeta = null; + ResultSetMetaData newmeta = null; + int colCount = 0; + Type[] types = null; + + // first compare the metadata from the two results + try { + oldmeta = oldrs.getMetaData(); + newmeta = newrs.getMetaData(); + assertEquals( "Different column counts", oldmeta.getColumnCount(), newmeta.getColumnCount() ); + + colCount = oldmeta.getColumnCount(); + types = new Type[colCount]; + + for ( int i = 1, max = colCount; i < max; i++ ) { + assertEquals( "Column names were different", oldmeta.getColumnName(i), newmeta.getColumnName(i) ); + assertEquals( "Column types were different", oldmeta.getColumnType(i), newmeta.getColumnType(i) ); + assertEquals( "Java types were different", oldmeta.getColumnClassName(i), newmeta.getColumnClassName(i) ); + types[i] = TypeFactory.basic( oldmeta.getColumnClassName(i) ); + } + } + catch( Throwable t ) { + fail( "Error comparing result set metadata" ); + } + + // Then compare the actual results + try { + while ( oldrs.next() & newrs.next() ) { + for ( int i = 1; i < colCount; i++ ) { + Object oldval = oldrs.getObject(i); + if ( oldrs.wasNull() ) oldval = null; + Object newval = newrs.getObject(i); + if ( newrs.wasNull() ) newval = null; + checkLogicalEquality( oldval, newval, types[i] ); + } + } + + // for "better reporting" purposes, make sure both result sets are fully exhausted + while ( oldrs.next() ); + while ( newrs.next() ); + + assertEquals( "Different row counts", oldrs.getRow(), newrs.getRow() ); + } + catch( Throwable t ) { + fail( "Error comparing result set structure" ); + } + } + + private void checkLogicalEquality(Object oldval, Object newval, Type type) { + if ( oldval == null && newval == null ) { + // two nulls are logically equivalent here... + return; + } + else { + assertTrue( "Different result values", type.isEqual(oldval, newval, EntityMode.POJO) ); + } + } + + private void release(PreparedStatement ps) { + if ( ps != null ) { + try { + ps.close(); + } + catch( Throwable t ) {} + } + } + + private void release(ResultSet rs) { + if ( rs != null ) { + try { + rs.close(); + } + catch( Throwable t ) {} + } + } + + private void release(Session session) { + if ( session != null ) { + try { + session.close(); + } + catch( Throwable t ) {} + } + } +} diff --git a/test/org/hibernate/test/hql/Reptile.java b/test/org/hibernate/test/hql/Reptile.java new file mode 100644 index 0000000000..064dd1c59c --- /dev/null +++ b/test/org/hibernate/test/hql/Reptile.java @@ -0,0 +1,15 @@ +//$Id$ +package org.hibernate.test.hql; + +/** + * @author Gavin King + */ +public class Reptile extends Animal { + private float bodyTemperature; + public float getBodyTemperature() { + return bodyTemperature; + } + public void setBodyTemperature(float bodyTemperature) { + this.bodyTemperature = bodyTemperature; + } +} diff --git a/test/org/hibernate/test/hql/SUV.java b/test/org/hibernate/test/hql/SUV.java new file mode 100644 index 0000000000..ad2fda1d5a --- /dev/null +++ b/test/org/hibernate/test/hql/SUV.java @@ -0,0 +1,10 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of SUV. + * + * @author Steve Ebersole + */ +public class SUV extends Truck { +} diff --git a/test/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java b/test/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java new file mode 100644 index 0000000000..dbcbe0e6af --- /dev/null +++ b/test/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java @@ -0,0 +1,220 @@ +// $Id$ +package org.hibernate.test.hql; + +import junit.framework.Test; + +import org.hibernate.HibernateException; +import org.hibernate.ScrollMode; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * Tests the new functionality of allowing scrolling of results which + * contain collection fetches. + * + * @author Steve Ebersole + */ +public class ScrollableCollectionFetchingTest extends FunctionalTestCase { + + public ScrollableCollectionFetchingTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ScrollableCollectionFetchingTest.class ); + } + + public String[] getMappings() { + return new String[] { "hql/Animal.hbm.xml" }; + } + + public void testTupleReturnFails() { + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + try { + s.createQuery( "select a, a.weight from Animal a inner join fetch a.offspring" ).scroll(); + fail( "scroll allowed with collection fetch and reurning tuples" ); + } + catch( HibernateException e ) { + // expected result... + } + + txn.commit(); + s.close(); + } + + public void testScrollingJoinFetchesForward() { + if ( ! supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() ) { + return; + } + + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + ScrollableResults results = s + .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) + .setString( "desc", "root%" ) + .scroll( ScrollMode.FORWARD_ONLY ); + + int counter = 0; + while ( results.next() ) { + counter++; + Animal animal = ( Animal ) results.get( 0 ); + checkResult( animal ); + } + assertEquals( "unexpected result count", 2, counter ); + + txn.commit(); + s.close(); + + data.cleanup(); + } + + public void testScrollingJoinFetchesReverse() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + ScrollableResults results = s + .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) + .setString( "desc", "root%" ) + .scroll(); + + results.afterLast(); + + int counter = 0; + while ( results.previous() ) { + counter++; + Animal animal = ( Animal ) results.get( 0 ); + checkResult( animal ); + } + assertEquals( "unexpected result count", 2, counter ); + + txn.commit(); + s.close(); + + data.cleanup(); + } + + public void testScrollingJoinFetchesPositioning() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + ScrollableResults results = s + .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" ) + .setString( "desc", "root%" ) + .scroll(); + + results.first(); + Animal animal = ( Animal ) results.get( 0 ); + assertEquals( "first() did not return expected row", data.root1Id, animal.getId() ); + + results.scroll( 1 ); + animal = ( Animal ) results.get( 0 ); + assertEquals( "scroll(1) did not return expected row", data.root2Id, animal.getId() ); + + results.scroll( -1 ); + animal = ( Animal ) results.get( 0 ); + assertEquals( "scroll(-1) did not return expected row", data.root1Id, animal.getId() ); + + results.setRowNumber( 1 ); + animal = ( Animal ) results.get( 0 ); + assertEquals( "setRowNumber(1) did not return expected row", data.root1Id, animal.getId() ); + + results.setRowNumber( 2 ); + animal = ( Animal ) results.get( 0 ); + assertEquals( "setRowNumber(2) did not return expected row", data.root2Id, animal.getId() ); + + txn.commit(); + s.close(); + + data.cleanup(); + } + + private void checkResult(Animal animal) { + if ( "root-1".equals( animal.getDescription() ) ) { + assertEquals( "root-1 did not contain both children", 2, animal.getOffspring().size() ); + } + else if ( "root-2".equals( animal.getDescription() ) ) { + assertEquals( "root-2 did not contain zero children", 0, animal.getOffspring().size() ); + } + } + + private class TestData { + + private Long root1Id; + private Long root2Id; + + private void prepare() { + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + Animal mother = new Animal(); + mother.setDescription( "root-1" ); + + Animal another = new Animal(); + another.setDescription( "root-2" ); + + Animal son = new Animal(); + son.setDescription( "son"); + + Animal daughter = new Animal(); + daughter.setDescription( "daughter" ); + + Animal grandson = new Animal(); + grandson.setDescription( "grandson" ); + + Animal grandDaughter = new Animal(); + grandDaughter.setDescription( "granddaughter" ); + + son.setMother( mother ); + mother.addOffspring( son ); + + daughter.setMother( mother ); + mother.addOffspring( daughter ); + + grandson.setMother( daughter ); + daughter.addOffspring( grandson ); + + grandDaughter.setMother( daughter ); + daughter.addOffspring( grandDaughter ); + + s.save( mother ); + s.save( another ); + s.save( son ); + s.save( daughter ); + s.save( grandson ); + s.save( grandDaughter ); + + txn.commit(); + s.close(); + + root1Id = mother.getId(); + root2Id = another.getId(); + } + + private void cleanup() { + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + s.createQuery( "delete Animal where description like 'grand%'" ).executeUpdate(); + s.createQuery( "delete Animal where not description like 'root%'" ).executeUpdate(); + s.createQuery( "delete Animal" ).executeUpdate(); + + txn.commit(); + s.close(); + } + } +} diff --git a/test/org/hibernate/test/hql/SimpleAssociatedEntity.java b/test/org/hibernate/test/hql/SimpleAssociatedEntity.java new file mode 100644 index 0000000000..ae79702f55 --- /dev/null +++ b/test/org/hibernate/test/hql/SimpleAssociatedEntity.java @@ -0,0 +1,63 @@ +package org.hibernate.test.hql; + +/** + * @author Steve Ebersole + */ +public class SimpleAssociatedEntity { + private Long id; + private String name; + private SimpleEntityWithAssociation owner; + + public SimpleAssociatedEntity() { + } + + public SimpleAssociatedEntity(String name) { + this.name = name; + } + + public SimpleAssociatedEntity(String name, SimpleEntityWithAssociation owner) { + this( name ); + bindToOwner( owner ); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SimpleEntityWithAssociation getOwner() { + return owner; + } + + public void setOwner(SimpleEntityWithAssociation owner) { + this.owner = owner; + } + + public void bindToOwner(SimpleEntityWithAssociation owner) { + if ( owner != this.owner ) { + unbindFromCurrentOwner(); + if ( owner != null ) { + owner.getAssociatedEntities().add( this ); + } + } + this.owner = owner; + } + + public void unbindFromCurrentOwner() { + if ( this.owner != null ) { + this.owner.getAssociatedEntities().remove( this ); + this.owner = null; + } + } +} diff --git a/test/org/hibernate/test/hql/SimpleEntityWithAssociation.hbm.xml b/test/org/hibernate/test/hql/SimpleEntityWithAssociation.hbm.xml new file mode 100644 index 0000000000..fc05b681e2 --- /dev/null +++ b/test/org/hibernate/test/hql/SimpleEntityWithAssociation.hbm.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/hql/SimpleEntityWithAssociation.java b/test/org/hibernate/test/hql/SimpleEntityWithAssociation.java new file mode 100644 index 0000000000..4315704381 --- /dev/null +++ b/test/org/hibernate/test/hql/SimpleEntityWithAssociation.java @@ -0,0 +1,70 @@ +package org.hibernate.test.hql; + +import java.util.Set; +import java.util.HashSet; + +/** + * @author Steve Ebersole + */ +public class SimpleEntityWithAssociation { + private Long id; + private String name; + private Set associatedEntities = new HashSet(); + private Set manyToManyAssociatedEntities = new HashSet(); + + public SimpleEntityWithAssociation() { + } + + public SimpleEntityWithAssociation(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getAssociatedEntities() { + return associatedEntities; + } + + public void setAssociatedEntities(Set associatedEntities) { + this.associatedEntities = associatedEntities; + } + + public SimpleAssociatedEntity addAssociation(String name) { + return new SimpleAssociatedEntity( name, this ); + } + + public void addAssociation(SimpleAssociatedEntity association) { + association.bindToOwner( this ); + } + + public void removeAssociation(SimpleAssociatedEntity association) { + if ( getAssociatedEntities().contains( association ) ) { + association.unbindFromCurrentOwner(); + } + else { + throw new IllegalArgumentException( "SimpleAssociatedEntity [" + association + "] not currently bound to this [" + this + "]" ); + } + } + + public Set getManyToManyAssociatedEntities() { + return manyToManyAssociatedEntities; + } + + public void setManyToManyAssociatedEntities(Set manyToManyAssociatedEntities) { + this.manyToManyAssociatedEntities = manyToManyAssociatedEntities; + } +} diff --git a/test/org/hibernate/test/hql/StateProvince.java b/test/org/hibernate/test/hql/StateProvince.java new file mode 100644 index 0000000000..22f4234955 --- /dev/null +++ b/test/org/hibernate/test/hql/StateProvince.java @@ -0,0 +1,37 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of StateProvince. + * + * @author Steve Ebersole + */ +public class StateProvince { + private Long id; + private String name; + private String isoCode; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIsoCode() { + return isoCode; + } + + public void setIsoCode(String isoCode) { + this.isoCode = isoCode; + } +} diff --git a/test/org/hibernate/test/hql/TimestampVersioned.java b/test/org/hibernate/test/hql/TimestampVersioned.java new file mode 100644 index 0000000000..87e3b8c70c --- /dev/null +++ b/test/org/hibernate/test/hql/TimestampVersioned.java @@ -0,0 +1,38 @@ +// $Id$ +package org.hibernate.test.hql; + +import java.util.Date; + +/** + * Implementation of TimestampVersioned. + * + * @author Steve Ebersole + */ +public class TimestampVersioned { + private Long id; + private Date version; + private String name; + + public TimestampVersioned() { + } + + public TimestampVersioned(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public Date getVersion() { + return version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/hql/Truck.java b/test/org/hibernate/test/hql/Truck.java new file mode 100644 index 0000000000..4fadec352c --- /dev/null +++ b/test/org/hibernate/test/hql/Truck.java @@ -0,0 +1,10 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of Truck. + * + * @author Steve Ebersole + */ +public class Truck extends Vehicle { +} diff --git a/test/org/hibernate/test/hql/User.java b/test/org/hibernate/test/hql/User.java new file mode 100755 index 0000000000..e390f14de3 --- /dev/null +++ b/test/org/hibernate/test/hql/User.java @@ -0,0 +1,48 @@ +//$Id$ +package org.hibernate.test.hql; + +import java.util.List; + +/** + * @author Gavin King + */ +public class User { + private Long id; + private String userName; + private Human human; + private List permissions; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Human getHuman() { + return human; + } + + public void setHuman(Human human) { + this.human = human; + } + + public List getPermissions() { + return permissions; + } + + + public void setPermissions(List permissions) { + this.permissions = permissions; + } + +} diff --git a/test/org/hibernate/test/hql/Vehicle.hbm.xml b/test/org/hibernate/test/hql/Vehicle.hbm.xml new file mode 100644 index 0000000000..f4091eaa7a --- /dev/null +++ b/test/org/hibernate/test/hql/Vehicle.hbm.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + delete from CAR where owner = ? + + \ No newline at end of file diff --git a/test/org/hibernate/test/hql/Vehicle.java b/test/org/hibernate/test/hql/Vehicle.java new file mode 100644 index 0000000000..2d21eb40d6 --- /dev/null +++ b/test/org/hibernate/test/hql/Vehicle.java @@ -0,0 +1,29 @@ +// $Id$ +package org.hibernate.test.hql; + +/** + * Implementation of Vehicle. + * + * @author Steve Ebersole + */ +public abstract class Vehicle { + private Long id; + private String vin; + private String owner; + + public String getVin() { + return vin; + } + + public void setVin(String vin) { + this.vin = vin; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } +} diff --git a/test/org/hibernate/test/hql/Versions.hbm.xml b/test/org/hibernate/test/hql/Versions.hbm.xml new file mode 100644 index 0000000000..6e8192182e --- /dev/null +++ b/test/org/hibernate/test/hql/Versions.hbm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/hql/WithClauseTest.java b/test/org/hibernate/test/hql/WithClauseTest.java new file mode 100644 index 0000000000..4a947cdc4e --- /dev/null +++ b/test/org/hibernate/test/hql/WithClauseTest.java @@ -0,0 +1,196 @@ +// $Id$ +package org.hibernate.test.hql; + +import org.hibernate.test.TestCase; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.HibernateException; +import org.hibernate.QueryException; +import org.hibernate.hql.ast.InvalidWithClauseException; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; + +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Implementation of WithClauseTest. + * + * @author Steve Ebersole + */ +public class WithClauseTest extends TestCase { + + public WithClauseTest(String name) { + super( name ); + } + + protected String[] getMappings() { + return new String[] { "hql/Animal.hbm.xml" }; + } + + public static Test suite() { + return new TestSuite( WithClauseTest.class ); + } + + protected void configure(Configuration cfg) { + super.configure( cfg ); + } + + public void testWithClauseFailsWithFetch() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + try { + s.createQuery( "from Animal a inner join fetch a.offspring as o with o.bodyWeight = :someLimit" ) + .setDouble( "someLimit", 1 ) + .list(); + fail( "ad-hoc on clause allowed with fetched association" ); + } + catch ( HibernateException e ) { + // the expected response... + } + + txn.commit(); + s.close(); + + data.cleanup(); + } + + public void testInvalidWithSemantics() { + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + try { + // PROBLEM : f.bodyWeight is a reference to a column on the Animal table; however, the 'f' + // alias relates to the Human.friends collection which the aonther Human entity. The issue + // here is the way JoinSequence and Joinable (the persister) interact to generate the + // joins relating to the sublcass/superclass tables + s.createQuery( "from Human h inner join h.friends as f with f.bodyWeight < :someLimit" ) + .setDouble( "someLimit", 1 ) + .list(); + fail( "failure expected" ); + } + catch( InvalidWithClauseException expected ) { + } + + try { + s.createQuery( "from Animal a inner join a.offspring o inner join o.mother as m inner join m.father as f with o.bodyWeight > 1" ) + .list(); + fail( "failure expected" ); + } + catch( InvalidWithClauseException expected ) { + } + + try { + s.createQuery( "from Human h inner join h.offspring o with o.mother.father = :cousin" ) + .setEntity( "cousin", s.load( Human.class, new Long(123) ) ) + .list(); + fail( "failure expected" ); + } + catch( InvalidWithClauseException expected ) { + } + + txn.commit(); + s.close(); + } + + public void testWithClause() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction txn = s.beginTransaction(); + + // one-to-many + List list = s.createQuery( "from Human h inner join h.offspring as o with o.bodyWeight < :someLimit" ) + .setDouble( "someLimit", 1 ) + .list(); + assertTrue( "ad-hoc on did not take effect", list.isEmpty() ); + + // many-to-one + list = s.createQuery( "from Animal a inner join a.mother as m with m.bodyWeight < :someLimit" ) + .setDouble( "someLimit", 1 ) + .list(); + assertTrue( "ad-hoc on did not take effect", list.isEmpty() ); + + // many-to-many + list = s.createQuery( "from Human h inner join h.friends as f with f.nickName like 'bubba'" ) + .list(); + assertTrue( "ad-hoc on did not take effect", list.isEmpty() ); + + txn.commit(); + s.close(); + + data.cleanup(); + } + + private class TestData { + public void prepare() { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + + Human mother = new Human(); + mother.setBodyWeight( 10 ); + mother.setDescription( "mother" ); + + Human father = new Human(); + father.setBodyWeight( 15 ); + father.setDescription( "father" ); + + Human child1 = new Human(); + child1.setBodyWeight( 5 ); + child1.setDescription( "child1" ); + + Human child2 = new Human(); + child2.setBodyWeight( 6 ); + child2.setDescription( "child2" ); + + Human friend = new Human(); + friend.setBodyWeight( 20 ); + friend.setDescription( "friend" ); + + child1.setMother( mother ); + child1.setFather( father ); + mother.addOffspring( child1 ); + father.addOffspring( child1 ); + + child2.setMother( mother ); + child2.setFather( father ); + mother.addOffspring( child2 ); + father.addOffspring( child2 ); + + father.setFriends( new ArrayList() ); + father.getFriends().add( friend ); + + session.save( mother ); + session.save( father ); + session.save( child1 ); + session.save( child2 ); + session.save( friend ); + + txn.commit(); + session.close(); + } + + public void cleanup() { + Session session = openSession(); + Transaction txn = session.beginTransaction(); + session.createQuery( "delete Animal where mother is not null" ).executeUpdate(); + List humansWithFriends = session.createQuery( "from Human h where exists(from h.friends)" ).list(); + Iterator itr = humansWithFriends.iterator(); + while ( itr.hasNext() ) { + session.delete( itr.next() ); + } + session.createQuery( "delete Animal" ).executeUpdate(); + txn.commit(); + session.close(); + } + } +} diff --git a/test/org/hibernate/test/hql/Zoo.java b/test/org/hibernate/test/hql/Zoo.java new file mode 100644 index 0000000000..5d3b73f56e --- /dev/null +++ b/test/org/hibernate/test/hql/Zoo.java @@ -0,0 +1,64 @@ +//$Id$ +package org.hibernate.test.hql; + +import java.util.Map; + +/** + * @author Gavin King + */ +public class Zoo { + private Long id; + private String name; + private Classification classification; + private Map animals; + private Map mammals; + private Address address; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getMammals() { + return mammals; + } + + public void setMammals(Map mammals) { + this.mammals = mammals; + } + + public Map getAnimals() { + return animals; + } + + public void setAnimals(Map animals) { + this.animals = animals; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + public Classification getClassification() { + return classification; + } + + public void setClassification(Classification classification) { + this.classification = classification; + } +} diff --git a/test/org/hibernate/test/id/Car.hbm.xml b/test/org/hibernate/test/id/Car.hbm.xml new file mode 100644 index 0000000000..9d0b5f7026 --- /dev/null +++ b/test/org/hibernate/test/id/Car.hbm.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + 0 + + + + + + diff --git a/test/org/hibernate/test/id/Car.java b/test/org/hibernate/test/id/Car.java new file mode 100644 index 0000000000..92a31b66ea --- /dev/null +++ b/test/org/hibernate/test/id/Car.java @@ -0,0 +1,26 @@ +//$Id$ +package org.hibernate.test.id; + +/** + * @author Emmanuel Bernard + */ +public class Car { + private Long id; + private String color; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } +} diff --git a/test/org/hibernate/test/id/MultipleHiLoPerTableGeneratorTest.java b/test/org/hibernate/test/id/MultipleHiLoPerTableGeneratorTest.java new file mode 100644 index 0000000000..f0799aad31 --- /dev/null +++ b/test/org/hibernate/test/id/MultipleHiLoPerTableGeneratorTest.java @@ -0,0 +1,107 @@ +//$Id$ +package org.hibernate.test.id; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Emmanuel Bernard + */ +public class MultipleHiLoPerTableGeneratorTest extends FunctionalTestCase { + public MultipleHiLoPerTableGeneratorTest(String x) { + super(x); + } + + public String[] getMappings() { + return new String[]{ "id/Car.hbm.xml", "id/Plane.hbm.xml", "id/Radio.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( MultipleHiLoPerTableGeneratorTest.class ); + } + + public void testDistinctId() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + int testLength = 8; + Car[] cars = new Car[testLength]; + Plane[] planes = new Plane[testLength]; + for (int i = 0; i < testLength ; i++) { + cars[i] = new Car(); + cars[i].setColor("Color" + i); + planes[i] = new Plane(); + planes[i].setNbrOfSeats(i); + s.persist(cars[i]); + //s.persist(planes[i]); + } + tx.commit(); + s.close(); + for (int i = 0; i < testLength ; i++) { + assertEquals(i+1, cars[i].getId().intValue()); + //assertEquals(i+1, planes[i].getId().intValue()); + } + + s = openSession(); + tx = s.beginTransaction(); + s.createQuery( "delete from Car" ).executeUpdate(); + tx.commit(); + s.close(); + } + + public void testRollingBack() throws Throwable { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + int testLength = 3; + Long lastId = null; + for (int i = 0; i < testLength ; i++) { + Car car = new Car(); + car.setColor( "color " + i ); + s.save( car ); + lastId = car.getId(); + } + tx.rollback(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + Car car = new Car(); + car.setColor( "blue" ); + s.save( car ); + s.flush(); + tx.commit(); + s.close(); + + assertEquals( "id generation was rolled back", lastId.longValue() + 1, car.getId().longValue() ); + + s = openSession(); + tx = s.beginTransaction(); + s.createQuery( "delete Car" ).executeUpdate(); + tx.commit(); + s.close(); + } + + public void testAllParams() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + Radio radio = new Radio(); + radio.setFrequency("32 MHz"); + s.persist(radio); + assertEquals( new Integer(1), radio.getId() ); + radio = new Radio(); + radio.setFrequency("32 MHz"); + s.persist(radio); + assertEquals( new Integer(2), radio.getId() ); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + s.createQuery( "delete from Radio" ).executeUpdate(); + tx.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/id/Plane.hbm.xml b/test/org/hibernate/test/id/Plane.hbm.xml new file mode 100644 index 0000000000..aa87e5ec67 --- /dev/null +++ b/test/org/hibernate/test/id/Plane.hbm.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + 2 + + + + + + diff --git a/test/org/hibernate/test/id/Plane.java b/test/org/hibernate/test/id/Plane.java new file mode 100644 index 0000000000..9f805befe6 --- /dev/null +++ b/test/org/hibernate/test/id/Plane.java @@ -0,0 +1,26 @@ +//$Id$ +package org.hibernate.test.id; + +/** + * @author Emmanuel Bernard + */ +public class Plane { + private Long id; + private int nbrOfSeats; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getNbrOfSeats() { + return nbrOfSeats; + } + + public void setNbrOfSeats(int nbrOfSeats) { + this.nbrOfSeats = nbrOfSeats; + } +} diff --git a/test/org/hibernate/test/id/Product.hbm.xml b/test/org/hibernate/test/id/Product.hbm.xml new file mode 100644 index 0000000000..a4b224c5bf --- /dev/null +++ b/test/org/hibernate/test/id/Product.hbm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/id/Product.java b/test/org/hibernate/test/id/Product.java new file mode 100644 index 0000000000..d81aabab3f --- /dev/null +++ b/test/org/hibernate/test/id/Product.java @@ -0,0 +1,17 @@ +//$Id: $ +package org.hibernate.test.id; + +/** + * @author Emmanuel Bernard + */ +public class Product { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/id/Radio.hbm.xml b/test/org/hibernate/test/id/Radio.hbm.xml new file mode 100644 index 0000000000..ebd8d6b714 --- /dev/null +++ b/test/org/hibernate/test/id/Radio.hbm.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + sequences + hi_value + name + 50 + 2 + Radio + + + + + + diff --git a/test/org/hibernate/test/id/Radio.java b/test/org/hibernate/test/id/Radio.java new file mode 100644 index 0000000000..1d65a06978 --- /dev/null +++ b/test/org/hibernate/test/id/Radio.java @@ -0,0 +1,26 @@ +//$Id$ +package org.hibernate.test.id; + +/** + * @author Emmanuel Bernard + */ +public class Radio { + private Integer id; + private String frequency; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getFrequency() { + return frequency; + } + + public void setFrequency(String frequency) { + this.frequency = frequency; + } +} diff --git a/test/org/hibernate/test/id/UseIdentifierRollbackTest.java b/test/org/hibernate/test/id/UseIdentifierRollbackTest.java new file mode 100644 index 0000000000..1f8c34225a --- /dev/null +++ b/test/org/hibernate/test/id/UseIdentifierRollbackTest.java @@ -0,0 +1,44 @@ +//$Id: $ +package org.hibernate.test.id; + +import org.hibernate.test.TestCase; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.Session; +import org.hibernate.Transaction; +import junit.framework.Test; + +/** + * @author Emmanuel Bernard + */ +public class UseIdentifierRollbackTest extends TestCase { + public UseIdentifierRollbackTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "id/Product.hbm.xml" }; + } + + public void configure(Configuration cfg) { + cfg.setProperty( Environment.USE_IDENTIFIER_ROLLBACK, "true"); + super.configure( cfg ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( UseIdentifierRollbackTest.class ); + } + + public void testSimpleRollback() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product(); + assertNull( prod.getName() ); + session.persist(prod); + session.flush(); + assertNotNull( prod.getName() ); + t.rollback(); + session.close(); + } +} diff --git a/test/org/hibernate/test/idbag/Group.java b/test/org/hibernate/test/idbag/Group.java new file mode 100755 index 0000000000..66eca24893 --- /dev/null +++ b/test/org/hibernate/test/idbag/Group.java @@ -0,0 +1,24 @@ +//$Id$ +package org.hibernate.test.idbag; + +/** + * @author Gavin King + */ +public class Group { + private String name; + + Group() {} + + public Group(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + void setName(String name) { + this.name = name; + } + +} diff --git a/test/org/hibernate/test/idbag/IdBagTest.java b/test/org/hibernate/test/idbag/IdBagTest.java new file mode 100755 index 0000000000..74696894fa --- /dev/null +++ b/test/org/hibernate/test/idbag/IdBagTest.java @@ -0,0 +1,101 @@ +//$Id$ +package org.hibernate.test.idbag; + +import java.sql.SQLException; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class IdBagTest extends FunctionalTestCase { + + public IdBagTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "idbag/UserGroup.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( IdBagTest.class ); + } + + public void testUpdateIdBag() throws HibernateException, SQLException { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User gavin = new User("gavin"); + Group admins = new Group("admins"); + Group plebs = new Group("plebs"); + Group moderators = new Group("moderators"); + Group banned = new Group("banned"); + gavin.getGroups().add(plebs); + //gavin.getGroups().add(moderators); + s.persist(gavin); + s.persist(plebs); + s.persist(admins); + s.persist(moderators); + s.persist(banned); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + gavin = (User) s.createCriteria(User.class).uniqueResult(); + admins = (Group) s.load(Group.class, "admins"); + plebs = (Group) s.load(Group.class, "plebs"); + banned = (Group) s.load(Group.class, "banned"); + gavin.getGroups().add(admins); + gavin.getGroups().remove(plebs); + //gavin.getGroups().add(banned); + + s.delete(plebs); + s.delete(banned); + s.delete(moderators); + s.delete(admins); + s.delete(gavin); + + t.commit(); + s.close(); + } + + public void testJoin() throws HibernateException, SQLException { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User gavin = new User("gavin"); + Group admins = new Group("admins"); + Group plebs = new Group("plebs"); + gavin.getGroups().add(plebs); + gavin.getGroups().add(admins); + s.persist(gavin); + s.persist(plebs); + s.persist(admins); + + List l = s.createQuery("from User u join u.groups g").list(); + assertEquals( l.size(), 2 ); + s.clear(); + + gavin = (User) s.createQuery("from User u join fetch u.groups").uniqueResult(); + assertTrue( Hibernate.isInitialized( gavin.getGroups() ) ); + assertEquals( gavin.getGroups().size(), 2 ); + assertEquals( ( (Group) gavin.getGroups().get(0) ).getName(), "admins" ); + + s.delete( gavin.getGroups().get(0) ); + s.delete( gavin.getGroups().get(1) ); + s.delete(gavin); + + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/idbag/User.java b/test/org/hibernate/test/idbag/User.java new file mode 100755 index 0000000000..43b5f0796e --- /dev/null +++ b/test/org/hibernate/test/idbag/User.java @@ -0,0 +1,37 @@ +//$Id$ +package org.hibernate.test.idbag; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Gavin King + */ +public class User { + private String name; + private List groups = new ArrayList(); + + User() {} + + public User(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + + void setName(String name) { + this.name = name; + } + + public List getGroups() { + return groups; + } + + void setGroups(List groups) { + this.groups = groups; + } + +} diff --git a/test/org/hibernate/test/idbag/UserGroup.hbm.xml b/test/org/hibernate/test/idbag/UserGroup.hbm.xml new file mode 100755 index 0000000000..93cd9e6f6c --- /dev/null +++ b/test/org/hibernate/test/idbag/UserGroup.hbm.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/idclass/Customer.hbm.xml b/test/org/hibernate/test/idclass/Customer.hbm.xml new file mode 100755 index 0000000000..4f41136732 --- /dev/null +++ b/test/org/hibernate/test/idclass/Customer.hbm.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/idclass/Customer.java b/test/org/hibernate/test/idclass/Customer.java new file mode 100755 index 0000000000..2df3376289 --- /dev/null +++ b/test/org/hibernate/test/idclass/Customer.java @@ -0,0 +1,90 @@ +//$Id$ + +package org.hibernate.test.idclass; + + + + + +public class Customer { + + + + public Customer() { + + super(); + + } + + + + public Customer(String orgName, String custName, String add) { + + this.orgName = orgName; + + this.customerName = custName; + + this.address = add; + + } + + + + private String orgName; + + private String customerName; + + private String address; + + + + public String getAddress() { + + return address; + + } + + + + public void setAddress(String address) { + + this.address = address; + + } + + + + public String getCustomerName() { + + return customerName; + + } + + + + public void setCustomerName(String customerName) { + + this.customerName = customerName; + + } + + + + public String getOrgName() { + + return orgName; + + } + + + + public void setOrgName(String orgName) { + + this.orgName = orgName; + + } + + + +} + diff --git a/test/org/hibernate/test/idclass/CustomerId.java b/test/org/hibernate/test/idclass/CustomerId.java new file mode 100755 index 0000000000..1edb257e2c --- /dev/null +++ b/test/org/hibernate/test/idclass/CustomerId.java @@ -0,0 +1,36 @@ +//$Id$ +package org.hibernate.test.idclass; + +import java.io.Serializable; + +public class CustomerId implements Serializable { + + private String orgName; + private String customerName; + + public CustomerId() { + super(); + } + + public CustomerId(String orgName, String custName) { + this.orgName = orgName; + this.customerName = custName; + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName(String customerName) { + this.customerName = customerName; + } + + public String getOrgName() { + return orgName; + } + + public void setOrgName(String orgName) { + this.orgName = orgName; + } + +} diff --git a/test/org/hibernate/test/idclass/FavoriteCustomer.java b/test/org/hibernate/test/idclass/FavoriteCustomer.java new file mode 100644 index 0000000000..6fe769ca98 --- /dev/null +++ b/test/org/hibernate/test/idclass/FavoriteCustomer.java @@ -0,0 +1,14 @@ +//$Id$ +package org.hibernate.test.idclass; + +/** + * @author Emmanuel Bernard + */ +public class FavoriteCustomer extends Customer { + public FavoriteCustomer() { + } + + public FavoriteCustomer(String orgName, String custName, String add) { + super( orgName, custName, add ); + } +} diff --git a/test/org/hibernate/test/idclass/IdClassTest.java b/test/org/hibernate/test/idclass/IdClassTest.java new file mode 100755 index 0000000000..348b0f3ac8 --- /dev/null +++ b/test/org/hibernate/test/idclass/IdClassTest.java @@ -0,0 +1,69 @@ +//$Id$ +package org.hibernate.test.idclass; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class IdClassTest extends FunctionalTestCase { + + public IdClassTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "idclass/Customer.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( IdClassTest.class ); + } + + public void testIdClass() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Customer cust = new FavoriteCustomer("JBoss", "RouteOne", "Detroit"); + s.persist(cust); + t.commit(); + s.close(); + + s = openSession(); + CustomerId custId = new CustomerId("JBoss", "RouteOne"); + t = s.beginTransaction(); + cust = (Customer) s.get(Customer.class, custId); + assertEquals( "Detroit", cust.getAddress() ); + assertEquals( cust.getCustomerName(), custId.getCustomerName() ); + assertEquals( cust.getOrgName(), custId.getOrgName() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Customer) s.createQuery("from Customer where id.customerName = 'RouteOne'").uniqueResult(); + assertEquals( "Detroit", cust.getAddress() ); + assertEquals( cust.getCustomerName(), custId.getCustomerName() ); + assertEquals( cust.getOrgName(), custId.getOrgName() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + cust = (Customer) s.createQuery("from Customer where customerName = 'RouteOne'").uniqueResult(); + assertEquals( "Detroit", cust.getAddress() ); + assertEquals( cust.getCustomerName(), custId.getCustomerName() ); + assertEquals( cust.getOrgName(), custId.getOrgName() ); + + s.createQuery( "delete from Customer" ).executeUpdate(); + + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/idgen/IdGenSuite.java b/test/org/hibernate/test/idgen/IdGenSuite.java new file mode 100644 index 0000000000..f67a2daedd --- /dev/null +++ b/test/org/hibernate/test/idgen/IdGenSuite.java @@ -0,0 +1,44 @@ +package org.hibernate.test.idgen; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.test.idgen.enhanced.OptimizerUnitTest; +import org.hibernate.test.idgen.enhanced.SequenceStyleConfigUnitTest; +import org.hibernate.test.idgen.enhanced.forcedtable.BasicForcedTableSequenceTest; +import org.hibernate.test.idgen.enhanced.forcedtable.HiLoForcedTableSequenceTest; +import org.hibernate.test.idgen.enhanced.forcedtable.PooledForcedTableSequenceTest; +import org.hibernate.test.idgen.enhanced.sequence.BasicSequenceTest; +import org.hibernate.test.idgen.enhanced.sequence.HiLoSequenceTest; +import org.hibernate.test.idgen.enhanced.sequence.PooledSequenceTest; +import org.hibernate.test.idgen.enhanced.table.BasicTableTest; +import org.hibernate.test.idgen.enhanced.table.HiLoTableTest; +import org.hibernate.test.idgen.enhanced.table.PooledTableTest; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class IdGenSuite { + public static Test suite() { + TestSuite suite = new TestSuite( "enhanced id generators" ); + + suite.addTest( OptimizerUnitTest.suite() ); + suite.addTest( SequenceStyleConfigUnitTest.suite() ); + + suite.addTest( BasicForcedTableSequenceTest.suite() ); + suite.addTest( HiLoForcedTableSequenceTest.suite() ); + suite.addTest( PooledForcedTableSequenceTest.suite() ); + + suite.addTest( BasicSequenceTest.suite() ); + suite.addTest( HiLoSequenceTest.suite() ); + suite.addTest( PooledSequenceTest.suite() ); + + suite.addTest( BasicTableTest.suite() ); + suite.addTest( HiLoTableTest.suite() ); + suite.addTest( PooledTableTest.suite() ); + + return suite; + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java b/test/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java new file mode 100644 index 0000000000..1cad81ff13 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java @@ -0,0 +1,154 @@ +package org.hibernate.test.idgen.enhanced; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.junit.UnitTestCase; +import org.hibernate.id.enhanced.Optimizer; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.AccessCallback; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class OptimizerUnitTest extends UnitTestCase { + public OptimizerUnitTest(String string) { + super( string ); + } + + public static Test suite() { + return new TestSuite( OptimizerUnitTest.class ); + } + + public void testBasicNoOptimizerUsage() { + // test historic sequence behavior, where the initial values start at 1... + SourceMock sequence = new SourceMock( 1 ); + Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 ); + for ( int i = 1; i < 11; i++ ) { + final Long next = ( Long ) optimizer.generate( sequence ); + assertEquals( i, next.intValue() ); + } + assertEquals( 10, sequence.getTimesCalled() ); + assertEquals( 10, sequence.getCurrentValue() ); + + // test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value) + sequence = new SourceMock( 0 ); + optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 ); + for ( int i = 1; i < 11; i++ ) { + final Long next = ( Long ) optimizer.generate( sequence ); + assertEquals( i, next.intValue() ); + } + assertEquals( 11, sequence.getTimesCalled() ); // an extra time to get to 1 initially + assertEquals( 10, sequence.getCurrentValue() ); + } + + public void testBasicHiLoOptimizerUsage() { + int increment = 10; + Long next; + + // test historic sequence behavior, where the initial values start at 1... + SourceMock sequence = new SourceMock( 1 ); + Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment ); + for ( int i = 1; i <= increment; i++ ) { + next = ( Long ) optimizer.generate( sequence ); + assertEquals( i, next.intValue() ); + } + assertEquals( 1, sequence.getTimesCalled() ); // once to initialze state + assertEquals( 1, sequence.getCurrentValue() ); + // force a "clock over" + next = ( Long ) optimizer.generate( sequence ); + assertEquals( 11, next.intValue() ); + assertEquals( 2, sequence.getTimesCalled() ); + assertEquals( 2, sequence.getCurrentValue() ); + + // test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value) + sequence = new SourceMock( 0 ); + optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment ); + for ( int i = 1; i <= increment; i++ ) { + next = ( Long ) optimizer.generate( sequence ); + assertEquals( i, next.intValue() ); + } + assertEquals( 2, sequence.getTimesCalled() ); // here have have an extra call to get to 1 initially + assertEquals( 1, sequence.getCurrentValue() ); + // force a "clock over" + next = ( Long ) optimizer.generate( sequence ); + assertEquals( 11, next.intValue() ); + assertEquals( 3, sequence.getTimesCalled() ); + assertEquals( 2, sequence.getCurrentValue() ); + } + + public void testBasicPooledOptimizerUsage() { + Long next; + // test historic sequence behavior, where the initial values start at 1... + SourceMock sequence = new SourceMock( 1, 10 ); + Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, 10 ); + for ( int i = 1; i < 11; i++ ) { + next = ( Long ) optimizer.generate( sequence ); + assertEquals( i, next.intValue() ); + } + assertEquals( 2, sequence.getTimesCalled() ); // twice to initialze state + assertEquals( 11, sequence.getCurrentValue() ); + // force a "clock over" + next = ( Long ) optimizer.generate( sequence ); + assertEquals( 11, next.intValue() ); + assertEquals( 3, sequence.getTimesCalled() ); + assertEquals( 21, sequence.getCurrentValue() ); + } + + private static class SourceMock implements AccessCallback { + private long value; + private int increment; + private int timesCalled = 0; + + public SourceMock(long initialValue) { + this( initialValue, 1 ); + } + + public SourceMock(long initialValue, int increment) { + this.increment = increment; + this.value = initialValue - increment; + } + + public long getNextValue() { + timesCalled++; + return ( value += increment ); + } + + public int getTimesCalled() { + return timesCalled; + } + + public long getCurrentValue() { + return value; + } + } + +// public void testNoopDumping() { +// SourceMock sequence = new SourceMock( 1 ); +// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 ); +// for ( int i = 1; i <= 41; i++ ) { +// System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" ); +// } +// } +// +// public void testHiLoDumping() { +// int increment = 10; +// SourceMock sequence = new SourceMock( 1 ); +// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment ); +// for ( int i = 1; i <= 41; i++ ) { +// System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" ); +// } +// } +// +// public void testPooledDumping() { +// int increment = 10; +// SourceMock sequence = new SourceMock( 1, increment ); +// Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, increment ); +// for ( int i = 1; i <= 41; i++ ) { +// System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" ); +// } +// } + +} diff --git a/test/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java b/test/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java new file mode 100644 index 0000000000..0bedcd15db --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java @@ -0,0 +1,179 @@ +package org.hibernate.test.idgen.enhanced; + +import java.util.Properties; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.junit.UnitTestCase; +import org.hibernate.dialect.Dialect; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.id.enhanced.SequenceStructure; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.TableStructure; +import org.hibernate.Hibernate; +import org.hibernate.MappingException; + +/** + * Tests that SequenceStyleGenerator configures itself as expected + * in various scenarios + * + * @author Steve Ebersole + */ +public class SequenceStyleConfigUnitTest extends UnitTestCase { + public SequenceStyleConfigUnitTest(String string) { + super( string ); + } + + public static Test suite() { + return new TestSuite( SequenceStyleConfigUnitTest.class ); + } + + /** + * Test all params defaulted with a dialect supporting sequences + */ + public void testDefaultedSequenceBackedConfiguration() { + Dialect dialect = new SequenceDialect(); + Properties props = new Properties(); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + + assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + } + + /** + * Test all params defaulted with a dialect which does not support sequences + */ + public void testDefaultedTableBackedConfiguration() { + Dialect dialect = new TableDialect(); + Properties props = new Properties(); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + + assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + } + + /** + * Test default optimizer selection for sequence backed generators + * based on the configured increment size; both in the case of the + * dialect supporting pooled sequences (pooled) and not (hilo) + */ + public void testDefaultOptimizerBasedOnIncrementBackedBySequence() { + Properties props = new Properties(); + props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" ); + + // for dialects which do not support pooled sequences, we default to hilo + Dialect dialect = new SequenceDialect(); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + + // for dialects which do support pooled sequences, we default to pooled + dialect = new PooledSequenceDialect(); + generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + } + + /** + * Test default optimizer selection for table backed generators + * based on the configured increment size. Here we always prefer + * pooled. + */ + public void testDefaultOptimizerBasedOnIncrementBackedByTable() { + Properties props = new Properties(); + props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" ); + Dialect dialect = new TableDialect(); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + } + + /** + * Test forcing of table as backing strucuture with dialect supporting sequences + */ + public void testForceTableUse() { + Dialect dialect = new SequenceDialect(); + Properties props = new Properties(); + props.setProperty( SequenceStyleGenerator.FORCE_TBL_PARAM, "true" ); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + } + + /** + * Test explicitly specifying both optimizer and increment + */ + public void testExplicitOptimizerWithExplicitIncrementSize() { + // with sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Dialect dialect = new SequenceDialect(); + + // optimizer=none w/ increment > 1 => should honor optimizer + Properties props = new Properties(); + props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.NONE ); + props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" ); + SequenceStyleGenerator generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( 1, generator.getOptimizer().getIncrementSize() ); + assertEquals( 1, generator.getDatabaseStructure().getIncrementSize() ); + + // optimizer=hilo w/ increment > 1 => hilo + props = new Properties(); + props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.HILO ); + props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( 20, generator.getOptimizer().getIncrementSize() ); + assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() ); + + // optimizer=pooled w/ increment > 1 => hilo + props = new Properties(); + props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.POOL ); + props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" ); + generator = new SequenceStyleGenerator(); + generator.configure( Hibernate.LONG, props, dialect ); + assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); + assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() ); + assertEquals( 20, generator.getOptimizer().getIncrementSize() ); + assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() ); + } + + private static class TableDialect extends Dialect { + public boolean supportsSequences() { + return false; + } + } + + private static class SequenceDialect extends Dialect { + public boolean supportsSequences() { + return true; + } + public boolean supportsPooledSequences() { + return false; + } + public String getSequenceNextValString(String sequenceName) throws MappingException { + return ""; + } + } + + private static class PooledSequenceDialect extends SequenceDialect { + public boolean supportsPooledSequences() { + return true; + } + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/forcedtable/Basic.hbm.xml b/test/org/hibernate/test/idgen/enhanced/forcedtable/Basic.hbm.xml new file mode 100644 index 0000000000..ada60064a5 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/forcedtable/Basic.hbm.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + ID_SEQ_TBL_BSC_SEQ + hi_val + 1 + 1 + none + true + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java b/test/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java new file mode 100644 index 0000000000..5e8c37d69f --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java @@ -0,0 +1,57 @@ +package org.hibernate.test.idgen.enhanced.forcedtable; + +import junit.framework.Test; + +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class BasicForcedTableSequenceTest extends DatabaseSpecificFunctionalTestCase { + public BasicForcedTableSequenceTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/forcedtable/Basic.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BasicForcedTableSequenceTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() ); + SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator(); + + int count = 5; + Entity[] entities = new Entity[count]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < count; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + long expectedId = i + 1; + assertEquals( expectedId, entities[i].getId().longValue() ); + assertEquals( expectedId, generator.getDatabaseStructure().getTimesAccessed() ); + assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() ); + } + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < count; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/forcedtable/Entity.java b/test/org/hibernate/test/idgen/enhanced/forcedtable/Entity.java new file mode 100644 index 0000000000..998423f2fb --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/forcedtable/Entity.java @@ -0,0 +1,34 @@ +package org.hibernate.test.idgen.enhanced.forcedtable; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Entity { + private Long id; + private String name; + + public Entity() { + } + + public Entity(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/forcedtable/HiLo.hbm.xml b/test/org/hibernate/test/idgen/enhanced/forcedtable/HiLo.hbm.xml new file mode 100644 index 0000000000..04976e328d --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/forcedtable/HiLo.hbm.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + ID_SEQ_TBL_HILO_SEQ + 1 + 10 + hilo + true + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java b/test/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java new file mode 100644 index 0000000000..6ccffd9465 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java @@ -0,0 +1,69 @@ +package org.hibernate.test.idgen.enhanced.forcedtable; + +import junit.framework.Test; + +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class HiLoForcedTableSequenceTest extends DatabaseSpecificFunctionalTestCase { + public HiLoForcedTableSequenceTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/forcedtable/HiLo.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( HiLoForcedTableSequenceTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() ); + SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator(); + assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() ); + OptimizerFactory.HiLoOptimizer optimizer = ( OptimizerFactory.HiLoOptimizer ) generator.getOptimizer(); + + int increment = optimizer.getIncrementSize(); + Entity[] entities = new Entity[ increment + 1 ]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < increment; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + long expectedId = i + 1; + assertEquals( expectedId, entities[i].getId().longValue() ); + assertEquals( 1, generator.getOptimizer().getLastSourceValue() ); + assertEquals( i + 1, optimizer.getLastValue() ); + assertEquals( increment + 1, optimizer.getHiValue() ); + } + // now force a "clock over" + entities[ increment ] = new Entity( "" + increment ); + s.save( entities[ increment ] ); + long expectedId = optimizer.getIncrementSize() + 1; + assertEquals( expectedId, entities[ optimizer.getIncrementSize() ].getId().longValue() ); + assertEquals( 2, optimizer.getLastSourceValue() ); // initialization + clokc-over + assertEquals( increment + 1, optimizer.getLastValue() ); + assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() ); + + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < entities.length; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/forcedtable/Pooled.hbm.xml b/test/org/hibernate/test/idgen/enhanced/forcedtable/Pooled.hbm.xml new file mode 100644 index 0000000000..bbcd54997c --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/forcedtable/Pooled.hbm.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + ID_SEQ_TBL_POOL_SEQ + 1 + 10 + pooled + true + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java b/test/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java new file mode 100644 index 0000000000..25d74488ab --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java @@ -0,0 +1,69 @@ +package org.hibernate.test.idgen.enhanced.forcedtable; + +import junit.framework.Test; + +import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class PooledForcedTableSequenceTest extends DatabaseSpecificFunctionalTestCase { + public PooledForcedTableSequenceTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/forcedtable/Pooled.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PooledForcedTableSequenceTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() ); + SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator(); + assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() ); + OptimizerFactory.PooledOptimizer optimizer = ( OptimizerFactory.PooledOptimizer ) generator.getOptimizer(); + + int increment = optimizer.getIncrementSize(); + Entity[] entities = new Entity[ increment + 1 ]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < increment; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + long expectedId = i + 1; + assertEquals( expectedId, entities[i].getId().longValue() ); + assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization calls table twice + assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls table twice + assertEquals( i + 1, optimizer.getLastValue() ); + assertEquals( increment + 1, optimizer.getLastSourceValue() ); + } + // now force a "clock over" + entities[ increment ] = new Entity( "" + increment ); + s.save( entities[ increment ] ); + long expectedId = optimizer.getIncrementSize() + 1; + assertEquals( expectedId, entities[ optimizer.getIncrementSize() ].getId().longValue() ); + assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); // initialization (2) + clock over + assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over + assertEquals( increment + 1, optimizer.getLastValue() ); + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < entities.length; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml b/test/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml new file mode 100644 index 0000000000..7405a78fd0 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + ID_SEQ_BSC_SEQ + 1 + 1 + none + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java b/test/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java new file mode 100644 index 0000000000..a99c395f0b --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java @@ -0,0 +1,57 @@ +package org.hibernate.test.idgen.enhanced.sequence; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.Session; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.persister.entity.EntityPersister; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class BasicSequenceTest extends FunctionalTestCase { + public BasicSequenceTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/sequence/Basic.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BasicSequenceTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() ); + SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator(); + + int count = 5; + Entity[] entities = new Entity[count]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < count; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + long expectedId = i + 1; + assertEquals( expectedId, entities[i].getId().longValue() ); + assertEquals( expectedId, generator.getDatabaseStructure().getTimesAccessed() ); + assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() ); + } + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < count; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/sequence/Entity.java b/test/org/hibernate/test/idgen/enhanced/sequence/Entity.java new file mode 100644 index 0000000000..61d79479fd --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/sequence/Entity.java @@ -0,0 +1,34 @@ +package org.hibernate.test.idgen.enhanced.sequence; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Entity { + private Long id; + private String name; + + public Entity() { + } + + public Entity(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml b/test/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml new file mode 100644 index 0000000000..3934a08a9d --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + ID_SEQ_HILO_SEQ + 1 + 10 + hilo + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java b/test/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java new file mode 100644 index 0000000000..77627336f1 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java @@ -0,0 +1,67 @@ +package org.hibernate.test.idgen.enhanced.sequence; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.Session; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.persister.entity.EntityPersister; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class HiLoSequenceTest extends FunctionalTestCase { + public HiLoSequenceTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/sequence/HiLo.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( HiLoSequenceTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() ); + SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator(); + assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() ); + OptimizerFactory.HiLoOptimizer optimizer = ( OptimizerFactory.HiLoOptimizer ) generator.getOptimizer(); + + int increment = optimizer.getIncrementSize(); + Entity[] entities = new Entity[ increment + 1 ]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < increment; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + assertEquals( 1, generator.getDatabaseStructure().getTimesAccessed() ); // initialization + assertEquals( 1, optimizer.getLastSourceValue() ); // initialization + assertEquals( i + 1, optimizer.getLastValue() ); + assertEquals( increment + 1, optimizer.getHiValue() ); + } + // now force a "clock over" + entities[ increment ] = new Entity( "" + increment ); + s.save( entities[ increment ] ); + assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization + assertEquals( 2, optimizer.getLastSourceValue() ); // initialization + assertEquals( increment + 1, optimizer.getLastValue() ); + assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() ); + + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < entities.length; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml b/test/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml new file mode 100644 index 0000000000..d2029d367c --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + ID_SEQ_POOL_SEQ + 1 + 10 + pooled + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java b/test/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java new file mode 100644 index 0000000000..a17cff9009 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java @@ -0,0 +1,65 @@ +package org.hibernate.test.idgen.enhanced.sequence; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class PooledSequenceTest extends FunctionalTestCase { + public PooledSequenceTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/sequence/Pooled.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PooledSequenceTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() ); + SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator(); + assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() ); + OptimizerFactory.PooledOptimizer optimizer = ( OptimizerFactory.PooledOptimizer ) generator.getOptimizer(); + + int increment = optimizer.getIncrementSize(); + Entity[] entities = new Entity[ increment + 1 ]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < increment; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization calls seq twice + assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls seq twice + assertEquals( i + 1, optimizer.getLastValue() ); + assertEquals( increment + 1, optimizer.getLastSourceValue() ); + } + // now force a "clock over" + entities[ increment ] = new Entity( "" + increment ); + s.save( entities[ increment ] ); + assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); // initialization (2) + clock over + assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over + assertEquals( increment + 1, optimizer.getLastValue() ); + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < entities.length; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml b/test/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml new file mode 100644 index 0000000000..4b4a12a16e --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + ID_TBL_BSC_TBL + test + 1 + 1 + none + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java b/test/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java new file mode 100644 index 0000000000..51d2f4907c --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java @@ -0,0 +1,57 @@ +package org.hibernate.test.idgen.enhanced.table; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.id.enhanced.TableGenerator; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class BasicTableTest extends FunctionalTestCase { + public BasicTableTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/table/Basic.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BasicTableTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( TableGenerator.class, persister.getIdentifierGenerator().getClass() ); + TableGenerator generator = ( TableGenerator ) persister.getIdentifierGenerator(); + + int count = 5; + Entity[] entities = new Entity[count]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < count; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + long expectedId = i + 1; + assertEquals( expectedId, entities[i].getId().longValue() ); + assertEquals( expectedId, generator.getTableAccessCount() ); + assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() ); + } + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < count; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/table/Entity.java b/test/org/hibernate/test/idgen/enhanced/table/Entity.java new file mode 100644 index 0000000000..c23942101d --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/table/Entity.java @@ -0,0 +1,34 @@ +package org.hibernate.test.idgen.enhanced.table; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Entity { + private Long id; + private String name; + + public Entity() { + } + + public Entity(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml b/test/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml new file mode 100644 index 0000000000..f4f1590f59 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + ID_TBL_HILO_TBL + test + 1 + 10 + hilo + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java b/test/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java new file mode 100644 index 0000000000..1fcc90d579 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java @@ -0,0 +1,67 @@ +package org.hibernate.test.idgen.enhanced.table; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.TableGenerator; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class HiLoTableTest extends FunctionalTestCase { + public HiLoTableTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/table/HiLo.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( HiLoTableTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( TableGenerator.class, persister.getIdentifierGenerator().getClass() ); + TableGenerator generator = ( TableGenerator ) persister.getIdentifierGenerator(); + assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() ); + OptimizerFactory.HiLoOptimizer optimizer = ( OptimizerFactory.HiLoOptimizer ) generator.getOptimizer(); + + int increment = optimizer.getIncrementSize(); + Entity[] entities = new Entity[ increment + 1 ]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < increment; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + assertEquals( 1, generator.getTableAccessCount() ); // initialization + assertEquals( 1, optimizer.getLastSourceValue() ); // initialization + assertEquals( i + 1, optimizer.getLastValue() ); + assertEquals( increment + 1, optimizer.getHiValue() ); + } + // now force a "clock over" + entities[ increment ] = new Entity( "" + increment ); + s.save( entities[ increment ] ); + assertEquals( 2, generator.getTableAccessCount() ); // initialization + assertEquals( 2, optimizer.getLastSourceValue() ); // initialization + assertEquals( increment + 1, optimizer.getLastValue() ); + assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() ); + + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < entities.length; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml b/test/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml new file mode 100644 index 0000000000..a2d1a9b477 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + ID_TBL_POOL_TBL + test + 1 + 10 + pooled + + + + + + diff --git a/test/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java b/test/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java new file mode 100644 index 0000000000..75891dcad7 --- /dev/null +++ b/test/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java @@ -0,0 +1,65 @@ +package org.hibernate.test.idgen.enhanced.table; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.hibernate.id.enhanced.TableGenerator; +import org.hibernate.Session; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class PooledTableTest extends FunctionalTestCase { + public PooledTableTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "idgen/enhanced/table/Pooled.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( PooledTableTest.class ); + } + + public void testNormalBoundary() { + EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() ); + assertClassAssignability( TableGenerator.class, persister.getIdentifierGenerator().getClass() ); + TableGenerator generator = ( TableGenerator ) persister.getIdentifierGenerator(); + assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() ); + OptimizerFactory.PooledOptimizer optimizer = ( OptimizerFactory.PooledOptimizer ) generator.getOptimizer(); + + int increment = optimizer.getIncrementSize(); + Entity[] entities = new Entity[ increment + 1 ]; + Session s = openSession(); + s.beginTransaction(); + for ( int i = 0; i < increment; i++ ) { + entities[i] = new Entity( "" + ( i + 1 ) ); + s.save( entities[i] ); + assertEquals( 2, generator.getTableAccessCount() ); // initialization calls seq twice + assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls seq twice + assertEquals( i + 1, optimizer.getLastValue() ); + assertEquals( increment + 1, optimizer.getLastSourceValue() ); + } + // now force a "clock over" + entities[ increment ] = new Entity( "" + increment ); + s.save( entities[ increment ] ); + assertEquals( 3, generator.getTableAccessCount() ); // initialization (2) + clock over + assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over + assertEquals( increment + 1, optimizer.getLastValue() ); + s.getTransaction().commit(); + + s.beginTransaction(); + for ( int i = 0; i < entities.length; i++ ) { + assertEquals( i + 1, entities[i].getId().intValue() ); + s.delete( entities[i] ); + } + s.getTransaction().commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java b/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java new file mode 100644 index 0000000000..812783d3d7 --- /dev/null +++ b/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java @@ -0,0 +1,187 @@ +package org.hibernate.test.idprops; + +import junit.framework.Test; + +import org.hibernate.Criteria; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.criterion.Projections; +import org.hibernate.criterion.Restrictions; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class IdentifierPropertyReferencesTest extends FunctionalTestCase { + public IdentifierPropertyReferencesTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "idprops/Mapping.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( IdentifierPropertyReferencesTest.class ); + } + + public void testHqlIdPropertyReferences() { + Session s = openSession(); + s.beginTransaction(); + Person p = new Person( new Long(1), "steve", 123 ); + s.save( p ); + Order o = new Order( new Long(1), p ); + LineItem l = new LineItem( o, "my-product", 2 ); + l.setId( "456" ); + s.save( o ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + + long count = extractCount( s, "select count(*) from Person p where p.id = 123" ); + assertEquals( "Person by id prop (non-identifier)", 1, count ); + count = extractCount( s, "select count(*) from Person p where p.pk = 1" ); + assertEquals( "Person by pk prop (identifier)", 1, count ); + + count = extractCount( s, "select count(*) from Order o where o.id = 1" ); + assertEquals( "Order by number prop (named identifier)", 1, count ); + count = extractCount( s, "select count(*) from Order o where o.number = 1" ); + assertEquals( "Order by id prop (virtual identifier)", 1, count ); + + count = extractCount( s, "select count(*) from LineItem l where l.id = '456'" ); + assertEquals( "LineItem by id prop (non-identifier", 1, count ); + + if ( getDialect().supportsRowValueConstructorSyntax() ) { + Query q = s.createQuery( "select count(*) from LineItem l where l.pk = (:order, :product)" ) + .setEntity( "order", o ) + .setString( "product", "my-product" ); + count = extractCount( q ); + assertEquals( "LineItem by pk prop (named composite identifier", 1, count ); + } + + count = extractCount( s, "select count(*) from Order o where o.orderee.id = 1" ); + assertEquals( 0, count ); + count = extractCount( s, "select count(*) from Order o where o.orderee.pk = 1" ); + assertEquals( 1, count ); + count = extractCount( s, "select count(*) from Order o where o.orderee.id = 123" ); + assertEquals( 1, count ); + + count = extractCount( s, "select count(*) from LineItem l where l.pk.order.id = 1" ); + assertEquals( 1, count ); + count = extractCount( s, "select count(*) from LineItem l where l.pk.order.number = 1" ); + assertEquals( 1, count ); + count = extractCount( s, "select count(*) from LineItem l where l.pk.order.orderee.pk = 1" ); + assertEquals( 1, count ); + + s.delete( o ); + s.delete( p ); + s.getTransaction().commit(); + s.close(); + } + + public void testCriteriaIdPropertyReferences() { + Session s = openSession(); + s.beginTransaction(); + Person p = new Person( new Long(1), "steve", 123 ); + s.save( p ); + Order o = new Order( new Long(1), p ); + LineItem l = new LineItem( o, "my-product", 2 ); + l.setId( "456" ); + s.save( o ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + + Criteria crit = s.createCriteria( Person.class ); + crit.setProjection( Projections.rowCount() ); + crit.add( Restrictions.eq( "id", new Integer(123) ) ); + long count = extractCount( crit ); + assertEquals( "Person by id prop (non-identifier)", 1, count ); + + crit = s.createCriteria( Person.class ); + crit.setProjection( Projections.rowCount() ); + crit.add( Restrictions.eq( "pk", new Long(1) ) ); + count = extractCount( crit ); + assertEquals( "Person by pk prop (identifier)", 1, count ); + + crit = s.createCriteria( Order.class ); + crit.setProjection( Projections.rowCount() ); + crit.add( Restrictions.eq( "number", new Long(1) ) ); + count = extractCount( crit ); + assertEquals( "Order by number prop (named identifier)", 1, count ); + + crit = s.createCriteria( Order.class ); + crit.setProjection( Projections.rowCount() ); + crit.add( Restrictions.eq( "id", new Long(1) ) ); + count = extractCount( crit ); + assertEquals( "Order by id prop (virtual identifier)", 1, count ); + + crit = s.createCriteria( LineItem.class ); + crit.setProjection( Projections.rowCount() ); + crit.add( Restrictions.eq( "id", "456" ) ); + count = extractCount( crit ); + assertEquals( "LineItem by id prop (non-identifier", 1, count ); + + if ( getDialect().supportsRowValueConstructorSyntax() ) { + crit = s.createCriteria( LineItem.class ); + crit.setProjection( Projections.rowCount() ); + crit.add( Restrictions.eq( "pk", new LineItemPK( o, "my-product" ) ) ); + count = extractCount( crit ); + assertEquals( "LineItem by pk prop (named composite identifier)", 1, count ); + } + + crit = s.createCriteria( Order.class ); + crit.setProjection( Projections.rowCount() ); + crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.id", new Integer(1) ) ); + count = extractCount( crit ); + assertEquals( 0, count ); + + crit = s.createCriteria( Order.class ); + crit.setProjection( Projections.rowCount() ); + crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.pk", new Long(1) ) ); + count = extractCount( crit ); + assertEquals( 1, count ); + + crit = s.createCriteria( Order.class ); + crit.setProjection( Projections.rowCount() ); + crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.id", new Integer(123) ) ); + count = extractCount( crit ); + assertEquals( 1, count ); + + crit = s.createCriteria( LineItem.class ); + crit.setProjection( Projections.rowCount() ); + crit.add( Restrictions.eq( "pk.order.id", new Long(1) ) ); + count = extractCount( crit ); + assertEquals( 1, count ); + + crit = s.createCriteria( LineItem.class ); + crit.setProjection( Projections.rowCount() ); + crit.add( Restrictions.eq( "pk.order.number", new Long(1) ) ); + count = extractCount( crit ); + assertEquals( 1, count ); + + s.delete( o ); + s.delete( p ); + s.getTransaction().commit(); + s.close(); + } + + private long extractCount(Session s, String hql) { + return extractCount( s.createQuery( hql ) ); + } + + private long extractCount(Query query) { + return ( ( Long ) query.list().get( 0 ) ).longValue(); + } + + private long extractCount(Criteria crit) { + return ( ( Integer ) crit.list().get( 0 ) ).intValue(); + } +} diff --git a/test/org/hibernate/test/idprops/LineItem.java b/test/org/hibernate/test/idprops/LineItem.java new file mode 100644 index 0000000000..75899725b5 --- /dev/null +++ b/test/org/hibernate/test/idprops/LineItem.java @@ -0,0 +1,49 @@ +package org.hibernate.test.idprops; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class LineItem { + private LineItemPK pk; + private int quantity; + private String id; + + public LineItem() { + } + + public LineItem(LineItemPK pk, int quantity) { + this.pk = pk; + this.quantity = quantity; + this.pk.getOrder().getLineItems().add( this ); + } + + public LineItem(Order order, String productCode, int quantity) { + this( new LineItemPK( order, productCode ), quantity ); + } + + public LineItemPK getPk() { + return pk; + } + + public void setPk(LineItemPK pk) { + this.pk = pk; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/test/org/hibernate/test/idprops/LineItemPK.java b/test/org/hibernate/test/idprops/LineItemPK.java new file mode 100644 index 0000000000..4a3a6ecb3b --- /dev/null +++ b/test/org/hibernate/test/idprops/LineItemPK.java @@ -0,0 +1,64 @@ +package org.hibernate.test.idprops; + +import java.io.Serializable; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class LineItemPK implements Serializable { + private Order order; + private String productCode; + + public LineItemPK() { + } + + public LineItemPK(Order order, String productCode) { + this.order = order; + this.productCode = productCode; + } + + public Order getOrder() { + return order; + } + + public void setOrder(Order order) { + this.order = order; + } + + public String getProductCode() { + return productCode; + } + + public void setProductCode(String productCode) { + this.productCode = productCode; + } + + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + LineItemPK that = ( LineItemPK ) o; + + if ( !order.equals( that.order ) ) { + return false; + } + if ( !productCode.equals( that.productCode ) ) { + return false; + } + + return true; + } + + public int hashCode() { + int result; + result = order.hashCode(); + result = 31 * result + productCode.hashCode(); + return result; + } +} diff --git a/test/org/hibernate/test/idprops/Mapping.hbm.xml b/test/org/hibernate/test/idprops/Mapping.hbm.xml new file mode 100644 index 0000000000..0ce4be8e76 --- /dev/null +++ b/test/org/hibernate/test/idprops/Mapping.hbm.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/idprops/Order.java b/test/org/hibernate/test/idprops/Order.java new file mode 100644 index 0000000000..ed463ae2d9 --- /dev/null +++ b/test/org/hibernate/test/idprops/Order.java @@ -0,0 +1,60 @@ +package org.hibernate.test.idprops; + +import java.util.Date; +import java.util.Set; +import java.util.HashSet; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Order { + private Long number; + private Date placed; + private Person orderee; + + private Set lineItems = new HashSet(); + + public Order() { + } + + public Order(Long number, Person orderee) { + this.number = number; + this.orderee = orderee; + this.placed = new Date(); + } + + public Long getNumber() { + return number; + } + + public void setNumber(Long number) { + this.number = number; + } + + public Date getPlaced() { + return placed; + } + + public void setPlaced(Date placed) { + this.placed = placed; + } + + public Person getOrderee() { + return orderee; + } + + public void setOrderee(Person orderee) { + this.orderee = orderee; + } + + + public Set getLineItems() { + return lineItems; + } + + public void setLineItems(Set lineItems) { + this.lineItems = lineItems; + } +} diff --git a/test/org/hibernate/test/idprops/Person.java b/test/org/hibernate/test/idprops/Person.java new file mode 100644 index 0000000000..8f4e752d8a --- /dev/null +++ b/test/org/hibernate/test/idprops/Person.java @@ -0,0 +1,45 @@ +package org.hibernate.test.idprops; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Person { + private Long pk; + private String name; + private int id; + + public Person() { + } + + public Person(Long pk, String name, int id) { + this.pk = pk; + this.name = name; + this.id = id; + } + + public Long getPk() { + return pk; + } + + public void setPk(Long pk) { + this.pk = pk; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } +} diff --git a/test/org/hibernate/test/immutable/Contract.java b/test/org/hibernate/test/immutable/Contract.java new file mode 100755 index 0000000000..8cd5c10fab --- /dev/null +++ b/test/org/hibernate/test/immutable/Contract.java @@ -0,0 +1,57 @@ +//$Id$ +package org.hibernate.test.immutable; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class Contract implements Serializable { + + private long id; + private String customerName; + private String type; + private List variations; + + public Contract() { + super(); + } + + public Contract(String customerName, String type) { + this.customerName = customerName; + this.type = type; + variations = new ArrayList(); + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName(String customerName) { + this.customerName = customerName; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public List getVariations() { + return variations; + } + + public void setVariations(List variations) { + this.variations = variations; + } + +} diff --git a/test/org/hibernate/test/immutable/ContractVariation.hbm.xml b/test/org/hibernate/test/immutable/ContractVariation.hbm.xml new file mode 100755 index 0000000000..a117028b29 --- /dev/null +++ b/test/org/hibernate/test/immutable/ContractVariation.hbm.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/immutable/ContractVariation.java b/test/org/hibernate/test/immutable/ContractVariation.java new file mode 100755 index 0000000000..56a504e4ae --- /dev/null +++ b/test/org/hibernate/test/immutable/ContractVariation.java @@ -0,0 +1,45 @@ +//$Id$ +package org.hibernate.test.immutable; + +import java.io.Serializable; + +public class ContractVariation implements Serializable { + + private int version; + private Contract contract; + private String text; + + public Contract getContract() { + return contract; + } + + public void setContract(Contract contract) { + this.contract = contract; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public ContractVariation() { + super(); + } + + public ContractVariation(int version, Contract contract) { + this.contract = contract; + this.version = version; + contract.getVariations().add(this); + } +} diff --git a/test/org/hibernate/test/immutable/ImmutableTest.java b/test/org/hibernate/test/immutable/ImmutableTest.java new file mode 100755 index 0000000000..3c75cc155b --- /dev/null +++ b/test/org/hibernate/test/immutable/ImmutableTest.java @@ -0,0 +1,66 @@ +//$Id$ +package org.hibernate.test.immutable; + +import junit.framework.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.criterion.Projections; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class ImmutableTest extends FunctionalTestCase { + + public ImmutableTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "immutable/ContractVariation.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ImmutableTest.class ); + } + + public void testImmutable() { + Contract c = new Contract("gavin", "phone"); + ContractVariation cv1 = new ContractVariation(1, c); + cv1.setText("expensive"); + ContractVariation cv2 = new ContractVariation(2, c); + cv2.setText("more expensive"); + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.persist(c); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + c.setCustomerName("foo bar"); + c.getVariations().add( new ContractVariation(3, c) ); + cv1 = (ContractVariation) c.getVariations().iterator().next(); + cv1.setText("blah blah"); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + c = (Contract) s.createCriteria(Contract.class).uniqueResult(); + assertEquals( c.getCustomerName(), "gavin" ); + assertEquals( c.getVariations().size(), 2 ); + cv1 = (ContractVariation) c.getVariations().iterator().next(); + assertEquals( cv1.getText(), "expensive" ); + s.delete(c); + assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Integer(0) ); + assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Integer(0) ); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/insertordering/Group.java b/test/org/hibernate/test/insertordering/Group.java new file mode 100644 index 0000000000..0905ae6744 --- /dev/null +++ b/test/org/hibernate/test/insertordering/Group.java @@ -0,0 +1,29 @@ +package org.hibernate.test.insertordering; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Group { + private Long id; + private String name; + + /** + * for persistence + */ + Group() { + } + + public Group(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/test/org/hibernate/test/insertordering/InsertOrderingTest.java b/test/org/hibernate/test/insertordering/InsertOrderingTest.java new file mode 100644 index 0000000000..e28c72896a --- /dev/null +++ b/test/org/hibernate/test/insertordering/InsertOrderingTest.java @@ -0,0 +1,127 @@ +package org.hibernate.test.insertordering; + +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.sql.SQLException; +import java.sql.PreparedStatement; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.Session; +import org.hibernate.Interceptor; +import org.hibernate.HibernateException; +import org.hibernate.jdbc.BatchingBatcher; +import org.hibernate.jdbc.ConnectionManager; +import org.hibernate.jdbc.Expectation; +import org.hibernate.jdbc.BatcherFactory; +import org.hibernate.jdbc.Batcher; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class InsertOrderingTest extends FunctionalTestCase { + public InsertOrderingTest(String string) { + super( string ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( InsertOrderingTest.class ); + } + + public String[] getMappings() { + return new String[] { "insertordering/Mapping.hbm.xml" }; + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.ORDER_INSERTS, "true" ); + cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "10" ); + cfg.setProperty( Environment.BATCH_STRATEGY, StatsBatcherFactory.class.getName() ); + } + + public void testBatchOrdering() { + Session s = openSession(); + s.beginTransaction(); + int iterations = 12; + for ( int i = 0; i < iterations; i++ ) { + User user = new User( "user-" + i ); + Group group = new Group( "group-" + i ); + s.save( user ); + s.save( group ); + user.addMembership( group ); + } + StatsBatcher.reset(); + s.getTransaction().commit(); + s.close(); + + assertEquals( 6, StatsBatcher.batchSizes.size() ); // 2 batches of each insert statement + + s = openSession(); + s.beginTransaction(); + Iterator users = s.createQuery( "from User u left join fetch u.memberships m left join fetch m.group" ).list().iterator(); + while ( users.hasNext() ) { + s.delete( users.next() ); + } + s.getTransaction().commit(); + s.close(); + } + + public static class Counter { + public int count = 0; + } + + public static class StatsBatcher extends BatchingBatcher { + private static String batchSQL; + private static List batchSizes = new ArrayList(); + private static int currentBatch = -1; + + public StatsBatcher(ConnectionManager connectionManager, Interceptor interceptor) { + super( connectionManager, interceptor ); + } + + static void reset() { + batchSizes = new ArrayList(); + currentBatch = -1; + batchSQL = null; + } + + public PreparedStatement prepareBatchStatement(String sql) throws SQLException { + PreparedStatement rtn = super.prepareBatchStatement( sql ); + if ( batchSQL == null || !batchSQL.equals( sql ) ) { + currentBatch++; + batchSQL = sql; + batchSizes.add( currentBatch, new Counter() ); + System.out.println( "--------------------------------------------------------" ); + System.out.println( "Preparing statement [" + sql + "]" ); + } + return rtn; + } + + public void addToBatch(Expectation expectation) throws SQLException, HibernateException { + Counter counter = ( Counter ) batchSizes.get( currentBatch ); + counter.count++; + System.out.println( "Adding to batch [" + batchSQL + "]" ); + super.addToBatch( expectation ); + } + + protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException { + System.out.println( "executing batch [" + batchSQL + "]" ); + System.out.println( "--------------------------------------------------------" ); + batchSQL = null; + super.doExecuteBatch( ps ); + } + } + + public static class StatsBatcherFactory implements BatcherFactory { + public Batcher createBatcher(ConnectionManager connectionManager, Interceptor interceptor) { + return new StatsBatcher( connectionManager, interceptor ); + } + } +} diff --git a/test/org/hibernate/test/insertordering/Mapping.hbm.xml b/test/org/hibernate/test/insertordering/Mapping.hbm.xml new file mode 100644 index 0000000000..d75187906b --- /dev/null +++ b/test/org/hibernate/test/insertordering/Mapping.hbm.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/insertordering/Membership.java b/test/org/hibernate/test/insertordering/Membership.java new file mode 100644 index 0000000000..84cddef286 --- /dev/null +++ b/test/org/hibernate/test/insertordering/Membership.java @@ -0,0 +1,47 @@ +package org.hibernate.test.insertordering; + +import java.util.Date; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Membership { + private Long id; + private User user; + private Group group; + private Date activationDate; + + /** + * For persistence + */ + Membership() { + } + + public Membership(User user, Group group) { + this( user, group, new Date() ); + } + + public Membership(User user, Group group, Date activationDate) { + this.user = user; + this.group = group; + this.activationDate = activationDate; + } + + public Long getId() { + return id; + } + + public User getUser() { + return user; + } + + public Group getGroup() { + return group; + } + + public Date getActivationDate() { + return activationDate; + } +} diff --git a/test/org/hibernate/test/insertordering/User.java b/test/org/hibernate/test/insertordering/User.java new file mode 100644 index 0000000000..dc8c8cbc44 --- /dev/null +++ b/test/org/hibernate/test/insertordering/User.java @@ -0,0 +1,44 @@ +package org.hibernate.test.insertordering; + +import java.util.Set; +import java.util.HashSet; +import java.util.Iterator; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class User { + private Long id; + private String username; + private Set memberships = new HashSet(); + + /** + * for persistence + */ + User() { + } + + public User(String username) { + this.username = username; + } + + public Long getId() { + return id; + } + + public String getUsername() { + return username; + } + + public Iterator getMemberships() { + return memberships.iterator(); + } + + public Membership addMembership(Group group) { + Membership membership = new Membership( this, group ); + memberships.add( membership ); + return membership; + } +} diff --git a/test/org/hibernate/test/instrument/buildtime/InstrumentTest.java b/test/org/hibernate/test/instrument/buildtime/InstrumentTest.java new file mode 100755 index 0000000000..f88f534f2a --- /dev/null +++ b/test/org/hibernate/test/instrument/buildtime/InstrumentTest.java @@ -0,0 +1,88 @@ +//$Id$ +package org.hibernate.test.instrument.buildtime; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.hibernate.intercept.FieldInterceptionHelper; +import org.hibernate.test.instrument.domain.Document; +import org.hibernate.test.instrument.cases.TestDirtyCheckExecutable; +import org.hibernate.test.instrument.cases.TestFetchAllExecutable; +import org.hibernate.test.instrument.cases.TestLazyExecutable; +import org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable; +import org.hibernate.test.instrument.cases.TestInjectFieldInterceptorExecutable; +import org.hibernate.test.instrument.cases.TestIsPropertyInitializedExecutable; +import org.hibernate.test.instrument.cases.TestLazyPropertyCustomTypeExecutable; +import org.hibernate.test.instrument.cases.TestManyToOneProxyExecutable; +import org.hibernate.test.instrument.cases.Executable; +import org.hibernate.junit.UnitTestCase; + +/** + * @author Gavin King + */ +public class InstrumentTest extends UnitTestCase { + + public InstrumentTest(String str) { + super(str); + } + + public static Test suite() { + return new TestSuite( InstrumentTest.class ); + } + + public void testDirtyCheck() { + execute( new TestDirtyCheckExecutable() ); + } + + public void testFetchAll() throws Exception { + execute( new TestFetchAllExecutable() ); + } + + public void testLazy() throws Exception { + execute( new TestLazyExecutable() ); + } + + public void testLazyManyToOne() { + execute( new TestLazyManyToOneExecutable() ); + } + + public void testSetFieldInterceptor() { + execute( new TestInjectFieldInterceptorExecutable() ); + } + + public void testPropertyInitialized() { + execute( new TestIsPropertyInitializedExecutable() ); + } + + public void testManyToOneProxy() { + execute( new TestManyToOneProxyExecutable() ); + } + + public void testLazyPropertyCustomTypeExecutable() { + execute( new TestLazyPropertyCustomTypeExecutable() ); + } + + private void execute(Executable executable) { + executable.prepare(); + try { + executable.execute(); + } + finally { + executable.complete(); + } + } + + protected void runTest() throws Throwable { + if ( isRunnable() ) { + super.runTest(); + } + else { + reportSkip( "domain classes not instrumented", "build-time instrumentation" ); + } + } + + public static boolean isRunnable() { + return FieldInterceptionHelper.isInstrumented( new Document() ); + } +} + diff --git a/test/org/hibernate/test/instrument/cases/AbstractExecutable.java b/test/org/hibernate/test/instrument/cases/AbstractExecutable.java new file mode 100644 index 0000000000..87f006dd88 --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/AbstractExecutable.java @@ -0,0 +1,42 @@ +package org.hibernate.test.instrument.cases; + +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractExecutable implements Executable { + + private SessionFactory factory; + + public final void prepare() { + Configuration cfg = new Configuration().setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); + String[] resources = getResources(); + for ( int i = 0; i < resources.length; i++ ) { + cfg.addResource( resources[i] ); + } + factory = cfg.buildSessionFactory(); + } + + public final void complete() { + try { + cleanup(); + } + finally { + factory.close(); + } + } + + protected SessionFactory getFactory() { + return factory; + } + + protected void cleanup() { + } + + protected String[] getResources() { + return new String[] { "org/hibernate/test/instrument/domain/Documents.hbm.xml" }; + } +} diff --git a/test/org/hibernate/test/instrument/cases/Executable.java b/test/org/hibernate/test/instrument/cases/Executable.java new file mode 100644 index 0000000000..c899f2907d --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/Executable.java @@ -0,0 +1,10 @@ +package org.hibernate.test.instrument.cases; + +/** + * @author Steve Ebersole + */ +public interface Executable { + public void prepare(); + public void execute(); + public void complete(); +} diff --git a/test/org/hibernate/test/instrument/cases/TestDirtyCheckExecutable.java b/test/org/hibernate/test/instrument/cases/TestDirtyCheckExecutable.java new file mode 100644 index 0000000000..a0be1f9bdd --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/TestDirtyCheckExecutable.java @@ -0,0 +1,49 @@ +package org.hibernate.test.instrument.cases; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.test.instrument.domain.Folder; + +import java.util.List; +import java.util.Iterator; + +import junit.framework.Assert; + +/** + * @author Steve Ebersole + */ +public class TestDirtyCheckExecutable extends AbstractExecutable { + public void execute() { + Session s = getFactory().openSession(); + Transaction t = s.beginTransaction(); + Folder pics = new Folder(); + pics.setName("pics"); + Folder docs = new Folder(); + docs.setName("docs"); + s.persist(docs); + s.persist(pics); + t.commit(); + s.close(); + + s = getFactory().openSession(); + t = s.beginTransaction(); + List list = s.createCriteria(Folder.class).list(); + for ( Iterator iter = list.iterator(); iter.hasNext(); ) { + Folder f = (Folder) iter.next(); + Assert.assertFalse( f.nameWasread ); + } + t.commit(); + s.close(); + + for ( Iterator iter = list.iterator(); iter.hasNext(); ) { + Folder f = (Folder) iter.next(); + Assert.assertFalse( f.nameWasread ); + } + + s = getFactory().openSession(); + t = s.beginTransaction(); + s.createQuery("delete from Folder").executeUpdate(); + t.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/instrument/cases/TestFetchAllExecutable.java b/test/org/hibernate/test/instrument/cases/TestFetchAllExecutable.java new file mode 100644 index 0000000000..f7c280e433 --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/TestFetchAllExecutable.java @@ -0,0 +1,47 @@ +package org.hibernate.test.instrument.cases; + +import org.hibernate.Session; +import org.hibernate.Hibernate; +import org.hibernate.Transaction; +import org.hibernate.test.instrument.domain.Owner; +import org.hibernate.test.instrument.domain.Document; +import org.hibernate.test.instrument.domain.Folder; +import junit.framework.Assert; + +/** + * @author Steve Ebersole + */ +public class TestFetchAllExecutable extends AbstractExecutable { + public void execute() { + Session s = getFactory().openSession(); + Transaction t = s.beginTransaction(); + Owner o = new Owner(); + Document doc = new Document(); + Folder fol = new Folder(); + o.setName("gavin"); + doc.setName("Hibernate in Action"); + doc.setSummary("blah"); + doc.updateText("blah blah"); + fol.setName("books"); + doc.setOwner(o); + doc.setFolder(fol); + fol.getDocuments().add(doc); + s.persist(o); + s.persist(fol); + t.commit(); + s.close(); + + s = getFactory().openSession(); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document fetch all properties").uniqueResult(); + Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) ); + Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "upperCaseName" ) ); + Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "owner" ) ); + Assert.assertEquals( doc.getSummary(), "blah" ); + s.delete(doc); + s.delete( doc.getOwner() ); + s.delete( doc.getFolder() ); + t.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/instrument/cases/TestInjectFieldInterceptorExecutable.java b/test/org/hibernate/test/instrument/cases/TestInjectFieldInterceptorExecutable.java new file mode 100644 index 0000000000..f089f39537 --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/TestInjectFieldInterceptorExecutable.java @@ -0,0 +1,17 @@ +package org.hibernate.test.instrument.cases; + +import org.hibernate.test.instrument.domain.Document; +import org.hibernate.intercept.FieldInterceptionHelper; + +import java.util.HashSet; + +/** + * @author Steve Ebersole + */ +public class TestInjectFieldInterceptorExecutable extends AbstractExecutable { + public void execute() { + Document doc = new Document(); + FieldInterceptionHelper.injectFieldInterceptor( doc, "Document", new HashSet(), null ); + doc.getId(); + } +} diff --git a/test/org/hibernate/test/instrument/cases/TestIsPropertyInitializedExecutable.java b/test/org/hibernate/test/instrument/cases/TestIsPropertyInitializedExecutable.java new file mode 100644 index 0000000000..363f6d1d87 --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/TestIsPropertyInitializedExecutable.java @@ -0,0 +1,48 @@ +//$Id: $ +package org.hibernate.test.instrument.cases; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.Hibernate; +import org.hibernate.test.instrument.domain.Owner; +import org.hibernate.test.instrument.domain.Document; +import org.hibernate.test.instrument.domain.Folder; +import junit.framework.Assert; + +/** + * @author Steve Ebersole + */ +public class TestIsPropertyInitializedExecutable extends AbstractExecutable { + public void execute() { + Session s = getFactory().openSession(); + Transaction t = s.beginTransaction(); + Owner o = new Owner(); + Document doc = new Document(); + Folder fol = new Folder(); + o.setName("gavin"); + doc.setName("Hibernate in Action"); + doc.setSummary("blah"); + doc.updateText("blah blah"); + fol.setName("books"); + doc.setOwner(o); + doc.setFolder(fol); + fol.getDocuments().add(doc); + Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) ); + s.persist(o); + s.persist(fol); + t.commit(); + s.close(); + + s = getFactory().openSession(); + t = s.beginTransaction(); + doc = (Document) s.get( Document.class, doc.getId() ); + Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "summary" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "upperCaseName" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "owner" ) ); + s.delete(doc); + s.delete( doc.getOwner() ); + s.delete( doc.getFolder() ); + t.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/instrument/cases/TestLazyExecutable.java b/test/org/hibernate/test/instrument/cases/TestLazyExecutable.java new file mode 100644 index 0000000000..23b1df4a6f --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/TestLazyExecutable.java @@ -0,0 +1,197 @@ +package org.hibernate.test.instrument.cases; + +import org.hibernate.test.TestCase; +import org.hibernate.test.instrument.cases.AbstractExecutable; +import org.hibernate.test.instrument.domain.Owner; +import org.hibernate.test.instrument.domain.Document; +import org.hibernate.test.instrument.domain.Folder; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.Hibernate; +import org.hibernate.LockMode; +import org.hibernate.CacheMode; +import org.hibernate.SessionFactory; + +/** + * @author Steve Ebersole + */ +public class TestLazyExecutable extends AbstractExecutable { + public void execute() { + SessionFactory factory = getFactory(); + Session s = factory.openSession(); + Transaction t = s.beginTransaction(); + Owner o = new Owner(); + Document doc = new Document(); + Folder fol = new Folder(); + o.setName("gavin"); + doc.setName("Hibernate in Action"); + doc.setSummary("blah"); + doc.updateText("blah blah"); + fol.setName("books"); + doc.setOwner(o); + doc.setFolder(fol); + fol.getDocuments().add(doc); + s.save(o); + s.save(fol); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = ( Document ) s.get( Document.class, doc.getId() ); + TestCase.assertTrue( Hibernate.isPropertyInitialized(doc, "weirdProperty")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "name")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "upperCaseName")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "folder")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "owner")); + doc.getUpperCaseName(); // should force initialization + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "upperCaseName")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "folder")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "owner")); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + doc.getName(); + TestCase.assertEquals( doc.getText(), "blah blah" ); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + doc.getName(); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "summary")); + TestCase.assertEquals( doc.getText(), "blah blah" ); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "summary")); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + doc.setName("HiA"); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + TestCase.assertEquals( doc.getName(), "HiA" ); + TestCase.assertEquals( doc.getText(), "blah blah" ); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + doc.getText(); + doc.setName("HiA second edition"); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "name")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "upperCaseName")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "owner")); + TestCase.assertEquals( doc.getName(), "HiA second edition" ); + TestCase.assertEquals( doc.getText(), "blah blah" ); + TestCase.assertEquals( doc.getUpperCaseName(), "HIA SECOND EDITION" ); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty")); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "upperCaseName")); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + t.commit(); + s.close(); + + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text")); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + s.lock(doc, LockMode.NONE); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertEquals( doc.getText(), "blah blah" ); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text")); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + t.commit(); + s.close(); + + doc.setName("HiA2"); + + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text")); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + s.saveOrUpdate(doc); + s.flush(); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertEquals( doc.getText(), "blah blah" ); + TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text")); + doc.updateText("blah blah blah blah"); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = ( Document ) s.createQuery("from Document").uniqueResult(); + TestCase.assertEquals( doc.getName(), "HiA2" ); + TestCase.assertEquals( doc.getText(), "blah blah blah blah" ); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.load( Document.class, doc.getId() ); + doc.getName(); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text")); + TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "summary")); + t.commit(); + s.close(); + + s = factory.openSession(); + s.setCacheMode( CacheMode.IGNORE ); + t = s.beginTransaction(); + doc = (Document) s.createQuery("from Document").uniqueResult(); + //s.delete(doc); + s.delete( doc.getFolder() ); + s.delete( doc.getOwner() ); + s.flush(); + t.commit(); + s.close(); + } + +} diff --git a/test/org/hibernate/test/instrument/cases/TestLazyManyToOneExecutable.java b/test/org/hibernate/test/instrument/cases/TestLazyManyToOneExecutable.java new file mode 100644 index 0000000000..5c65eff704 --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/TestLazyManyToOneExecutable.java @@ -0,0 +1,74 @@ +package org.hibernate.test.instrument.cases; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.Hibernate; +import org.hibernate.test.instrument.domain.Owner; +import org.hibernate.test.instrument.domain.Document; +import org.hibernate.test.instrument.domain.Folder; +import org.hibernate.test.instrument.cases.AbstractExecutable; +import junit.framework.Assert; + +/** + * @author Steve Ebersole + */ +public class TestLazyManyToOneExecutable extends AbstractExecutable { + public void execute() { + Session s = getFactory().openSession(); + Transaction t = s.beginTransaction(); + Owner gavin = new Owner(); + Document hia = new Document(); + Folder fol = new Folder(); + gavin.setName("gavin"); + hia.setName("Hibernate in Action"); + hia.setSummary("blah"); + hia.updateText("blah blah"); + fol.setName("books"); + hia.setOwner(gavin); + hia.setFolder(fol); + fol.getDocuments().add(hia); + s.persist(gavin); + s.persist(fol); + t.commit(); + s.close(); + + s = getFactory().openSession(); + t = s.beginTransaction(); + hia = (Document) s.createCriteria(Document.class).uniqueResult(); + Assert.assertEquals( hia.getFolder().getClass(), Folder.class); + fol = hia.getFolder(); + Assert.assertTrue( Hibernate.isInitialized(fol) ); + t.commit(); + s.close(); + + s = getFactory().openSession(); + t = s.beginTransaction(); + hia = (Document) s.createCriteria(Document.class).uniqueResult(); + Assert.assertSame( hia.getFolder(), s.load(Folder.class, fol.getId()) ); + Assert.assertTrue( Hibernate.isInitialized( hia.getFolder() ) ); + t.commit(); + s.close(); + + s = getFactory().openSession(); + t = s.beginTransaction(); + fol = (Folder) s.get(Folder.class, fol.getId()); + hia = (Document) s.createCriteria(Document.class).uniqueResult(); + Assert.assertSame( fol, hia.getFolder() ); + fol = hia.getFolder(); + Assert.assertTrue( Hibernate.isInitialized(fol) ); + t.commit(); + s.close(); + + s = getFactory().openSession(); + t = s.beginTransaction(); + fol = (Folder) s.load(Folder.class, fol.getId()); + hia = (Document) s.createCriteria(Document.class).uniqueResult(); + Assert.assertNotSame( fol, hia.getFolder() ); + fol = hia.getFolder(); + Assert.assertTrue( Hibernate.isInitialized(fol) ); + s.delete(hia.getFolder()); + s.delete(hia.getOwner()); + t.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/instrument/cases/TestLazyPropertyCustomTypeExecutable.java b/test/org/hibernate/test/instrument/cases/TestLazyPropertyCustomTypeExecutable.java new file mode 100644 index 0000000000..749ce3597e --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/TestLazyPropertyCustomTypeExecutable.java @@ -0,0 +1,68 @@ +package org.hibernate.test.instrument.cases; + +import java.util.Iterator; + +import junit.framework.Assert; + +import org.hibernate.Session; +import org.hibernate.intercept.FieldInterceptionHelper; +import org.hibernate.test.instrument.domain.Problematic; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class TestLazyPropertyCustomTypeExecutable extends AbstractExecutable { + + protected String[] getResources() { + return new String[] { "org/hibernate/test/instrument/domain/Problematic.hbm.xml" }; + } + + public void execute() { + Session s = getFactory().openSession(); + s.beginTransaction(); + Problematic p = new Problematic(); + p.setName( "whatever" ); + p.setBytes( new byte[] { 1, 0, 1, 1, 0 } ); + s.save( p ); + s.getTransaction().commit(); + s.close(); + + // this access should be ok because p1 is not a lazy proxy + s = getFactory().openSession(); + s.beginTransaction(); + Problematic p1 = (Problematic) s.get( Problematic.class, p.getId() ); + Assert.assertTrue( FieldInterceptionHelper.isInstrumented( p1 ) ); + p1.getRepresentation(); + s.getTransaction().commit(); + s.close(); + + s = getFactory().openSession(); + s.beginTransaction(); + p1 = (Problematic) s.createQuery( "from Problematic" ).setReadOnly(true ).list().get( 0 ); + p1.getRepresentation(); + s.getTransaction().commit(); + s.close(); + + s = getFactory().openSession(); + s.beginTransaction(); + p1 = (Problematic) s.load( Problematic.class, p.getId() ); + Assert.assertFalse( FieldInterceptionHelper.isInstrumented( p1 ) ); + p1.setRepresentation( p.getRepresentation() ); + s.getTransaction().commit(); + s.close(); + } + + protected void cleanup() { + Session s = getFactory().openSession(); + s.beginTransaction(); + Iterator itr = s.createQuery( "from Problematic" ).list().iterator(); + while ( itr.hasNext() ) { + Problematic p = (Problematic) itr.next(); + s.delete( p ); + } + s.getTransaction().commit(); + s.close(); + } +} \ No newline at end of file diff --git a/test/org/hibernate/test/instrument/cases/TestManyToOneProxyExecutable.java b/test/org/hibernate/test/instrument/cases/TestManyToOneProxyExecutable.java new file mode 100644 index 0000000000..3d7a279aea --- /dev/null +++ b/test/org/hibernate/test/instrument/cases/TestManyToOneProxyExecutable.java @@ -0,0 +1,67 @@ +package org.hibernate.test.instrument.cases; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.Hibernate; +import org.hibernate.test.instrument.domain.Entity; +import junit.framework.Assert; + +/** + * + * @author Steve Ebersole + */ +public class TestManyToOneProxyExecutable extends AbstractExecutable { + public void execute() { + Session s = getFactory().openSession(); + Transaction t = s.beginTransaction(); + Entity root = new Entity( "root" ); + Entity child1 = new Entity( "child1" ); + Entity child2 = new Entity( "child2" ); + root.setChild( child1 ); + child1.setSibling( child2 ); + Entity gChild1 = new Entity( "grandchild 1" ); + Entity gChild2 = new Entity( "grandchild 2" ); + child1.setChild( gChild1 ); + gChild1.setSibling( gChild2 ); + s.save( root ); + t.commit(); + s.close(); + + // NOTE : child is mapped with lazy="proxy"; sibling with lazy="no-proxy"... + + s = getFactory().openSession(); + t = s.beginTransaction(); + // load root + root = ( Entity ) s.get( Entity.class, root.getId() ); + Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) ); + Assert.assertTrue( Hibernate.isPropertyInitialized( root, "child" ) ); + + // get a handle to the child1 proxy reference (and make certain that + // this does not force the lazy properties of the root entity + // to get initialized. + child1 = root.getChild(); + Assert.assertFalse( Hibernate.isInitialized( child1 ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "name" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "sibling" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "child" ) ); + + child1.getName(); + Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) ); + Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "name" ) ); + Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "sibling" ) ); + Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "child" ) ); + + gChild1 = child1.getChild(); + Assert.assertFalse( Hibernate.isInitialized( gChild1 ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) ); + Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) ); + + s.delete( root ); + t.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/instrument/domain/CustomBlobType.java b/test/org/hibernate/test/instrument/domain/CustomBlobType.java new file mode 100644 index 0000000000..d93813ba2d --- /dev/null +++ b/test/org/hibernate/test/instrument/domain/CustomBlobType.java @@ -0,0 +1,109 @@ +package org.hibernate.test.instrument.domain; + +import java.io.Serializable; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; + +import org.hibernate.HibernateException; +import org.hibernate.Hibernate; +import org.hibernate.usertype.UserType; + +/** + * A simple byte[]-based custom type. + */ +public class CustomBlobType implements UserType { + /** + * {@inheritDoc} + */ + public Object nullSafeGet(ResultSet rs, String names[], Object owner) throws SQLException { + // cast just to make sure... + return ( byte[] ) Hibernate.BINARY.nullSafeGet( rs, names ); + } + + /** + * {@inheritDoc} + */ + public void nullSafeSet(PreparedStatement ps, Object value, int index) throws SQLException, HibernateException { + // cast just to make sure... + Hibernate.BINARY.nullSafeSet( ps, ( byte[] ) value, index ); + } + + /** + * {@inheritDoc} + */ + public Object deepCopy(Object value) { + byte result[] = null; + + if ( value != null ) { + byte bytes[] = ( byte[] ) value; + + result = new byte[bytes.length]; + System.arraycopy( bytes, 0, result, 0, bytes.length ); + } + + return result; + } + + /** + * {@inheritDoc} + */ + public boolean isMutable() { + return true; + } + + /** + * {@inheritDoc} + */ + public int[] sqlTypes() { + return new int[] { Types.VARBINARY }; + } + + /** + * {@inheritDoc} + */ + public Class returnedClass() { + return byte[].class; + } + + /** + * {@inheritDoc} + */ + public boolean equals(Object x, Object y) { + return Arrays.equals( ( byte[] ) x, ( byte[] ) y ); + } + + /** + * {@inheritDoc} + */ + public Object assemble(Serializable arg0, Object arg1) + throws HibernateException { + return null; + } + + /** + * {@inheritDoc} + */ + public Serializable disassemble(Object arg0) + throws HibernateException { + return null; + } + + /** + * {@inheritDoc} + */ + public int hashCode(Object arg0) + throws HibernateException { + return 0; + } + + /** + * {@inheritDoc} + */ + public Object replace(Object arg0, Object arg1, Object arg2) + throws HibernateException { + return null; + } +} \ No newline at end of file diff --git a/test/org/hibernate/test/instrument/domain/Document.java b/test/org/hibernate/test/instrument/domain/Document.java new file mode 100755 index 0000000000..b9d58cb444 --- /dev/null +++ b/test/org/hibernate/test/instrument/domain/Document.java @@ -0,0 +1,110 @@ +//$Id$ +package org.hibernate.test.instrument.domain; + +import java.util.Date; + +/** + * @author Gavin King + */ +public class Document { + private Long id; + private String name; + private String upperCaseName; + private String summary; + private String text; + private Owner owner; + private Folder folder; + private Date lastTextModification = new Date(); + /** + * @return Returns the folder. + */ + public Folder getFolder() { + return folder; + } + /** + * @param folder The folder to set. + */ + public void setFolder(Folder folder) { + this.folder = folder; + } + /** + * @return Returns the owner. + */ + public Owner getOwner() { + return owner; + } + /** + * @param owner The owner to set. + */ + public void setOwner(Owner owner) { + this.owner = owner; + } + /** + * @return Returns the id. + */ + public Long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Long id) { + this.id = id; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + /** + * @return Returns the summary. + */ + public String getSummary() { + return summary; + } + /** + * @param summary The summary to set. + */ + public void setSummary(String summary) { + this.summary = summary; + } + /** + * @return Returns the text. + */ + public String getText() { + return text; + } + /** + * @param text The text to set. + */ + private void setText(String text) { + this.text = text; + } + /** + * @return Returns the upperCaseName. + */ + public String getUpperCaseName() { + return upperCaseName; + } + /** + * @param upperCaseName The upperCaseName to set. + */ + public void setUpperCaseName(String upperCaseName) { + this.upperCaseName = upperCaseName; + } + + public void updateText(String newText) { + if ( !newText.equals(text) ) { + this.text = newText; + lastTextModification = new Date(); + } + } + +} diff --git a/test/org/hibernate/test/instrument/domain/Documents.hbm.xml b/test/org/hibernate/test/instrument/domain/Documents.hbm.xml new file mode 100755 index 0000000000..13badb64dc --- /dev/null +++ b/test/org/hibernate/test/instrument/domain/Documents.hbm.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/instrument/domain/Entity.java b/test/org/hibernate/test/instrument/domain/Entity.java new file mode 100644 index 0000000000..df1590ce82 --- /dev/null +++ b/test/org/hibernate/test/instrument/domain/Entity.java @@ -0,0 +1,52 @@ +package org.hibernate.test.instrument.domain; + +/** + * todo: describe Entity + * + * @author Steve Ebersole + */ +public class Entity { + private Long id; + private String name; + private Entity child; + private Entity sibling; + + public Entity() { + } + + public Entity(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Entity getChild() { + return child; + } + + public void setChild(Entity child) { + this.child = child; + } + + public Entity getSibling() { + return sibling; + } + + public void setSibling(Entity sibling) { + this.sibling = sibling; + } +} diff --git a/test/org/hibernate/test/instrument/domain/Folder.java b/test/org/hibernate/test/instrument/domain/Folder.java new file mode 100755 index 0000000000..72cc5a71a1 --- /dev/null +++ b/test/org/hibernate/test/instrument/domain/Folder.java @@ -0,0 +1,80 @@ +//$Id$ +package org.hibernate.test.instrument.domain; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author Gavin King + */ +public class Folder { + private Long id; + private String name; + private Folder parent; + private Collection subfolders = new ArrayList(); + private Collection documents = new ArrayList(); + + public boolean nameWasread; + + /** + * @return Returns the id. + */ + public Long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Long id) { + this.id = id; + } + /** + * @return Returns the name. + */ + public String getName() { + nameWasread = true; + return name; + } + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + /** + * @return Returns the documents. + */ + public Collection getDocuments() { + return documents; + } + /** + * @param documents The documents to set. + */ + public void setDocuments(Collection documents) { + this.documents = documents; + } + /** + * @return Returns the parent. + */ + public Folder getParent() { + return parent; + } + /** + * @param parent The parent to set. + */ + public void setParent(Folder parent) { + this.parent = parent; + } + /** + * @return Returns the subfolders. + */ + public Collection getSubfolders() { + return subfolders; + } + /** + * @param subfolders The subfolders to set. + */ + public void setSubfolders(Collection subfolders) { + this.subfolders = subfolders; + } +} diff --git a/test/org/hibernate/test/instrument/domain/Owner.java b/test/org/hibernate/test/instrument/domain/Owner.java new file mode 100755 index 0000000000..906821e039 --- /dev/null +++ b/test/org/hibernate/test/instrument/domain/Owner.java @@ -0,0 +1,34 @@ +//$Id$ +package org.hibernate.test.instrument.domain; + +/** + * @author Gavin King + */ +public class Owner { + private Long id; + private String name; + /** + * @return Returns the id. + */ + public Long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Long id) { + this.id = id; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/instrument/domain/Problematic.hbm.xml b/test/org/hibernate/test/instrument/domain/Problematic.hbm.xml new file mode 100644 index 0000000000..5949cf9157 --- /dev/null +++ b/test/org/hibernate/test/instrument/domain/Problematic.hbm.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/test/org/hibernate/test/instrument/domain/Problematic.java b/test/org/hibernate/test/instrument/domain/Problematic.java new file mode 100644 index 0000000000..9c3751f068 --- /dev/null +++ b/test/org/hibernate/test/instrument/domain/Problematic.java @@ -0,0 +1,69 @@ +package org.hibernate.test.instrument.domain; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class Problematic { + private Long id; + private String name; + private byte[] bytes; + + private Representation representation; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public byte[] getBytes() { + return bytes; + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } + + public Representation getRepresentation() { + if ( representation == null ) { + representation = ( ( bytes == null ) ? null : new Representation( bytes ) ); + } + return representation; + } + + public void setRepresentation(Representation rep) { + bytes = rep.getBytes(); + } + + public static class Representation { + private byte[] bytes; + + public Representation(byte[] bytes) { + this.bytes = bytes; + } + + public byte[] getBytes() { + return bytes; + } + + public String toString() { + String result = ""; + for ( int i = 0; i < bytes.length; i++ ) { + result += bytes[i]; + } + return result; + } + } +} diff --git a/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java b/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java new file mode 100644 index 0000000000..8c80ae8e82 --- /dev/null +++ b/test/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java @@ -0,0 +1,119 @@ +package org.hibernate.test.instrument.runtime; + +import java.lang.reflect.InvocationTargetException; + +import org.hibernate.HibernateException; +import org.hibernate.bytecode.BytecodeProvider; +import org.hibernate.bytecode.InstrumentedClassLoader; +import org.hibernate.bytecode.util.BasicClassFilter; +import org.hibernate.bytecode.util.FieldFilter; +import org.hibernate.junit.AbstractClassLoaderIsolatedTestCase; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractTransformingClassLoaderInstrumentTestCase extends AbstractClassLoaderIsolatedTestCase { + + public AbstractTransformingClassLoaderInstrumentTestCase(String string) { + super( string ); + } + + protected ClassLoader buildIsolatedClassLoader(ClassLoader parent) { + BytecodeProvider provider = buildBytecodeProvider(); + return new InstrumentedClassLoader( + parent, + provider.getTransformer( + new BasicClassFilter( new String[] { "org.hibernate.test.instrument" }, null ), + new FieldFilter() { + public boolean shouldInstrumentField(String className, String fieldName) { + return className.startsWith( "org.hibernate.test.instrument.domain" ); + } + public boolean shouldTransformFieldAccess(String transformingClassName, String fieldOwnerClassName, String fieldName) { + return fieldOwnerClassName.startsWith( "org.hibernate.test.instrument.domain" ) + && transformingClassName.equals( fieldOwnerClassName ); + } + } + ) + ); + + } + + protected void releaseIsolatedClassLoader(ClassLoader isolatedLoader) { + } + + protected abstract BytecodeProvider buildBytecodeProvider(); + + + // the tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public void testSetFieldInterceptor() { + executeExecutable( "org.hibernate.test.instrument.cases.TestInjectFieldInterceptorExecutable" ); + } + + public void testDirtyCheck() { + executeExecutable( "org.hibernate.test.instrument.cases.TestDirtyCheckExecutable" ); + } + + public void testFetchAll() throws Exception { + executeExecutable( "org.hibernate.test.instrument.cases.TestFetchAllExecutable" ); + } + + public void testLazy() { + executeExecutable( "org.hibernate.test.instrument.cases.TestLazyExecutable" ); + } + + public void testLazyManyToOne() { + executeExecutable( "org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable" ); + } + + public void testPropertyInitialized() { + executeExecutable( "org.hibernate.test.instrument.cases.TestIsPropertyInitializedExecutable" ); + } + + public void testManyToOneProxy() { + executeExecutable( "org.hibernate.test.instrument.cases.TestManyToOneProxyExecutable" ); + } + + public void testLazyPropertyCustomType() { + executeExecutable( "org.hibernate.test.instrument.cases.TestLazyPropertyCustomTypeExecutable" ); + } + + + + // reflection code to ensure isolation into the created classloader ~~~~~~~ + + private static final Class[] SIG = new Class[] {}; + private static final Object[] ARGS = new Object[] {}; + + public void executeExecutable(String name) { + Class execClass = null; + Object executable = null; + try { + execClass = Thread.currentThread().getContextClassLoader().loadClass( name ); + executable = execClass.newInstance(); + } + catch( Throwable t ) { + throw new HibernateException( "could not load executable", t ); + } + try { + execClass.getMethod( "prepare", SIG ).invoke( executable, ARGS ); + execClass.getMethod( "execute", SIG ).invoke( executable, ARGS ); + } + catch ( NoSuchMethodException e ) { + throw new HibernateException( "could not exeucte executable", e ); + } + catch ( IllegalAccessException e ) { + throw new HibernateException( "could not exeucte executable", e ); + } + catch ( InvocationTargetException e ) { + throw new HibernateException( "could not exeucte executable", e.getTargetException() ); + } + finally { + try { + execClass.getMethod( "complete", SIG ).invoke( executable, ARGS ); + } + catch ( Throwable ignore ) { + } + } + } +} diff --git a/test/org/hibernate/test/instrument/runtime/CGLIBInstrumentationTest.java b/test/org/hibernate/test/instrument/runtime/CGLIBInstrumentationTest.java new file mode 100644 index 0000000000..1bba3d213b --- /dev/null +++ b/test/org/hibernate/test/instrument/runtime/CGLIBInstrumentationTest.java @@ -0,0 +1,51 @@ +package org.hibernate.test.instrument.runtime; + +import org.hibernate.bytecode.BytecodeProvider; +import org.hibernate.bytecode.cglib.BytecodeProviderImpl; +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * @author Steve Ebersole + */ +public class CGLIBInstrumentationTest extends AbstractTransformingClassLoaderInstrumentTestCase { + public CGLIBInstrumentationTest(String string) { + super( string ); + } + + protected BytecodeProvider buildBytecodeProvider() { + return new BytecodeProviderImpl(); + } + + public static Test suite() { + return new TestSuite( CGLIBInstrumentationTest.class ); + } + + public void testSetFieldInterceptor() { + super.testSetFieldInterceptor(); //To change body of overridden methods use File | Settings | File Templates. + } + + public void testDirtyCheck() { + super.testDirtyCheck(); //To change body of overridden methods use File | Settings | File Templates. + } + + public void testFetchAll() throws Exception { + super.testFetchAll(); //To change body of overridden methods use File | Settings | File Templates. + } + + public void testLazy() { + super.testLazy(); //To change body of overridden methods use File | Settings | File Templates. + } + + public void testLazyManyToOne() { + super.testLazyManyToOne(); //To change body of overridden methods use File | Settings | File Templates. + } + + public void testPropertyInitialized() { + super.testPropertyInitialized(); //To change body of overridden methods use File | Settings | File Templates. + } + + public void testManyToOneProxy() { + super.testManyToOneProxy(); //To change body of overridden methods use File | Settings | File Templates. + } +} diff --git a/test/org/hibernate/test/instrument/runtime/JavassistInstrumentationTest.java b/test/org/hibernate/test/instrument/runtime/JavassistInstrumentationTest.java new file mode 100644 index 0000000000..fc8417b1c9 --- /dev/null +++ b/test/org/hibernate/test/instrument/runtime/JavassistInstrumentationTest.java @@ -0,0 +1,52 @@ +//$Id: $ +package org.hibernate.test.instrument.runtime; + +import org.hibernate.bytecode.BytecodeProvider; +import org.hibernate.bytecode.javassist.BytecodeProviderImpl; +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * @author Steve Ebersole + */ +public class JavassistInstrumentationTest extends AbstractTransformingClassLoaderInstrumentTestCase { + public JavassistInstrumentationTest(String string) { + super( string ); + } + + protected BytecodeProvider buildBytecodeProvider() { + return new BytecodeProviderImpl(); + } + + public static Test suite() { + return new TestSuite( JavassistInstrumentationTest.class ); + } + + public void testSetFieldInterceptor() { + super.testSetFieldInterceptor(); + } + + public void testDirtyCheck() { + super.testDirtyCheck(); + } + + public void testFetchAll() throws Exception { + super.testFetchAll(); + } + + public void testLazy() { + super.testLazy(); + } + + public void testLazyManyToOne() { + super.testLazyManyToOne(); + } + + public void testPropertyInitialized() { + super.testPropertyInitialized(); + } + + public void testManyToOneProxy() { + super.testManyToOneProxy(); + } +} diff --git a/test/org/hibernate/test/interceptor/CollectionInterceptor.java b/test/org/hibernate/test/interceptor/CollectionInterceptor.java new file mode 100755 index 0000000000..cac42bb7eb --- /dev/null +++ b/test/org/hibernate/test/interceptor/CollectionInterceptor.java @@ -0,0 +1,21 @@ +//$Id$ +package org.hibernate.test.interceptor; + +import java.io.Serializable; + +import org.hibernate.EmptyInterceptor; +import org.hibernate.type.Type; + +public class CollectionInterceptor extends EmptyInterceptor { + + public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { + ( (User) entity ).getActions().add("updated"); + return false; + } + + public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { + ( (User) entity ).getActions().add("created"); + return false; + } + +} diff --git a/test/org/hibernate/test/interceptor/Image.hbm.xml b/test/org/hibernate/test/interceptor/Image.hbm.xml new file mode 100644 index 0000000000..6641322444 --- /dev/null +++ b/test/org/hibernate/test/interceptor/Image.hbm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/interceptor/Image.java b/test/org/hibernate/test/interceptor/Image.java new file mode 100644 index 0000000000..2d2135953e --- /dev/null +++ b/test/org/hibernate/test/interceptor/Image.java @@ -0,0 +1,63 @@ +package org.hibernate.test.interceptor; + +public class Image { + + private Long id; + private String name; + private Details details; + + public Details getDetails() { + return details; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setDetails(Details details) { + this.details = details; + } + + public void setId(Long id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public String toString() { + return "Image/" + ( details == null ? "no details" : details.toString() ); + } + + public static class Details { + private long perm1 = -1; // all bits turned on. + private String comment; + + protected long getPerm1() { + return this.perm1; + } + + protected void setPerm1(long value) { + this.perm1 = value; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public String toString() { + return "Details=" + perm1; + } + } + +} + diff --git a/test/org/hibernate/test/interceptor/InterceptorTest.java b/test/org/hibernate/test/interceptor/InterceptorTest.java new file mode 100755 index 0000000000..c379a2f177 --- /dev/null +++ b/test/org/hibernate/test/interceptor/InterceptorTest.java @@ -0,0 +1,168 @@ +//$Id$ +package org.hibernate.test.interceptor; + +import java.io.Serializable; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.EmptyInterceptor; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.type.Type; + +/** + * @author Gavin King + */ +public class InterceptorTest extends FunctionalTestCase { + + public InterceptorTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "interceptor/User.hbm.xml", "interceptor/Image.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( InterceptorTest.class ); + } + + public void testCollectionIntercept() { + Session s = openSession( new CollectionInterceptor() ); + Transaction t = s.beginTransaction(); + User u = new User("Gavin", "nivag"); + s.persist(u); + u.setPassword("vagni"); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + u = (User) s.get(User.class, "Gavin"); + assertEquals( 2, u.getActions().size() ); + s.delete(u); + t.commit(); + s.close(); + } + + public void testPropertyIntercept() { + Session s = openSession( new PropertyInterceptor() ); + Transaction t = s.beginTransaction(); + User u = new User("Gavin", "nivag"); + s.persist(u); + u.setPassword("vagni"); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + u = (User) s.get(User.class, "Gavin"); + assertNotNull( u.getCreated() ); + assertNotNull( u.getLastUpdated() ); + s.delete(u); + t.commit(); + s.close(); + } + + /** + * Test case from HHH-1921. Here the interceptor resets the + * current-state to the same thing as the current db state; this + * causes EntityPersister.findDirty() to return no dirty properties. + */ + public void testPropertyIntercept2() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + User u = new User("Josh", "test"); + s.persist( u ); + t.commit(); + s.close(); + + s = openSession( + new EmptyInterceptor() { + public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { + currentState[0] = "test"; + return true; + } + } + ); + t = s.beginTransaction(); + u = ( User ) s.get( User.class, u.getName() ); + u.setPassword( "nottest" ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + u = (User) s.get(User.class, "Josh"); + assertEquals("test", u.getPassword()); + s.delete(u); + t.commit(); + s.close(); + + } + + public void testComponentInterceptor() { + final int checkPerm = 500; + final String checkComment = "generated from interceptor"; + + Session s = openSession( + new EmptyInterceptor() { + public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { + if ( state[0] == null ) { + Image.Details detail = new Image.Details(); + detail.setPerm1( checkPerm ); + detail.setComment( checkComment ); + state[0] = detail; + } + return true; + } + } + ); + s.beginTransaction(); + Image i = new Image(); + i.setName( "compincomp" ); + i = ( Image ) s.merge( i ); + assertNotNull( i.getDetails() ); + assertEquals( checkPerm, i.getDetails().getPerm1() ); + assertEquals( checkComment, i.getDetails().getComment() ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + i = ( Image ) s.get( Image.class, i.getId() ); + assertNotNull( i.getDetails() ); + assertEquals( checkPerm, i.getDetails().getPerm1() ); + assertEquals( checkComment, i.getDetails().getComment() ); + s.delete( i ); + s.getTransaction().commit(); + s.close(); + } + + public void testStatefulIntercept() { + final StatefulInterceptor statefulInterceptor = new StatefulInterceptor(); + Session s = openSession( statefulInterceptor ); + statefulInterceptor.setSession(s); + + Transaction t = s.beginTransaction(); + User u = new User("Gavin", "nivag"); + s.persist(u); + u.setPassword("vagni"); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + List logs = s.createCriteria(Log.class).list(); + assertEquals( 2, logs.size() ); + s.delete(u); + s.createQuery( "delete from Log" ).executeUpdate(); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/interceptor/Log.java b/test/org/hibernate/test/interceptor/Log.java new file mode 100755 index 0000000000..2b2ee153ee --- /dev/null +++ b/test/org/hibernate/test/interceptor/Log.java @@ -0,0 +1,53 @@ +//$Id$ +package org.hibernate.test.interceptor; + +import java.util.Calendar; + +public class Log { + private Long id; + private String entityName; + private String entityId; + private String action; + private Calendar time; + + public Log(String action, String id, String name) { + super(); + this.action = action; + entityId = id; + entityName = name; + time = Calendar.getInstance(); + } + public Log() { + super(); + } + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + public String getEntityId() { + return entityId; + } + public void setEntityId(String entityId) { + this.entityId = entityId; + } + public String getEntityName() { + return entityName; + } + public void setEntityName(String entityName) { + this.entityName = entityName; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Calendar getTime() { + return time; + } + public void setTime(Calendar time) { + this.time = time; + } +} diff --git a/test/org/hibernate/test/interceptor/PropertyInterceptor.java b/test/org/hibernate/test/interceptor/PropertyInterceptor.java new file mode 100755 index 0000000000..cae56d0db9 --- /dev/null +++ b/test/org/hibernate/test/interceptor/PropertyInterceptor.java @@ -0,0 +1,22 @@ +//$Id$ +package org.hibernate.test.interceptor; + +import java.io.Serializable; +import java.util.Calendar; + +import org.hibernate.EmptyInterceptor; +import org.hibernate.type.Type; + +public class PropertyInterceptor extends EmptyInterceptor { + + public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { + currentState[1] = Calendar.getInstance(); + return true; + } + + public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { + state[2] = Calendar.getInstance(); + return true; + } + +} diff --git a/test/org/hibernate/test/interceptor/StatefulInterceptor.java b/test/org/hibernate/test/interceptor/StatefulInterceptor.java new file mode 100755 index 0000000000..9e14fc1e96 --- /dev/null +++ b/test/org/hibernate/test/interceptor/StatefulInterceptor.java @@ -0,0 +1,47 @@ +//$Id$ +package org.hibernate.test.interceptor; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.hibernate.EmptyInterceptor; +import org.hibernate.Session; +import org.hibernate.type.Type; + +public class StatefulInterceptor extends EmptyInterceptor { + + private Session session; + + private List list = new ArrayList(); + + public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { + if ( !(entity instanceof Log) ) { + list.add( new Log( "insert", (String) id, entity.getClass().getName() ) ); + } + return false; + } + + public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { + if ( !(entity instanceof Log) ) { + list.add( new Log( "update", (String) id, entity.getClass().getName() ) ); + } + return false; + } + + public void postFlush(Iterator entities) { + if ( list.size()>0 ) { + for ( Iterator iter = list.iterator(); iter.hasNext(); ) { + session.persist( iter.next() ); + } + list.clear(); + session.flush(); + } + } + + public void setSession(Session s) { + session = s; + } + +} diff --git a/test/org/hibernate/test/interceptor/User.hbm.xml b/test/org/hibernate/test/interceptor/User.hbm.xml new file mode 100755 index 0000000000..57fc9150f4 --- /dev/null +++ b/test/org/hibernate/test/interceptor/User.hbm.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/interceptor/User.java b/test/org/hibernate/test/interceptor/User.java new file mode 100755 index 0000000000..b792350c45 --- /dev/null +++ b/test/org/hibernate/test/interceptor/User.java @@ -0,0 +1,53 @@ +//$Id$ +package org.hibernate.test.interceptor; + +import java.util.Calendar; +import java.util.HashSet; +import java.util.Set; + +public class User { + private String name; + private String password; + private Set actions = new HashSet(); + private Calendar lastUpdated; + private Calendar created; + + public User(String name, String password) { + super(); + this.name = name; + this.password = password; + } + public User() { + super(); + } + public Calendar getLastUpdated() { + return lastUpdated; + } + public void setLastUpdated(Calendar lastUpdated) { + this.lastUpdated = lastUpdated; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public Set getActions() { + return actions; + } + public void setActions(Set actions) { + this.actions = actions; + } + public Calendar getCreated() { + return created; + } + public void setCreated(Calendar created) { + this.created = created; + } +} diff --git a/test/org/hibernate/test/interfaceproxy/Document.java b/test/org/hibernate/test/interfaceproxy/Document.java new file mode 100755 index 0000000000..981bd01532 --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/Document.java @@ -0,0 +1,24 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +import java.sql.Blob; +import java.util.Calendar; + +/** + * @author Gavin King + */ +public interface Document extends Item { + /** + * @return Returns the content. + */ + public Blob getContent(); + + /** + * @param content The content to set. + */ + public void setContent(Blob content); + + public Calendar getCreated(); + + public Calendar getModified(); +} \ No newline at end of file diff --git a/test/org/hibernate/test/interfaceproxy/DocumentImpl.java b/test/org/hibernate/test/interfaceproxy/DocumentImpl.java new file mode 100755 index 0000000000..fc803c4068 --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/DocumentImpl.java @@ -0,0 +1,50 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +import java.sql.Blob; +import java.util.Calendar; + +/** + * @author Gavin King + */ +public class DocumentImpl extends ItemImpl implements Document { + private Blob content; + private Calendar modified; + private Calendar created; + /** + * @return Returns the created. + */ + public Calendar getCreated() { + return created; + } + /** + * @param created The created to set. + */ + public void setCreated(Calendar created) { + this.created = created; + } + /** + * @return Returns the modified. + */ + public Calendar getModified() { + return modified; + } + /** + * @param modified The modified to set. + */ + public void setModified(Calendar modified) { + this.modified = modified; + } + /** + * @return Returns the content. + */ + public Blob getContent() { + return content; + } + /** + * @param content The content to set. + */ + public void setContent(Blob content) { + this.content = content; + } +} diff --git a/test/org/hibernate/test/interfaceproxy/DocumentInterceptor.java b/test/org/hibernate/test/interfaceproxy/DocumentInterceptor.java new file mode 100755 index 0000000000..8e0754af1a --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/DocumentInterceptor.java @@ -0,0 +1,95 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +import java.io.Serializable; +import java.util.Calendar; +import java.util.Iterator; + +import org.hibernate.CallbackException; +import org.hibernate.Interceptor; +import org.hibernate.Transaction; +import org.hibernate.EntityMode; +import org.hibernate.type.Type; + +/** + * @author Gavin King + */ +public class DocumentInterceptor implements Interceptor { + + + public boolean onLoad(Object entity, Serializable id, Object[] state, + String[] propertyNames, Type[] types) throws CallbackException { + return false; + } + + public boolean onFlushDirty(Object entity, Serializable id, + Object[] currentState, Object[] previousState, + String[] propertyNames, Type[] types) throws CallbackException { + if ( entity instanceof Document ) { + currentState[2] = Calendar.getInstance(); + return true; + } + else { + return false; + } + } + + public boolean onSave(Object entity, Serializable id, Object[] state, + String[] propertyNames, Type[] types) throws CallbackException { + if ( entity instanceof Document ) { + state[3] = state[2] = Calendar.getInstance(); + return true; + } + else { + return false; + } + } + + public void onDelete(Object entity, Serializable id, Object[] state, + String[] propertyNames, Type[] types) throws CallbackException { + + } + + public void preFlush(Iterator entities) throws CallbackException { + + } + + public void postFlush(Iterator entities) throws CallbackException { + + } + + public Boolean isTransient(Object entity) { + return null; + } + + public int[] findDirty(Object entity, Serializable id, + Object[] currentState, Object[] previousState, + String[] propertyNames, Type[] types) { + return null; + } + + public Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException { + return null; + } + + public String getEntityName(Object object) throws CallbackException { + return null; + } + + public Object getEntity(String entityName, Serializable id) + throws CallbackException { + return null; + } + + public void afterTransactionBegin(Transaction tx) {} + public void afterTransactionCompletion(Transaction tx) {} + public void beforeTransactionCompletion(Transaction tx) {} + + public String onPrepareStatement(String sql) { + return sql; + } + + public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {} + public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {} + public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {} +} diff --git a/test/org/hibernate/test/interfaceproxy/Folder.java b/test/org/hibernate/test/interfaceproxy/Folder.java new file mode 100755 index 0000000000..b929d63843 --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/Folder.java @@ -0,0 +1,17 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +/** + * @author Gavin King + */ +public interface Folder extends Item { + /** + * @return Returns the parent. + */ + public Folder getParent(); + + /** + * @param parent The parent to set. + */ + public void setParent(Folder parent); +} \ No newline at end of file diff --git a/test/org/hibernate/test/interfaceproxy/FolderImpl.java b/test/org/hibernate/test/interfaceproxy/FolderImpl.java new file mode 100755 index 0000000000..79032e91d9 --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/FolderImpl.java @@ -0,0 +1,21 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +/** + * @author Gavin King + */ +public class FolderImpl extends ItemImpl implements Folder { + private Folder parent; + /** + * @return Returns the parent. + */ + public Folder getParent() { + return parent; + } + /** + * @param parent The parent to set. + */ + public void setParent(Folder parent) { + this.parent = parent; + } +} diff --git a/test/org/hibernate/test/interfaceproxy/InterfaceProxyTest.java b/test/org/hibernate/test/interfaceproxy/InterfaceProxyTest.java new file mode 100755 index 0000000000..4ffa11f0fb --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/InterfaceProxyTest.java @@ -0,0 +1,101 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class InterfaceProxyTest extends FunctionalTestCase { + + public InterfaceProxyTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "interfaceproxy/Item.hbm.xml" }; + } + + public String getCacheConcurrencyStrategy() { + return null; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( InterfaceProxyTest.class ); + } + + public void testInterfaceProxies() { + + if ( getDialect() instanceof PostgreSQLDialect ) { + // TODO : why? + return; + } + + Session s = openSession( new DocumentInterceptor() ); + Transaction t = s.beginTransaction(); + Document d = new DocumentImpl(); + d.setName("Hibernate in Action"); + d.setContent( Hibernate.createBlob( "blah blah blah".getBytes() ) ); + Long did = (Long) s.save(d); + SecureDocument d2 = new SecureDocumentImpl(); + d2.setName("Secret"); + d2.setContent( Hibernate.createBlob( "wxyz wxyz".getBytes() ) ); + d2.setPermissionBits( (byte) 664 ); + d2.setOwner("gavin"); + Long d2id = (Long) s.save(d2); + t.commit(); + s.close(); + + s = openSession( new DocumentInterceptor() ); + t = s.beginTransaction(); + d = (Document) s.load(ItemImpl.class, did); + assertEquals( did, d.getId() ); + assertEquals( "Hibernate in Action", d.getName() ); + assertNotNull( d.getContent() ); + + d2 = (SecureDocument) s.load(ItemImpl.class, d2id); + assertEquals( d2id, d2.getId() ); + assertEquals( "Secret", d2.getName() ); + assertNotNull( d2.getContent() ); + + s.clear(); + + d = (Document) s.load(DocumentImpl.class, did); + assertEquals( did, d.getId() ); + assertEquals( "Hibernate in Action", d.getName() ); + assertNotNull( d.getContent() ); + + d2 = (SecureDocument) s.load(SecureDocumentImpl.class, d2id); + assertEquals( d2id, d2.getId() ); + assertEquals( "Secret", d2.getName() ); + assertNotNull( d2.getContent() ); + assertEquals( "gavin", d2.getOwner() ); + + //s.clear(); + + d2 = (SecureDocument) s.load(SecureDocumentImpl.class, did); + assertEquals( did, d2.getId() ); + assertEquals( "Hibernate in Action", d2.getName() ); + assertNotNull( d2.getContent() ); + + try { + d2.getOwner(); //CCE + assertFalse(true); + } + catch (ClassCastException cce) { + //correct + } + + s.createQuery( "delete ItemImpl" ).executeUpdate(); + t.commit(); + s.close(); + } +} + diff --git a/test/org/hibernate/test/interfaceproxy/Item.hbm.xml b/test/org/hibernate/test/interfaceproxy/Item.hbm.xml new file mode 100755 index 0000000000..fc14b0e5d0 --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/Item.hbm.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/interfaceproxy/Item.java b/test/org/hibernate/test/interfaceproxy/Item.java new file mode 100755 index 0000000000..a67f1018c8 --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/Item.java @@ -0,0 +1,22 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +/** + * @author Gavin King + */ +public interface Item { + /** + * @return Returns the id. + */ + public Long getId(); + + /** + * @return Returns the name. + */ + public String getName(); + + /** + * @param name The name to set. + */ + public void setName(String name); +} \ No newline at end of file diff --git a/test/org/hibernate/test/interfaceproxy/ItemImpl.java b/test/org/hibernate/test/interfaceproxy/ItemImpl.java new file mode 100755 index 0000000000..caa4ff69f1 --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/ItemImpl.java @@ -0,0 +1,34 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +/** + * @author Gavin King + */ +public abstract class ItemImpl implements Item { + private Long id; + private String name; + /** + * @return Returns the id. + */ + public Long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(Long id) { + this.id = id; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/interfaceproxy/SecureDocument.java b/test/org/hibernate/test/interfaceproxy/SecureDocument.java new file mode 100755 index 0000000000..d0bd1f59dd --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/SecureDocument.java @@ -0,0 +1,27 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +/** + * @author Gavin King + */ +public interface SecureDocument extends Document { + /** + * @return Returns the owner. + */ + public String getOwner(); + + /** + * @param owner The owner to set. + */ + public void setOwner(String owner); + + /** + * @return Returns the permissionBits. + */ + public byte getPermissionBits(); + + /** + * @param permissionBits The permissionBits to set. + */ + public void setPermissionBits(byte permissionBits); +} \ No newline at end of file diff --git a/test/org/hibernate/test/interfaceproxy/SecureDocumentImpl.java b/test/org/hibernate/test/interfaceproxy/SecureDocumentImpl.java new file mode 100755 index 0000000000..4d1cfc3f19 --- /dev/null +++ b/test/org/hibernate/test/interfaceproxy/SecureDocumentImpl.java @@ -0,0 +1,34 @@ +//$Id$ +package org.hibernate.test.interfaceproxy; + +/** + * @author Gavin King + */ +public class SecureDocumentImpl extends DocumentImpl implements SecureDocument { + private byte permissionBits; + private String owner; + /** + * @return Returns the owner. + */ + public String getOwner() { + return owner; + } + /** + * @param owner The owner to set. + */ + public void setOwner(String owner) { + this.owner = owner; + } + /** + * @return Returns the permissionBits. + */ + public byte getPermissionBits() { + return permissionBits; + } + /** + * @param permissionBits The permissionBits to set. + */ + public void setPermissionBits(byte permissionBits) { + this.permissionBits = permissionBits; + } +} diff --git a/test/org/hibernate/test/iterate/Item.hbm.xml b/test/org/hibernate/test/iterate/Item.hbm.xml new file mode 100755 index 0000000000..cf29c45b3f --- /dev/null +++ b/test/org/hibernate/test/iterate/Item.hbm.xml @@ -0,0 +1,14 @@ + + + + + + + + from Item order by name desc + + + diff --git a/test/org/hibernate/test/iterate/Item.java b/test/org/hibernate/test/iterate/Item.java new file mode 100755 index 0000000000..42371782f6 --- /dev/null +++ b/test/org/hibernate/test/iterate/Item.java @@ -0,0 +1,20 @@ +//$Id$ +package org.hibernate.test.iterate; + +/** + * @author Gavin King + */ +public class Item { + private String name; + Item() {} + public Item(String n) { + name = n; + } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/test/org/hibernate/test/iterate/IterateTest.java b/test/org/hibernate/test/iterate/IterateTest.java new file mode 100755 index 0000000000..a2b49ec28b --- /dev/null +++ b/test/org/hibernate/test/iterate/IterateTest.java @@ -0,0 +1,105 @@ +//$Id$ +package org.hibernate.test.iterate; + +import java.util.Iterator; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class IterateTest extends FunctionalTestCase { + + public IterateTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "iterate/Item.hbm.xml" }; + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.USE_QUERY_CACHE, "true" ); + cfg.setProperty( Environment.CACHE_REGION_PREFIX, "foo" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( IterateTest.class ); + } + + public void testIterate() throws Exception { + getSessions().getStatistics().clear(); + Session s = openSession(); + Transaction t = s.beginTransaction(); + Item i1 = new Item("foo"); + Item i2 = new Item("bar"); + s.persist("Item", i1); + s.persist("Item", i2); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Iterator iter = s.getNamedQuery("Item.nameDesc").iterate(); + i1 = (Item) iter.next(); + i2 = (Item) iter.next(); + assertFalse( Hibernate.isInitialized(i1) ); + assertFalse( Hibernate.isInitialized(i2) ); + i1.getName(); + i2.getName(); + assertFalse( Hibernate.isInitialized(i1) ); + assertFalse( Hibernate.isInitialized(i2) ); + assertEquals( i1.getName(), "foo" ); + assertEquals( i2.getName(), "bar" ); + Hibernate.initialize(i1); + assertFalse( iter.hasNext() ); + s.delete(i1); + s.delete(i2); + t.commit(); + s.close(); + assertEquals( getSessions().getStatistics().getEntityFetchCount(), 2 ); + } + + public void testScroll() throws Exception { + getSessions().getStatistics().clear(); + Session s = openSession(); + Transaction t = s.beginTransaction(); + Item i1 = new Item("foo"); + Item i2 = new Item("bar"); + s.persist("Item", i1); + s.persist("Item", i2); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + ScrollableResults sr = s.getNamedQuery("Item.nameDesc").scroll(); + assertTrue( sr.next() ); + i1 = (Item) sr.get(0); + assertTrue( sr.next() ); + i2 = (Item) sr.get(0); + assertTrue( Hibernate.isInitialized(i1) ); + assertTrue( Hibernate.isInitialized(i2) ); + assertEquals( i1.getName(), "foo" ); + assertEquals( i2.getName(), "bar" ); + assertFalse( sr.next() ); + s.delete(i1); + s.delete(i2); + t.commit(); + s.close(); + assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 ); + } +} + diff --git a/test/org/hibernate/test/join/Customer.java b/test/org/hibernate/test/join/Customer.java new file mode 100755 index 0000000000..258c49aed3 --- /dev/null +++ b/test/org/hibernate/test/join/Customer.java @@ -0,0 +1,35 @@ +//$Id$ +package org.hibernate.test.join; + +/** + * @author Gavin King + */ +public class Customer extends Person { + private Employee salesperson; + private String comments; + + /** + * @return Returns the salesperson. + */ + public Employee getSalesperson() { + return salesperson; + } + /** + * @param salesperson The salesperson to set. + */ + public void setSalesperson(Employee salesperson) { + this.salesperson = salesperson; + } + /** + * @return Returns the comments. + */ + public String getComments() { + return comments; + } + /** + * @param comments The comments to set. + */ + public void setComments(String comments) { + this.comments = comments; + } +} diff --git a/test/org/hibernate/test/join/Employee.java b/test/org/hibernate/test/join/Employee.java new file mode 100755 index 0000000000..89dd482c7e --- /dev/null +++ b/test/org/hibernate/test/join/Employee.java @@ -0,0 +1,49 @@ +//$Id$ +package org.hibernate.test.join; + +import java.math.BigDecimal; + +/** + * @author Gavin King + */ +public class Employee extends Person { + private String title; + private BigDecimal salary; + private Employee manager; + /** + * @return Returns the title. + */ + public String getTitle() { + return title; + } + /** + * @param title The title to set. + */ + public void setTitle(String title) { + this.title = title; + } + /** + * @return Returns the manager. + */ + public Employee getManager() { + return manager; + } + /** + * @param manager The manager to set. + */ + public void setManager(Employee manager) { + this.manager = manager; + } + /** + * @return Returns the salary. + */ + public BigDecimal getSalary() { + return salary; + } + /** + * @param salary The salary to set. + */ + public void setSalary(BigDecimal salary) { + this.salary = salary; + } +} diff --git a/test/org/hibernate/test/join/JoinTest.java b/test/org/hibernate/test/join/JoinTest.java new file mode 100755 index 0000000000..31e930d40e --- /dev/null +++ b/test/org/hibernate/test/join/JoinTest.java @@ -0,0 +1,135 @@ +//$Id$ +package org.hibernate.test.join; + +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class JoinTest extends FunctionalTestCase { + + public JoinTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "join/Person.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( JoinTest.class ); + } + + public void testSequentialSelects() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Employee mark = new Employee(); + mark.setName("Mark"); + mark.setTitle("internal sales"); + mark.setSex('M'); + mark.setAddress("buckhead"); + mark.setZip("30305"); + mark.setCountry("USA"); + + Customer joe = new Customer(); + joe.setName("Joe"); + joe.setAddress("San Francisco"); + joe.setZip("XXXXX"); + joe.setCountry("USA"); + joe.setComments("Very demanding"); + joe.setSex('M'); + joe.setSalesperson(mark); + + Person yomomma = new Person(); + yomomma.setName("mum"); + yomomma.setSex('F'); + + s.save(yomomma); + s.save(mark); + s.save(joe); + + assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 ); + + assertEquals( s.createQuery("from Person").list().size(), 3 ); + assertEquals( s.createQuery("from Person p where p.class is null").list().size(), 1 ); + assertEquals( s.createQuery("from Person p where p.class = Customer").list().size(), 1 ); + assertTrue(s.createQuery("from Customer c").list().size()==1); + s.clear(); + + List customers = s.createQuery("from Customer c left join fetch c.salesperson").list(); + for ( Iterator iter = customers.iterator(); iter.hasNext(); ) { + Customer c = (Customer) iter.next(); + assertTrue( Hibernate.isInitialized( c.getSalesperson() ) ); + assertEquals( c.getSalesperson().getName(), "Mark" ); + } + assertEquals( customers.size(), 1 ); + s.clear(); + + customers = s.createQuery("from Customer").list(); + for ( Iterator iter = customers.iterator(); iter.hasNext(); ) { + Customer c = (Customer) iter.next(); + assertFalse( Hibernate.isInitialized( c.getSalesperson() ) ); + assertEquals( c.getSalesperson().getName(), "Mark" ); + } + assertEquals( customers.size(), 1 ); + s.clear(); + + + mark = (Employee) s.get( Employee.class, new Long( mark.getId() ) ); + joe = (Customer) s.get( Customer.class, new Long( joe.getId() ) ); + + mark.setZip("30306"); + assertEquals( s.createQuery("from Person p where p.zip = '30306'").list().size(), 1 ); + s.delete(mark); + s.delete(joe); + s.delete(yomomma); + assertTrue( s.createQuery("from Person").list().isEmpty() ); + t.commit(); + s.close(); + } + + public void testSequentialSelectsOptionalData() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + User jesus = new User(); + jesus.setName("Jesus Olvera y Martinez"); + jesus.setSex('M'); + + s.save(jesus); + + assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 ); + + assertEquals( s.createQuery("from Person").list().size(), 1 ); + assertEquals( s.createQuery("from Person p where p.class is null").list().size(), 0 ); + assertEquals( s.createQuery("from Person p where p.class = User").list().size(), 1 ); + assertTrue(s.createQuery("from User u").list().size()==1); + s.clear(); + + // Remove the optional row from the join table and requery the User obj + s.connection().prepareStatement("delete from t_user").execute(); + s.clear(); + + jesus = (User) s.get( Person.class, new Long( jesus.getId() ) ); + s.clear(); + + // Cleanup the test data + s.delete(jesus); + + assertTrue( s.createQuery("from Person").list().isEmpty() ); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/join/Person.hbm.xml b/test/org/hibernate/test/join/Person.hbm.xml new file mode 100755 index 0000000000..b3e6ea28c9 --- /dev/null +++ b/test/org/hibernate/test/join/Person.hbm.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/join/Person.java b/test/org/hibernate/test/join/Person.java new file mode 100755 index 0000000000..b5b240a19d --- /dev/null +++ b/test/org/hibernate/test/join/Person.java @@ -0,0 +1,90 @@ +//$Id$ +package org.hibernate.test.join; + + +/** + * @author Gavin King + */ +public class Person { + private long id; + private String name; + private String address; + private String zip; + private String country; + private char sex; + + /** + * @return Returns the sex. + */ + public char getSex() { + return sex; + } + /** + * @param sex The sex to set. + */ + public void setSex(char sex) { + this.sex = sex; + } + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(long id) { + this.id = id; + } + /** + * @return Returns the identity. + */ + public String getName() { + return name; + } + /** + * @param identity The identity to set. + */ + public void setName(String identity) { + this.name = identity; + } + public String getSpecies() { + return null; + } + + /** + * @return Returns the country. + */ + public String getCountry() { + return country; + } + /** + * @param country The country to set. + */ + public void setCountry(String country) { + this.country = country; + } + /** + * @return Returns the zip. + */ + public String getZip() { + return zip; + } + /** + * @param zip The zip to set. + */ + public void setZip(String zip) { + this.zip = zip; + } + /** + * @param address The address to set. + */ + public void setAddress(String address) { + this.address = address; + } + + public String getAddress() { + return address; + } +} diff --git a/test/org/hibernate/test/join/User.java b/test/org/hibernate/test/join/User.java new file mode 100644 index 0000000000..772b5b348a --- /dev/null +++ b/test/org/hibernate/test/join/User.java @@ -0,0 +1,23 @@ +//$Id$ +package org.hibernate.test.join; + +/** + * @author Mike Dillon + */ +public class User extends Person { + private String login; + private String silly; + + /** + * @return Returns the login. + */ + public String getLogin() { + return login; + } + /** + * @param login The login to set. + */ + public void setLogin(String login) { + this.login = login; + } +} diff --git a/test/org/hibernate/test/joinedsubclass/Address.java b/test/org/hibernate/test/joinedsubclass/Address.java new file mode 100755 index 0000000000..381396c2ac --- /dev/null +++ b/test/org/hibernate/test/joinedsubclass/Address.java @@ -0,0 +1,11 @@ +//$Id$ +package org.hibernate.test.joinedsubclass; + +/** + * @author Gavin King + */ +public class Address { + public String address; + public String zip; + public String country; +} diff --git a/test/org/hibernate/test/joinedsubclass/Customer.java b/test/org/hibernate/test/joinedsubclass/Customer.java new file mode 100755 index 0000000000..c02ef41de9 --- /dev/null +++ b/test/org/hibernate/test/joinedsubclass/Customer.java @@ -0,0 +1,35 @@ +//$Id$ +package org.hibernate.test.joinedsubclass; + +/** + * @author Gavin King + */ +public class Customer extends Person { + private Employee salesperson; + private String comments; + + /** + * @return Returns the salesperson. + */ + public Employee getSalesperson() { + return salesperson; + } + /** + * @param salesperson The salesperson to set. + */ + public void setSalesperson(Employee salesperson) { + this.salesperson = salesperson; + } + /** + * @return Returns the comments. + */ + public String getComments() { + return comments; + } + /** + * @param comments The comments to set. + */ + public void setComments(String comments) { + this.comments = comments; + } +} diff --git a/test/org/hibernate/test/joinedsubclass/Employee.java b/test/org/hibernate/test/joinedsubclass/Employee.java new file mode 100755 index 0000000000..9ba3fab418 --- /dev/null +++ b/test/org/hibernate/test/joinedsubclass/Employee.java @@ -0,0 +1,49 @@ +//$Id$ +package org.hibernate.test.joinedsubclass; + +import java.math.BigDecimal; + +/** + * @author Gavin King + */ +public class Employee extends Person { + private String title; + private BigDecimal salary; + private Employee manager; + /** + * @return Returns the title. + */ + public String getTitle() { + return title; + } + /** + * @param title The title to set. + */ + public void setTitle(String title) { + this.title = title; + } + /** + * @return Returns the manager. + */ + public Employee getManager() { + return manager; + } + /** + * @param manager The manager to set. + */ + public void setManager(Employee manager) { + this.manager = manager; + } + /** + * @return Returns the salary. + */ + public BigDecimal getSalary() { + return salary; + } + /** + * @param salary The salary to set. + */ + public void setSalary(BigDecimal salary) { + this.salary = salary; + } +} diff --git a/test/org/hibernate/test/joinedsubclass/JoinedSubclassTest.java b/test/org/hibernate/test/joinedsubclass/JoinedSubclassTest.java new file mode 100755 index 0000000000..30a0425ca3 --- /dev/null +++ b/test/org/hibernate/test/joinedsubclass/JoinedSubclassTest.java @@ -0,0 +1,211 @@ +//$Id$ +package org.hibernate.test.joinedsubclass; + +import java.math.BigDecimal; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.LockMode; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.criterion.Expression; +import org.hibernate.criterion.Property; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class JoinedSubclassTest extends FunctionalTestCase { + + public JoinedSubclassTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "joinedsubclass/Person.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( JoinedSubclassTest.class ); + } + + public void testJoinedSubclass() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Employee mark = new Employee(); + mark.setName("Mark"); + mark.setTitle("internal sales"); + mark.setSex('M'); + mark.setAddress("buckhead"); + mark.setZip("30305"); + mark.setCountry("USA"); + + Customer joe = new Customer(); + joe.setName("Joe"); + joe.setAddress("San Francisco"); + joe.setZip("XXXXX"); + joe.setCountry("USA"); + joe.setComments("Very demanding"); + joe.setSex('M'); + joe.setSalesperson(mark); + + Person yomomma = new Person(); + yomomma.setName("mum"); + yomomma.setSex('F'); + + s.save(yomomma); + s.save(mark); + s.save(joe); + + assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 ); + + assertEquals( s.createQuery("from Person").list().size(), 3 ); + assertEquals( s.createQuery("from Person p where p.class = Customer").list().size(), 1 ); + assertEquals( s.createQuery("from Person p where p.class = Person").list().size(), 1 ); + s.clear(); + + List customers = s.createQuery("from Customer c left join fetch c.salesperson").list(); + for ( Iterator iter = customers.iterator(); iter.hasNext(); ) { + Customer c = (Customer) iter.next(); + assertTrue( Hibernate.isInitialized( c.getSalesperson() ) ); + assertEquals( c.getSalesperson().getName(), "Mark" ); + } + assertEquals( customers.size(), 1 ); + s.clear(); + + customers = s.createQuery("from Customer").list(); + for ( Iterator iter = customers.iterator(); iter.hasNext(); ) { + Customer c = (Customer) iter.next(); + assertFalse( Hibernate.isInitialized( c.getSalesperson() ) ); + assertEquals( c.getSalesperson().getName(), "Mark" ); + } + assertEquals( customers.size(), 1 ); + s.clear(); + + + mark = (Employee) s.get( Employee.class, new Long( mark.getId() ) ); + joe = (Customer) s.get( Customer.class, new Long( joe.getId() ) ); + + mark.setZip("30306"); + assertEquals( s.createQuery("from Person p where p.address.zip = '30306'").list().size(), 1 ); + + if ( supportsRowValueConstructorSyntaxInInList() ) { + s.createCriteria(Person.class).add( + Expression.in("address", new Address[] { mark.getAddress(), joe.getAddress() } ) + ).list(); + } + + s.delete(mark); + s.delete(joe); + s.delete(yomomma); + assertTrue( s.createQuery("from Person").list().isEmpty() ); + t.commit(); + s.close(); + } + + public void testAccessAsIncorrectSubclass() { + Session s = openSession(); + s.beginTransaction(); + Employee e = new Employee(); + e.setName( "Steve" ); + e.setSex( 'M' ); + e.setTitle( "grand poobah" ); + s.save( e ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + Customer c = ( Customer ) s.get( Customer.class, new Long( e.getId() ) ); + s.getTransaction().commit(); + s.close(); + assertNull( c ); + + s = openSession(); + s.beginTransaction(); + e = ( Employee ) s.get( Employee.class, new Long( e.getId() ) ); + c = ( Customer ) s.get( Customer.class, new Long( e.getId() ) ); + s.getTransaction().commit(); + s.close(); + assertNotNull( e ); + assertNull( c ); + + s = openSession(); + s.beginTransaction(); + s.delete( e ); + s.getTransaction().commit(); + s.close(); + } + + public void testQuerySubclassAttribute() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Person p = new Person(); + p.setName("Emmanuel"); + p.setSex('M'); + s.persist(p); + Employee q = new Employee(); + q.setName("Steve"); + q.setSex('M'); + q.setTitle("Mr"); + q.setSalary( new BigDecimal(1000) ); + s.persist(q); + + List result = s.createQuery("from Person where salary > 100").list(); + assertEquals( result.size(), 1 ); + assertSame( result.get(0), q ); + + result = s.createQuery("from Person where salary > 100 or name like 'E%'").list(); + assertEquals( result.size(), 2 ); + + result = s.createCriteria(Person.class) + .add( Property.forName("salary").gt( new BigDecimal(100) ) ) + .list(); + assertEquals( result.size(), 1 ); + assertSame( result.get(0), q ); + + //TODO: make this work: + /*result = s.createQuery("select salary from Person where salary > 100").list(); + assertEquals( result.size(), 1 ); + assertEquals( result.get(0), new BigDecimal(1000) );*/ + + s.delete(p); + s.delete(q); + t.commit(); + s.close(); + } + + public void testLockingJoinedSubclass() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Person p = new Person(); + p.setName("Emmanuel"); + p.setSex('M'); + s.persist(p); + Employee q = new Employee(); + q.setName("Steve"); + q.setSex('M'); + q.setTitle("Mr"); + q.setSalary( new BigDecimal(1000) ); + s.persist(q); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.lock( p, LockMode.UPGRADE ); + s.lock( q, LockMode.UPGRADE ); + s.delete( p ); + s.delete( q ); + t.commit(); + s.close(); + + } + +} + diff --git a/test/org/hibernate/test/joinedsubclass/Person.hbm.xml b/test/org/hibernate/test/joinedsubclass/Person.hbm.xml new file mode 100755 index 0000000000..6603b53457 --- /dev/null +++ b/test/org/hibernate/test/joinedsubclass/Person.hbm.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/joinedsubclass/Person.java b/test/org/hibernate/test/joinedsubclass/Person.java new file mode 100755 index 0000000000..0f17b8fdc2 --- /dev/null +++ b/test/org/hibernate/test/joinedsubclass/Person.java @@ -0,0 +1,78 @@ +//$Id$ +package org.hibernate.test.joinedsubclass; + + +/** + * @author Gavin King + */ +public class Person { + private long id; + private String name; + private char sex; + private int version; + private Address address = new Address(); + /** + * @return Returns the address. + */ + public Address getAddress() { + return address; + } + + public void setAddress(String string) { + this.address.address = string; + } + + public void setZip(String string) { + this.address.zip = string; + } + + public void setCountry(String string) { + this.address.country = string; + } + + + /** + * @return Returns the sex. + */ + public char getSex() { + return sex; + } + /** + * @param sex The sex to set. + */ + public void setSex(char sex) { + this.sex = sex; + } + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + /** + * @param id The id to set. + */ + public void setId(long id) { + this.id = id; + } + /** + * @return Returns the identity. + */ + public String getName() { + return name; + } + /** + * @param identity The identity to set. + */ + public void setName(String identity) { + this.name = identity; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } +} diff --git a/test/org/hibernate/test/joinfetch/Bid.java b/test/org/hibernate/test/joinfetch/Bid.java new file mode 100755 index 0000000000..29981ca02d --- /dev/null +++ b/test/org/hibernate/test/joinfetch/Bid.java @@ -0,0 +1,49 @@ +//$Id$ +package org.hibernate.test.joinfetch; + +import java.util.Calendar; + +/** + * @author Gavin King + */ +public class Bid { + + private float amount; + private Item item; + private Calendar timestamp; + private Long id; + + public float getAmount() { + return amount; + } + public void setAmount(float amount) { + this.amount = amount; + } + public Item getItem() { + return item; + } + public void setItem(Item item) { + this.item = item; + } + public Calendar getTimestamp() { + return timestamp; + } + public void setTimestamp(Calendar timestamp) { + this.timestamp = timestamp; + } + + Bid() {} + public Bid(Item item, float amount) { + this.amount = amount; + this.item = item; + item.getBids().add(this); + this.timestamp = Calendar.getInstance(); + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + +} diff --git a/test/org/hibernate/test/joinfetch/Category.java b/test/org/hibernate/test/joinfetch/Category.java new file mode 100755 index 0000000000..df61b1982f --- /dev/null +++ b/test/org/hibernate/test/joinfetch/Category.java @@ -0,0 +1,20 @@ +//$Id$ +package org.hibernate.test.joinfetch; + +/** + * @author Gavin King + */ +public class Category { + + private String name; + + Category() {} + + public Category(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/test/org/hibernate/test/joinfetch/Comment.java b/test/org/hibernate/test/joinfetch/Comment.java new file mode 100755 index 0000000000..309130a790 --- /dev/null +++ b/test/org/hibernate/test/joinfetch/Comment.java @@ -0,0 +1,49 @@ +//$Id$ +package org.hibernate.test.joinfetch; + +import java.util.Calendar; + +/** + * @author Gavin King + */ +public class Comment { + + private String text; + private Item item; + private Calendar timestamp; + private Long id; + + public Item getItem() { + return item; + } + public void setItem(Item item) { + this.item = item; + } + public Calendar getTimestamp() { + return timestamp; + } + public void setTimestamp(Calendar timestamp) { + this.timestamp = timestamp; + } + + Comment() {} + public Comment(Item item, String comment) { + this.text = comment; + this.item = item; + item.getComments().add(this); + this.timestamp = Calendar.getInstance(); + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getText() { + return text; + } + public void setText(String text) { + this.text = text; + } + +} diff --git a/test/org/hibernate/test/joinfetch/Group.java b/test/org/hibernate/test/joinfetch/Group.java new file mode 100755 index 0000000000..1e051aae0b --- /dev/null +++ b/test/org/hibernate/test/joinfetch/Group.java @@ -0,0 +1,33 @@ +//$Id$ +package org.hibernate.test.joinfetch; + +import java.util.HashMap; +import java.util.Map; + +public class Group { + private String name; + private Map users = new HashMap(); + + public Group(String name) { + this.name = name; + } + + Group() {} + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getUsers() { + return users; + } + + public void setUsers(Map users) { + this.users = users; + } + +} diff --git a/test/org/hibernate/test/joinfetch/Item.java b/test/org/hibernate/test/joinfetch/Item.java new file mode 100755 index 0000000000..1f161ddd1f --- /dev/null +++ b/test/org/hibernate/test/joinfetch/Item.java @@ -0,0 +1,64 @@ +//$Id$ +package org.hibernate.test.joinfetch; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Gavin King + */ +public class Item { + + private String description; + private Long id; + private Category category; + private Set bids = new HashSet(); + private Set comments = new HashSet(); + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + Item() {} + public Item(Category cat, String desc) { + description = desc; + category = cat; + } + + public Set getBids() { + return bids; + } + + public void setBids(Set bids) { + this.bids = bids; + } + + public Set getComments() { + return comments; + } + + public void setComments(Set comments) { + this.comments = comments; + } + + public Category getCategory() { + return category; + } + + public void setCategory(Category category) { + this.category = category; + } + +} diff --git a/test/org/hibernate/test/joinfetch/ItemBid.hbm.xml b/test/org/hibernate/test/joinfetch/ItemBid.hbm.xml new file mode 100755 index 0000000000..3649ae774c --- /dev/null +++ b/test/org/hibernate/test/joinfetch/ItemBid.hbm.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select {item.*}, {bid.*}, {commnt.*} + from AuctionItems item + left outer join AuctionBids bid on bid.item = item.id + left outer join AuctionComments commnt on commnt.item = item.id + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/joinfetch/JoinFetchTest.java b/test/org/hibernate/test/joinfetch/JoinFetchTest.java new file mode 100755 index 0000000000..98f0b4904c --- /dev/null +++ b/test/org/hibernate/test/joinfetch/JoinFetchTest.java @@ -0,0 +1,267 @@ +//$Id$ +package org.hibernate.test.joinfetch; + +import java.util.List; + +import junit.framework.Test; + +import org.hibernate.FetchMode; +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.criterion.Projections; +import org.hibernate.criterion.Restrictions; +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; + +/** + * @author Gavin King + */ +public class JoinFetchTest extends FunctionalTestCase { + + public JoinFetchTest(String str) { + super(str); + } + + public String[] getMappings() { + return new String[] { "joinfetch/ItemBid.hbm.xml", "joinfetch/UserGroup.hbm.xml" }; + } + + public void configure(Configuration cfg) { + cfg.setProperty(Environment.MAX_FETCH_DEPTH, "10"); + cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false"); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( JoinFetchTest.class ); + } + + public void testProjection() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createCriteria(Item.class).setProjection( Projections.rowCount() ).uniqueResult(); + s.createCriteria(Item.class).uniqueResult(); + t.commit(); + s.close(); + } + + public void testJoinFetch() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createQuery( "delete from Bid" ).executeUpdate(); + s.createQuery( "delete from Comment" ).executeUpdate(); + s.createQuery( "delete from Item" ).executeUpdate(); + t.commit(); + s.close(); + + Category cat = new Category("Photography"); + Item i = new Item(cat, "Camera"); + Bid b = new Bid(i, 100.0f); + new Bid(i, 105.0f); + new Comment(i, "This looks like a really good deal"); + new Comment(i, "Is it the latest version?"); + new Comment(i, ""); + System.out.println( b.getTimestamp() ); + + s = openSession(); + t = s.beginTransaction(); + s.persist(cat); + s.persist(i); + t.commit(); + s.close(); + + getSessions().evict(Item.class); + + s = openSession(); + t = s.beginTransaction(); + i = (Item) s.get( Item.class, i.getId() ); + assertTrue( Hibernate.isInitialized( i.getBids() ) ); + assertEquals( i.getBids().size(), 2 ); + assertTrue( Hibernate.isInitialized( i.getComments() ) ); + assertEquals( i.getComments().size(), 3 ); + t.commit(); + s.close(); + + getSessions().evict(Bid.class); + + s = openSession(); + t = s.beginTransaction(); + b = (Bid) s.get( Bid.class, b.getId() ); + assertTrue( Hibernate.isInitialized( b.getItem() ) ); + assertTrue( Hibernate.isInitialized( b.getItem().getComments() ) ); + assertEquals( b.getItem().getComments().size(), 3 ); + System.out.println( b.getTimestamp() ); + t.commit(); + s.close(); + + getSessions().evictCollection(Item.class.getName() + ".bids"); + + s = openSession(); + t = s.beginTransaction(); + i = (Item) s.createCriteria( Item.class ) + .setFetchMode("bids", FetchMode.SELECT) + .setFetchMode("comments", FetchMode.SELECT) + .uniqueResult(); + assertFalse( Hibernate.isInitialized( i.getBids() ) ); + assertFalse( Hibernate.isInitialized( i.getComments() ) ); + b = (Bid) i.getBids().iterator().next(); + assertTrue( Hibernate.isInitialized( b.getItem() ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + i = (Item) s.createQuery("from Item i left join fetch i.bids left join fetch i.comments").uniqueResult(); + assertTrue( Hibernate.isInitialized( i.getBids() ) ); + assertTrue( Hibernate.isInitialized( i.getComments() ) ); + assertEquals( i.getComments().size(), 3 ); + assertEquals( i.getBids().size(), 2 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + Object[] row = (Object[]) s.getNamedQuery(Item.class.getName() + ".all").list().get(0); + i = (Item) row[0]; + assertTrue( Hibernate.isInitialized( i.getBids() ) ); + assertTrue( Hibernate.isInitialized( i.getComments() ) ); + assertEquals( i.getComments().size(), 3 ); + assertEquals( i.getBids().size(), 2 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + i = (Item) s.createCriteria(Item.class).uniqueResult(); + assertTrue( Hibernate.isInitialized( i.getBids() ) ); + assertTrue( Hibernate.isInitialized( i.getComments() ) ); + assertEquals( i.getComments().size(), 3 ); + assertEquals( i.getBids().size(), 2 ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + List bids = s.createQuery("from Bid b left join fetch b.item i left join fetch i.category").list(); + Bid bid = (Bid) bids.get(0); + assertTrue( Hibernate.isInitialized( bid.getItem() ) ); + assertTrue( Hibernate.isInitialized( bid.getItem().getCategory() ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + List pairs = s.createQuery("from Item i left join i.bids b left join fetch i.category").list(); + Item item = (Item) ( (Object[]) pairs.get(0) )[0]; + assertFalse( Hibernate.isInitialized( item.getBids() ) ); + assertTrue( Hibernate.isInitialized( item.getCategory() ) ); + s.clear(); + pairs = s.createQuery("from Item i left join i.bids b left join i.category").list(); + item = (Item) ( (Object[]) pairs.get(0) )[0]; + assertFalse( Hibernate.isInitialized( item.getBids() ) ); + assertTrue( Hibernate.isInitialized( item.getCategory() ) ); + s.clear(); + pairs = s.createQuery("from Bid b left join b.item i left join fetch i.category").list(); + bid = (Bid) ( (Object[]) pairs.get(0) )[0]; + assertTrue( Hibernate.isInitialized( bid.getItem() ) ); + assertTrue( Hibernate.isInitialized( bid.getItem().getCategory() ) ); + s.clear(); + pairs = s.createQuery("from Bid b left join b.item i left join i.category").list(); + bid = (Bid) ( (Object[]) pairs.get(0) )[0]; + assertTrue( Hibernate.isInitialized( bid.getItem() ) ); + assertTrue( Hibernate.isInitialized( bid.getItem().getCategory() ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.createQuery( "delete from Bid" ).executeUpdate(); + s.createQuery( "delete from Comment" ).executeUpdate(); + s.createQuery( "delete from Item" ).executeUpdate(); + s.createQuery( "delete from Category" ).executeUpdate(); + t.commit(); + s.close(); + + } + + public void testCollectionFilter() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Group hb = new Group("hibernate"); + User gavin = new User("gavin"); + User max = new User("max"); + hb.getUsers().put("gavin", gavin); + hb.getUsers().put("max", max); + gavin.getGroups().put("hibernate", hb); + max.getGroups().put("hibernate", hb); + s.persist(hb); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + hb = (Group) s.createCriteria(Group.class) + .setFetchMode("users", FetchMode.SELECT) + .add( Restrictions.idEq("hibernate") ) + .uniqueResult(); + assertFalse( Hibernate.isInitialized( hb.getUsers() ) ); + //gavin = (User) s.createFilter( hb.getUsers(), "where index(this) = 'gavin'" ).uniqueResult(); + Long size = (Long) s.createFilter( hb.getUsers(), "select count(*)" ).uniqueResult(); + assertEquals( new Long(2), size ); + assertFalse( Hibernate.isInitialized( hb.getUsers() ) ); + s.delete(hb); + t.commit(); + s.close(); + + } + + public void testJoinFetchManyToMany() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Group hb = new Group("hibernate"); + User gavin = new User("gavin"); + User max = new User("max"); + hb.getUsers().put("gavin", gavin); + hb.getUsers().put("max", max); + gavin.getGroups().put("hibernate", hb); + max.getGroups().put("hibernate", hb); + s.persist(hb); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + hb = (Group) s.get(Group.class, "hibernate"); + assertTrue( Hibernate.isInitialized( hb.getUsers() ) ); + gavin = (User) hb.getUsers().get("gavin"); + assertFalse( Hibernate.isInitialized( gavin.getGroups() ) ); + max = (User) s.get(User.class, "max"); + assertFalse( Hibernate.isInitialized( max.getGroups() ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + hb = (Group) s.createCriteria(Group.class) + .setFetchMode("users", FetchMode.JOIN) + .setFetchMode("users.groups", FetchMode.JOIN) + .uniqueResult(); + assertTrue( Hibernate.isInitialized( hb.getUsers() ) ); + gavin = (User) hb.getUsers().get("gavin"); + assertTrue( Hibernate.isInitialized( gavin.getGroups() ) ); + max = (User) s.get(User.class, "max"); + assertTrue( Hibernate.isInitialized( max.getGroups() ) ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete(hb); + t.commit(); + s.close(); + } + +} + diff --git a/test/org/hibernate/test/joinfetch/User.java b/test/org/hibernate/test/joinfetch/User.java new file mode 100755 index 0000000000..039bd3e38a --- /dev/null +++ b/test/org/hibernate/test/joinfetch/User.java @@ -0,0 +1,33 @@ +//$Id$ +package org.hibernate.test.joinfetch; + +import java.util.HashMap; +import java.util.Map; + +public class User { + private String name; + private Map groups = new HashMap(); + + public User(String name) { + this.name = name; + } + + User() {} + + public Map getGroups() { + return groups; + } + + public void setGroups(Map groups) { + this.groups = groups; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/test/org/hibernate/test/joinfetch/UserGroup.hbm.xml b/test/org/hibernate/test/joinfetch/UserGroup.hbm.xml new file mode 100755 index 0000000000..69b412d6f5 --- /dev/null +++ b/test/org/hibernate/test/joinfetch/UserGroup.hbm.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/jpa/AbstractJPATest.java b/test/org/hibernate/test/jpa/AbstractJPATest.java new file mode 100644 index 0000000000..5621d7b32c --- /dev/null +++ b/test/org/hibernate/test/jpa/AbstractJPATest.java @@ -0,0 +1,149 @@ +package org.hibernate.test.jpa; + +import org.hibernate.test.TestCase; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.proxy.EntityNotFoundDelegate; +import org.hibernate.event.def.DefaultPersistEventListener; +import org.hibernate.event.def.DefaultAutoFlushEventListener; +import org.hibernate.event.def.DefaultFlushEventListener; +import org.hibernate.event.def.DefaultFlushEntityEventListener; +import org.hibernate.event.AutoFlushEventListener; +import org.hibernate.event.FlushEventListener; +import org.hibernate.event.PersistEventListener; +import org.hibernate.event.FlushEntityEventListener; +import org.hibernate.engine.CascadingAction; +import org.hibernate.util.IdentityMap; +import org.hibernate.junit.functional.FunctionalTestCase; + +import java.io.Serializable; + +/** + * An abstract test for all JPA spec related tests. + * + * @author Steve Ebersole + */ +public class AbstractJPATest extends FunctionalTestCase { + public AbstractJPATest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "jpa/Part.hbm.xml", "jpa/Item.hbm.xml", "jpa/MyEntity.hbm.xml" }; + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.JPAQL_STRICT_COMPLIANCE, "true" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); + cfg.setEntityNotFoundDelegate( new JPAEntityNotFoundDelegate() ); + cfg.getEventListeners().setPersistEventListeners( buildPersistEventListeners() ); + cfg.getEventListeners().setPersistOnFlushEventListeners( buildPersisOnFlushEventListeners() ); + cfg.getEventListeners().setAutoFlushEventListeners( buildAutoFlushEventListeners() ); + cfg.getEventListeners().setFlushEventListeners( buildFlushEventListeners() ); + cfg.getEventListeners().setFlushEntityEventListeners( buildFlushEntityEventListeners() ); + } + + public String getCacheConcurrencyStrategy() { + // no second level caching + return null; + } + + + // mimic specific exception aspects of the JPA environment ~~~~~~~~~~~~~~~~ + + private static class JPAEntityNotFoundDelegate implements EntityNotFoundDelegate { + public void handleEntityNotFound(String entityName, Serializable id) { + throw new EntityNotFoundException( entityName, id ); + } + } + + /** + * Mimic the JPA EntityNotFoundException. + */ + public static class EntityNotFoundException extends RuntimeException { + private final String entityName; + private final Serializable id; + + public EntityNotFoundException(String entityName, Serializable id) { + this( "unable to locate specified entity", entityName, id ); + } + + public EntityNotFoundException(String message, String entityName, Serializable id) { + super( message ); + this.entityName = entityName; + this.id = id; + } + + public String getEntityName() { + return entityName; + } + + public Serializable getId() { + return id; + } + } + + + // mimic specific event aspects of the JPA environment ~~~~~~~~~~~~~~~~~~~~ + + protected PersistEventListener[] buildPersistEventListeners() { + return new PersistEventListener[] { new JPAPersistEventListener() }; + } + + protected PersistEventListener[] buildPersisOnFlushEventListeners() { + return new PersistEventListener[] { new JPAPersistOnFlushEventListener() }; + } + + protected AutoFlushEventListener[] buildAutoFlushEventListeners() { + return new AutoFlushEventListener[] { JPAAutoFlushEventListener.INSTANCE }; + } + + protected FlushEventListener[] buildFlushEventListeners() { + return new FlushEventListener[] { JPAFlushEventListener.INSTANCE }; + } + + protected FlushEntityEventListener[] buildFlushEntityEventListeners() { + return new FlushEntityEventListener[] { new JPAFlushEntityEventListener() }; + } + + public static class JPAPersistEventListener extends DefaultPersistEventListener { + // overridden in JPA impl for entity callbacks... + } + + public static class JPAPersistOnFlushEventListener extends JPAPersistEventListener { + protected CascadingAction getCascadeAction() { + return CascadingAction.PERSIST_ON_FLUSH; + } + } + + public static class JPAAutoFlushEventListener extends DefaultAutoFlushEventListener { + // not sure why EM code has this ... + public static final AutoFlushEventListener INSTANCE = new JPAAutoFlushEventListener(); + + protected CascadingAction getCascadingAction() { + return CascadingAction.PERSIST_ON_FLUSH; + } + + protected Object getAnything() { + return IdentityMap.instantiate( 10 ); + } + } + + public static class JPAFlushEventListener extends DefaultFlushEventListener { + // not sure why EM code has this ... + public static final FlushEventListener INSTANCE = new JPAFlushEventListener(); + + protected CascadingAction getCascadingAction() { + return CascadingAction.PERSIST_ON_FLUSH; + } + + protected Object getAnything() { + return IdentityMap.instantiate( 10 ); + } + } + + public static class JPAFlushEntityEventListener extends DefaultFlushEntityEventListener { + // in JPA, used mainly for preUpdate callbacks... + } +} diff --git a/test/org/hibernate/test/jpa/Item.hbm.xml b/test/org/hibernate/test/jpa/Item.hbm.xml new file mode 100644 index 0000000000..b607c127c9 --- /dev/null +++ b/test/org/hibernate/test/jpa/Item.hbm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/jpa/Item.java b/test/org/hibernate/test/jpa/Item.java new file mode 100644 index 0000000000..bf9e3505d0 --- /dev/null +++ b/test/org/hibernate/test/jpa/Item.java @@ -0,0 +1,53 @@ +package org.hibernate.test.jpa; + +import java.util.Set; +import java.util.HashSet; + +/** + * @author Steve Ebersole + */ +public class Item { + private Long id; + private String name; + private long version; + private Set parts = new HashSet(); + + public Item() { + } + + public Item(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public Set getParts() { + return parts; + } + + public void setParts(Set parts) { + this.parts = parts; + } +} diff --git a/test/org/hibernate/test/jpa/JPAComplianceSuite.java b/test/org/hibernate/test/jpa/JPAComplianceSuite.java new file mode 100644 index 0000000000..9beb50e781 --- /dev/null +++ b/test/org/hibernate/test/jpa/JPAComplianceSuite.java @@ -0,0 +1,30 @@ +package org.hibernate.test.jpa; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.hibernate.test.jpa.lock.JPALockTest; +import org.hibernate.test.jpa.lock.RepeatableReadTest; +import org.hibernate.test.jpa.removed.RemovedEntityTest; +import org.hibernate.test.jpa.proxy.JPAProxyTest; +import org.hibernate.test.jpa.fetch.FetchingTest; +import org.hibernate.test.jpa.ql.JPAQLComplianceTest; +import org.hibernate.test.jpa.ql.NativeQueryTest; +import org.hibernate.test.jpa.cascade.CascadeTest; + +/** + * @author Steve Ebersole + */ +public class JPAComplianceSuite { + public static Test suite() { + TestSuite suite = new TestSuite( "JPA-compliance tests"); + suite.addTest( CascadeTest.suite() ); + suite.addTest( FetchingTest.suite() ); + suite.addTest( JPALockTest.suite() ); + suite.addTest( RepeatableReadTest.suite() ); + suite.addTest( JPAProxyTest.suite() ); + suite.addTest( JPAQLComplianceTest.suite() ); + suite.addTest( NativeQueryTest.suite() ); + suite.addTest( RemovedEntityTest.suite() ); + return suite; + } +} diff --git a/test/org/hibernate/test/jpa/MyEntity.hbm.xml b/test/org/hibernate/test/jpa/MyEntity.hbm.xml new file mode 100644 index 0000000000..a120b802fa --- /dev/null +++ b/test/org/hibernate/test/jpa/MyEntity.hbm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/jpa/MyEntity.java b/test/org/hibernate/test/jpa/MyEntity.java new file mode 100644 index 0000000000..b39808c76d --- /dev/null +++ b/test/org/hibernate/test/jpa/MyEntity.java @@ -0,0 +1,36 @@ +package org.hibernate.test.jpa; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class MyEntity { + private Long id; + private String name; + private MyEntity other; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MyEntity getOther() { + return other; + } + + public void setOther(MyEntity other) { + this.other = other; + } +} diff --git a/test/org/hibernate/test/jpa/MySubclassEntity.java b/test/org/hibernate/test/jpa/MySubclassEntity.java new file mode 100644 index 0000000000..ae724289a8 --- /dev/null +++ b/test/org/hibernate/test/jpa/MySubclassEntity.java @@ -0,0 +1,18 @@ +package org.hibernate.test.jpa; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + */ +public class MySubclassEntity extends MyEntity { + private String someSubProperty; + + public String getSomeSubProperty() { + return someSubProperty; + } + + public void setSomeSubProperty(String someSubProperty) { + this.someSubProperty = someSubProperty; + } +} diff --git a/test/org/hibernate/test/jpa/Part.hbm.xml b/test/org/hibernate/test/jpa/Part.hbm.xml new file mode 100644 index 0000000000..dc56deabc2 --- /dev/null +++ b/test/org/hibernate/test/jpa/Part.hbm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/test/org/hibernate/test/jpa/Part.java b/test/org/hibernate/test/jpa/Part.java new file mode 100644 index 0000000000..69eeac832e --- /dev/null +++ b/test/org/hibernate/test/jpa/Part.java @@ -0,0 +1,66 @@ +package org.hibernate.test.jpa; + +import java.math.BigDecimal; + +/** + * @author Steve Ebersole + */ +public class Part { + private Long id; + private Item item; + private String name; + private String stockNumber; + private BigDecimal unitPrice; + + public Part() { + } + + public Part(Item item, String name, String stockNumber, BigDecimal unitPrice) { + this.item = item; + this.name = name; + this.stockNumber = stockNumber; + this.unitPrice = unitPrice; + + this.item.getParts().add( this ); + } + + public Long getId() { + return id; + } + + private void setId(Long id) { + this.id = id; + } + + public Item getItem() { + return item; + } + + private void setItem(Item item) { + this.item = item; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getStockNumber() { + return stockNumber; + } + + public void setStockNumber(String stockNumber) { + this.stockNumber = stockNumber; + } + + public BigDecimal getUnitPrice() { + return unitPrice; + } + + public void setUnitPrice(BigDecimal unitPrice) { + this.unitPrice = unitPrice; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/CascadeTest.java b/test/org/hibernate/test/jpa/cascade/CascadeTest.java new file mode 100644 index 0000000000..c742f2cd90 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/CascadeTest.java @@ -0,0 +1,321 @@ +package org.hibernate.test.jpa.cascade; + +import org.hibernate.test.jpa.AbstractJPATest; +import org.hibernate.Session; +import org.hibernate.TransientObjectException; +import org.hibernate.EntityMode; +import org.hibernate.HibernateException; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.engine.Status; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.event.FlushEntityEventListener; +import org.hibernate.event.FlushEntityEvent; +import org.hibernate.cfg.Configuration; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import junit.framework.Test; + +/** + * According to the JPA spec, persist()ing an entity should throw an exception + * when said entity contains a reference to a transient entity through a mapped + * association where that association is not marked for cascading the persist + * operation. + *

+ * This test-case tests that requirement in the various association style + * scenarios such as many-to-one, one-to-one, many-to-one (property-ref), + * one-to-one (property-ref). Additionally, it performs each of these tests + * in both generated and assigned identifier usages... + * + * @author Steve Ebersole + */ +public class CascadeTest extends AbstractJPATest { + + public static final Log log = LogFactory.getLog( CascadeTest.class ); + + public CascadeTest(String name) { + super( name ); + } + + public String[] getMappings() { + return new String[] { "jpa/cascade/ParentChild.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( CascadeTest.class ); + } + + public void testManyToOneGeneratedIdsOnSave() { + // NOTES: Child defines a many-to-one back to its Parent. This + // association does not define persist cascading (which is natural; + // a child should not be able to create its parent). + try { + Session s = openSession(); + s.beginTransaction(); + Parent p = new Parent( "parent" ); + Child c = new Child( "child" ); + c.setParent( p ); + s.save( c ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testManyToOneGeneratedIds() { + // NOTES: Child defines a many-to-one back to its Parent. This + // association does not define persist cascading (which is natural; + // a child should not be able to create its parent). + try { + Session s = openSession(); + s.beginTransaction(); + Parent p = new Parent( "parent" ); + Child c = new Child( "child" ); + c.setParent( p ); + s.persist( c ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testManyToOneAssignedIds() { + // NOTES: Child defines a many-to-one back to its Parent. This + // association does not define persist cascading (which is natural; + // a child should not be able to create its parent). + try { + Session s = openSession(); + s.beginTransaction(); + ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" ); + ChildAssigned c = new ChildAssigned( new Long( 2 ), "child" ); + c.setParent( p ); + s.persist( c ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testOneToOneGeneratedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + Parent p = new Parent( "parent" ); + ParentInfo info = new ParentInfo( "xyz" ); + p.setInfo( info ); + info.setOwner( p ); + s.persist( p ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testOneToOneAssignedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" ); + ParentInfoAssigned info = new ParentInfoAssigned( "something secret" ); + p.setInfo( info ); + info.setOwner( p ); + s.persist( p ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testManyToOnePropertyRefGeneratedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + Parent p = new Parent( "parent" ); + Other other = new Other(); + other.setOwner( p ); + s.persist( other ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testManyToOnePropertyRefAssignedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" ); + OtherAssigned other = new OtherAssigned( new Long( 2 ) ); + other.setOwner( p ); + s.persist( other ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testOneToOnePropertyRefGeneratedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + Child c2 = new Child( "c2" ); + ChildInfo info = new ChildInfo( "blah blah blah" ); + c2.setInfo( info ); + info.setOwner( c2 ); + s.persist( c2 ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception : " + e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testOneToOnePropertyRefAssignedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + ChildAssigned c2 = new ChildAssigned( new Long( 3 ), "c3" ); + ChildInfoAssigned info = new ChildInfoAssigned( new Long( 4 ), "blah blah blah" ); + c2.setInfo( info ); + info.setOwner( c2 ); + s.persist( c2 ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception : " + e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + + private void cleanupData() { + Session s = null; + try { + s = openSession(); + s.beginTransaction(); + s.createQuery( "delete ChildInfoAssigned" ).executeUpdate(); + s.createQuery( "delete ChildAssigned" ).executeUpdate(); + s.createQuery( "delete ParentAssigned" ).executeUpdate(); + s.createQuery( "delete ChildInfoAssigned" ).executeUpdate(); + s.createQuery( "delete ChildAssigned" ).executeUpdate(); + s.createQuery( "delete ParentAssigned" ).executeUpdate(); + s.getTransaction().commit(); + } + catch( Throwable t ) { + log.warn( "unable to cleanup test data [" + fullTestName() + "] : " + t ); + } + finally { + if ( s != null ) { + try { + s.close(); + } + catch( Throwable ignore ) { + } + } + } + } +} diff --git a/test/org/hibernate/test/jpa/cascade/Child.java b/test/org/hibernate/test/jpa/cascade/Child.java new file mode 100644 index 0000000000..8c1cee29c7 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/Child.java @@ -0,0 +1,52 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe Child + * + * @author Steve Ebersole + */ +public class Child { + private Long id; + private String name; + private Parent parent; + private ChildInfo info; + + public Child() { + } + + public Child(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } + + public ChildInfo getInfo() { + return info; + } + + public void setInfo(ChildInfo info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/ChildAssigned.java b/test/org/hibernate/test/jpa/cascade/ChildAssigned.java new file mode 100644 index 0000000000..cb11f7f465 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/ChildAssigned.java @@ -0,0 +1,49 @@ +package org.hibernate.test.jpa.cascade; + +/** + * Child, but with an assigned identifier. + * + * @author Steve Ebersole + */ +public class ChildAssigned { + private Long id; + private String name; + private ParentAssigned parent; + private ChildInfoAssigned info; + + public ChildAssigned() { + } + + public ChildAssigned(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ParentAssigned getParent() { + return parent; + } + + public void setParent(ParentAssigned parent) { + this.parent = parent; + } + + public ChildInfoAssigned getInfo() { + return info; + } + + public void setInfo(ChildInfoAssigned info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/ChildInfo.java b/test/org/hibernate/test/jpa/cascade/ChildInfo.java new file mode 100644 index 0000000000..8d1bc918b5 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/ChildInfo.java @@ -0,0 +1,39 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe ChildInfo + * + * @author Steve Ebersole + */ +public class ChildInfo { + private Long id; + private Child owner; + private String info; + + public ChildInfo() { + } + + public ChildInfo(String info) { + this.info = info; + } + + public Long getId() { + return id; + } + + public Child getOwner() { + return owner; + } + + public void setOwner(Child owner) { + this.owner = owner; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java b/test/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java new file mode 100644 index 0000000000..d065336997 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java @@ -0,0 +1,40 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe ChildInfo + * + * @author Steve Ebersole + */ +public class ChildInfoAssigned { + private Long id; + private ChildAssigned owner; + private String info; + + public ChildInfoAssigned() { + } + + public ChildInfoAssigned(Long id, String info) { + this.id = id; + this.info = info; + } + + public Long getId() { + return id; + } + + public ChildAssigned getOwner() { + return owner; + } + + public void setOwner(ChildAssigned owner) { + this.owner = owner; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/Other.java b/test/org/hibernate/test/jpa/cascade/Other.java new file mode 100644 index 0000000000..accb024b08 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/Other.java @@ -0,0 +1,23 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe Other + * + * @author Steve Ebersole + */ +public class Other { + private Long id; + private Parent owner; + + public Long getId() { + return id; + } + + public Parent getOwner() { + return owner; + } + + public void setOwner(Parent owner) { + this.owner = owner; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/OtherAssigned.java b/test/org/hibernate/test/jpa/cascade/OtherAssigned.java new file mode 100644 index 0000000000..28a287de82 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/OtherAssigned.java @@ -0,0 +1,30 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe Other + * + * @author Steve Ebersole + */ +public class OtherAssigned { + private Long id; + private ParentAssigned owner; + + public OtherAssigned() { + } + + public OtherAssigned(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public ParentAssigned getOwner() { + return owner; + } + + public void setOwner(ParentAssigned owner) { + this.owner = owner; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/Parent.java b/test/org/hibernate/test/jpa/cascade/Parent.java new file mode 100644 index 0000000000..e08828f6d0 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/Parent.java @@ -0,0 +1,43 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe Parent + * + * @author Steve Ebersole + */ +public class Parent { + private Long id; + private String name; + private ParentInfo info; + + public Parent() { + } + + public Parent(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ParentInfo getInfo() { + return info; + } + + public void setInfo(ParentInfo info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/ParentAssigned.java b/test/org/hibernate/test/jpa/cascade/ParentAssigned.java new file mode 100644 index 0000000000..b1b7456a9d --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/ParentAssigned.java @@ -0,0 +1,40 @@ +package org.hibernate.test.jpa.cascade; + +/** + * Parent, but with an assigned identifier. + * + * @author Steve Ebersole + */ +public class ParentAssigned { + private Long id; + private String name; + private ParentInfoAssigned info; + + public ParentAssigned() { + } + + public ParentAssigned(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ParentInfoAssigned getInfo() { + return info; + } + + public void setInfo(ParentInfoAssigned info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml b/test/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml new file mode 100644 index 0000000000..612601b492 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + owner + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + owner + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/jpa/cascade/ParentInfo.java b/test/org/hibernate/test/jpa/cascade/ParentInfo.java new file mode 100644 index 0000000000..770b2cdb21 --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/ParentInfo.java @@ -0,0 +1,39 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe ChildInfo + * + * @author Steve Ebersole + */ +public class ParentInfo { + private Long id; + private Parent owner; + private String info; + + public ParentInfo() { + } + + public ParentInfo(String info) { + this.info = info; + } + + public Long getId() { + return id; + } + + public Parent getOwner() { + return owner; + } + + public void setOwner(Parent owner) { + this.owner = owner; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java b/test/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java new file mode 100644 index 0000000000..a9ac493f7e --- /dev/null +++ b/test/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java @@ -0,0 +1,39 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe ChildInfo + * + * @author Steve Ebersole + */ +public class ParentInfoAssigned { + private Long id; + private ParentAssigned owner; + private String info; + + public ParentInfoAssigned() { + } + + public ParentInfoAssigned(String info) { + this.info = info; + } + + public Long getId() { + return id; + } + + public ParentAssigned getOwner() { + return owner; + } + + public void setOwner(ParentAssigned owner) { + this.owner = owner; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/test/org/hibernate/test/jpa/fetch/FetchingTest.java b/test/org/hibernate/test/jpa/fetch/FetchingTest.java new file mode 100644 index 0000000000..1d0280dfe9 --- /dev/null +++ b/test/org/hibernate/test/jpa/fetch/FetchingTest.java @@ -0,0 +1,84 @@ +package org.hibernate.test.jpa.fetch; + +import java.util.Date; + +import junit.framework.Test; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.jpa.AbstractJPATest; + +/** + * @author Emmanuel Bernard + */ +public class FetchingTest extends AbstractJPATest { + + public FetchingTest(String x) { + super( x ); + } + + public String[] getMappings() { + return new String[] { "jpa/fetch/Person.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( FetchingTest.class ); + } + + public void testLazy() throws Exception { + Session s; + Transaction tx; + s = openSession(); + tx = s.beginTransaction(); + Person p = new Person( "Gavin", "King", "JBoss Inc" ); + Stay stay = new Stay( p, new Date(), new Date(), "A380", "Blah", "Blah" ); + p.addStay( stay ); + s.persist( p ); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + p = (Person) s.createQuery( "select p from Person p where p.firstName = :name" ) + .setParameter( "name", "Gavin" ).uniqueResult(); + assertFalse( Hibernate.isInitialized( p.getStays() ) ); + s.delete( p ); + tx.commit(); + s.close(); + } + + public void testHibernateFetchingLazy() throws Exception { + Session s; + Transaction tx; + s = openSession(); + tx = s.beginTransaction(); + Person p = new Person( "Gavin", "King", "JBoss Inc" ); + Stay stay = new Stay( null, new Date(), new Date(), "A380", "Blah", "Blah" ); + Stay stay2 = new Stay( null, new Date(), new Date(), "A320", "Blah", "Blah" ); + Stay stay3 = new Stay( null, new Date(), new Date(), "A340", "Blah", "Blah" ); + stay.setOldPerson( p ); + stay2.setVeryOldPerson( p ); + stay3.setVeryOldPerson( p ); + p.addOldStay( stay ); + p.addVeryOldStay( stay2 ); + p.addVeryOldStay( stay3 ); + s.persist( p ); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + p = (Person) s.createQuery( "select p from Person p where p.firstName = :name" ) + .setParameter( "name", "Gavin" ).uniqueResult(); + assertFalse( Hibernate.isInitialized( p.getOldStays() ) ); + assertEquals( 1, p.getOldStays().size() ); + assertFalse( "lazy extra is failing", Hibernate.isInitialized( p.getOldStays() ) ); + s.clear(); + stay = (Stay) s.get( Stay.class, stay.getId() ); + assertTrue( ! Hibernate.isInitialized( stay.getOldPerson() ) ); + s.clear(); + stay3 = (Stay) s.get( Stay.class, stay3.getId() ); + assertTrue( "FetchMode.JOIN should overrides lazy options", Hibernate.isInitialized( stay3.getVeryOldPerson() ) ); + s.delete( stay3.getVeryOldPerson() ); + tx.commit(); + s.close(); + } +} diff --git a/test/org/hibernate/test/jpa/fetch/Person.hbm.xml b/test/org/hibernate/test/jpa/fetch/Person.hbm.xml new file mode 100644 index 0000000000..64852ac569 --- /dev/null +++ b/test/org/hibernate/test/jpa/fetch/Person.hbm.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/org/hibernate/test/jpa/fetch/Person.java b/test/org/hibernate/test/jpa/fetch/Person.java new file mode 100644 index 0000000000..778c8db14f --- /dev/null +++ b/test/org/hibernate/test/jpa/fetch/Person.java @@ -0,0 +1,136 @@ +package org.hibernate.test.jpa.fetch; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Date; +import java.util.ArrayList; + +/** + * Copied over from annotations test suite... + * + * @author Emmanuel Bernard + */ +public class Person implements Serializable { + + // member declaration + private Long id; + private String firstName; + private String lastName; + private String companyName; + private Collection stays; + private Collection oldStays; + private Collection veryOldStays; + + // constructors + public Person() { + } + + public Person(String firstName, String lastName, String companyName) { + this.firstName = firstName; + this.lastName = lastName; + this.companyName = companyName; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + public Collection getStays() { + return stays; + } + + public void setStays(Collection stays) { + this.stays = stays; + } + + public Collection getOldStays() { + return oldStays; + } + + public void setOldStays(Collection oldStays) { + this.oldStays = oldStays; + } + + public Collection getVeryOldStays() { + return veryOldStays; + } + + public void setVeryOldStays(Collection veryOldStays) { + this.veryOldStays = veryOldStays; + } + + + // business logic + public void addStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) { + Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments ); + addStay( stay ); + } + + public void addStay(Stay stay) { + Collection stays = getStays(); + if ( stays == null ) { + stays = new ArrayList(); + } + stays.add( stay ); + + this.stays = stays; + } + + public void addOldStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) { + Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments ); + addOldStay( stay ); + } + + public void addOldStay(Stay stay) { + Collection stays = getOldStays(); + if ( stays == null ) { + stays = new ArrayList(); + } + stays.add( stay ); + + this.oldStays = stays; + } + + public void addVeryOldStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) { + Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments ); + addVeryOldStay( stay ); + } + + public void addVeryOldStay(Stay stay) { + Collection stays = getVeryOldStays(); + if ( stays == null ) { + stays = new ArrayList(); + } + stays.add( stay ); + + this.veryOldStays = stays; + } +} diff --git a/test/org/hibernate/test/jpa/fetch/Stay.java b/test/org/hibernate/test/jpa/fetch/Stay.java new file mode 100644 index 0000000000..350f9b4721 --- /dev/null +++ b/test/org/hibernate/test/jpa/fetch/Stay.java @@ -0,0 +1,107 @@ +package org.hibernate.test.jpa.fetch; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author Emmanuel Bernard + */ +public class Stay implements Serializable { + + // member declaration + private Long id; + private Person person; + private Person oldPerson; + private Person veryOldPerson; + private Date startDate; + private Date endDate; + private String vessel; + private String authoriser; + private String comments; + + + // constructors + public Stay() { + } + + public Stay(Person person, Date startDate, Date endDate, String vessel, String authoriser, String comments) { + this.authoriser = authoriser; + this.endDate = endDate; + this.person = person; + this.startDate = startDate; + this.vessel = vessel; + this.comments = comments; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } + + public Person getOldPerson() { + return oldPerson; + } + + public void setOldPerson(Person oldPerson) { + this.oldPerson = oldPerson; + } + + public Person getVeryOldPerson() { + return veryOldPerson; + } + + public void setVeryOldPerson(Person veryOldPerson) { + this.veryOldPerson = veryOldPerson; + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public String getVessel() { + return vessel; + } + + public void setVessel(String vessel) { + this.vessel = vessel; + } + + public String getAuthoriser() { + return authoriser; + } + + public void setAuthoriser(String authoriser) { + this.authoriser = authoriser; + } + + public String getComments() { + return comments; + } + + public void setComments(String comments) { + this.comments = comments; + } +} diff --git a/test/org/hibernate/test/jpa/lock/JPALockTest.java b/test/org/hibernate/test/jpa/lock/JPALockTest.java new file mode 100644 index 0000000000..cd8d804616 --- /dev/null +++ b/test/org/hibernate/test/jpa/lock/JPALockTest.java @@ -0,0 +1,199 @@ +package org.hibernate.test.jpa.lock; + +import junit.framework.Test; + +import org.hibernate.LockMode; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.test.jpa.AbstractJPATest; +import org.hibernate.test.jpa.Item; +import org.hibernate.test.jpa.MyEntity; + +/** + * Tests specifically relating to section 3.3.5.3 [Lock Modes] of the + * JPA persistence specification (as of the Proposed Final Draft). + * + * @author Steve Ebersole + */ +public class JPALockTest extends AbstractJPATest { + public JPALockTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( JPALockTest.class ); + } + + /** + * Test the equivalent of EJB3 LockModeType.READ + *

+ * From the spec: + *

+ * If transaction T1 calls lock(entity, LockModeType.READ) on a versioned object, the entity + * manager must ensure that neither of the following phenomena can occur: