[hibernate-commits] Hibernate SVN: r10825 - in branches/Branch_3_2/Hibernate3: src/org/hibernate/hql/ast/tree src/org/hibernate/hql/ast/util src/org/hibernate/persister/entity test/org/hibernate/test/hql

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Nov 16 14:33:23 EST 2006


Author: steve.ebersole at jboss.com
Date: 2006-11-16 14:33:19 -0500 (Thu, 16 Nov 2006)
New Revision: 10825

Modified:
   branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/util/JoinProcessor.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/util/SessionFactoryHelper.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/Queryable.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
   branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/HQLTest.java
Log:
HHH-939  : special '.class' property reference from HQL for joined-subclass;
HHH-1631 : sub/super-classes property reference from HQL for joined-subclass

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -138,6 +138,8 @@
 		// discover foreign key (id) properties.
 		lhs.resolve( true, true, null, this );
 		setFromElement( lhs.getFromElement() );			// The 'from element' that the property is in.
+
+		checkSubclassOrSuperclassPropertyReference( lhs, propName );
 	}
 	
 	public void resolveInFunctionCall(boolean generateJoin, boolean implicitJoin) throws SemanticException {
@@ -222,7 +224,7 @@
 		return propertyType;
 	}
 
-	private void dereferenceCollection(CollectionType collectionType, boolean implicitJoin, boolean indexed, String classAlias, AST parent) 
+	private void dereferenceCollection(CollectionType collectionType, boolean implicitJoin, boolean indexed, String classAlias, AST parent)
 	throws SemanticException {
 		
 		dereferenceType = DEREF_COLLECTION;
@@ -284,14 +286,6 @@
 
 	private void dereferenceEntity(EntityType entityType, boolean implicitJoin, String classAlias, boolean generateJoin, AST parent) throws SemanticException {
 		checkForCorrelatedSubquery( "dereferenceEntity" );
-		// If this is an entity inside a component reference, then generate the join.
-//		if ( unresolvedComponent( generateJoin ) ) {
-//			if ( log.isDebugEnabled() ) {
-//				log.debug( "dereferenceEntity() : resolving unresolved component '" + propertyPath + "' ... " );
-//			}
-//			dereferenceEntityJoin( classAlias, entityType, implicitJoin, parent );
-//			return;
-//		}
 
 		// Only join to the entity table if:
 		//      1) we were instructed to generate any needed joins (generateJoins==true)
@@ -324,19 +318,6 @@
 
 	}
 
-	private boolean unresolvedComponent(boolean generateJoin) {
-		AST c = getFirstChild();
-		if ( generateJoin && isDotNode( c ) ) {
-			DotNode dot = ( DotNode ) c;
-			if ( dot.dereferenceType == DEREF_COMPONENT || dot.dereferenceType == DEREF_IDENTIFIER ) {
-				if ( StringHelper.isNotEmpty( propertyPath ) ) {
-					return true;
-				}
-			}
-		}
-		return false;
-	}
-
 	private boolean isDotNode(AST n) {
 		return n != null && n.getType() == SqlTokenTypes.DOT;
 	}
@@ -445,26 +426,11 @@
 			return propertyType.isReferenceToPrimaryKey();
 		}
 		else {
-			String keyPropertyName = getSessionFactoryHelper()
-			        .getIdentifierOrUniqueKeyPropertyName( propertyType );
-			return keyPropertyName != null && keyPropertyName.equals( propertyName );
+			String keyPropertyName = getSessionFactoryHelper().getIdentifierOrUniqueKeyPropertyName( propertyType );
+			return keyPropertyName != null && keyPropertyName.equals( propertyName ) && propertyType.isReferenceToPrimaryKey();
 		}
 	}
 
-//	private boolean isPrimaryKeyReference(String property, EntityType propertyType) {
-//		boolean isIdShortcut = EntityPersister.ENTITY_ID.equals( property ) &&
-//				propertyType.isReferenceToPrimaryKey();
-//		return isIdShortcut;
-//	}
-//
-//	private boolean isNamedIdPropertyShortcut(EntityType propertyType, String property) {
-//		final String idPropertyName = getSessionFactoryHelper()
-//				.getIdentifierOrUniqueKeyPropertyName( propertyType );
-//		boolean isNamedIdPropertyShortcut = idPropertyName != null &&
-//				idPropertyName.equals( property );
-//		return isNamedIdPropertyShortcut;
-//	}
-
 	private void checkForCorrelatedSubquery(String methodName) {
 		if ( isCorrelatedSubselect() ) {
 			if ( log.isDebugEnabled() ) {
@@ -614,6 +580,12 @@
 				}
 			}
 		}
+
+		FromReferenceNode lhs = getLhs();
+		while ( lhs != null ) {
+			checkSubclassOrSuperclassPropertyReference( lhs, lhs.getNextSibling().getText() );
+			lhs = ( FromReferenceNode ) lhs.getFirstChild();
+		}
 	}
 	
 	/**
@@ -626,4 +598,14 @@
 		dereferenceType = DEREF_JAVA_CONSTANT;
 		setResolved(); // Don't resolve the node again.
 	}
+
+	private boolean checkSubclassOrSuperclassPropertyReference(FromReferenceNode lhs, String propertyName) {
+		if ( lhs != null && !( lhs instanceof IndexNode ) && lhs.getDataType() != null && ! lhs.getDataType().isComponentType() ) {
+			final FromElement source = lhs.getFromElement();
+			if ( source != null ) {
+				source.handlePropertyBeingDereferenced( propertyName );
+			}
+		}
+		return false;
+	}
 }

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -7,6 +7,7 @@
 import org.hibernate.QueryException;
 import org.hibernate.engine.JoinSequence;
 import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.CollectionProperties;
 import org.hibernate.hql.antlr.SqlTokenTypes;
 import org.hibernate.hql.ast.util.ASTUtil;
 import org.hibernate.hql.ast.HqlSqlWalker;
@@ -60,6 +61,8 @@
 	private boolean manyToMany = false;
 	private String withClauseFragment = null;
 	private String withClauseJoinAlias;
+	private boolean dereferencedBySuperclassProperty;
+	private boolean dereferencedBySubclassProperty;
 
 	public FromElement() {
 	}
@@ -258,6 +261,11 @@
 	}
 
 	public void setIncludeSubclasses(boolean includeSubclasses) {
+		if ( isDereferencedBySuperclassOrSubclassProperty() ) {
+			if ( !includeSubclasses && log.isTraceEnabled() ) {
+				log.trace( "attempt to disable subclass-inclusions", new Exception( "stack-trace source" ) );
+			}
+		}
 		this.includeSubclasses = includeSubclasses;
 	}
 
@@ -265,6 +273,10 @@
 		return includeSubclasses;
 	}
 
+	public boolean isDereferencedBySuperclassOrSubclassProperty() {
+		return dereferencedBySubclassProperty || dereferencedBySuperclassProperty;
+	}
+
 	public String getIdentityColumn() {
 		checkInitialized();
 		String table = getTableAlias();
@@ -500,4 +512,33 @@
 			return getQueryable().hasCache();
 		}
 	}
+
+	public void handlePropertyBeingDereferenced(String propertyName) {
+		if ( getQueryableCollection() != null && CollectionProperties.isCollectionProperty( propertyName ) ) {
+		}
+		else {
+			Queryable persister = getQueryable();
+			if ( persister != null ) {
+				Queryable.Declarer propertyDeclarer = persister.getSubclassPropertyDeclarer( propertyName );
+				if ( log.isTraceEnabled() ) {
+					log.trace( "handling property dereference [" + persister.getEntityName() + " (" + getClassAlias() + ") -> " + propertyName + " (" + propertyDeclarer + ")]" );
+				}
+				if ( propertyDeclarer == Queryable.Declarer.SUBCLASS ) {
+					dereferencedBySubclassProperty = true;
+					includeSubclasses = true;
+				}
+				else if ( propertyDeclarer == Queryable.Declarer.SUPERCLASS ) {
+					dereferencedBySuperclassProperty = true;
+				}
+			}
+		}
+	}
+
+	public boolean isDereferencedBySuperclassProperty() {
+		return dereferencedBySuperclassProperty;
+	}
+
+	public boolean isDereferencedBySubclassProperty() {
+		return dereferencedBySubclassProperty;
+	}
 }

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -38,7 +38,6 @@
 	private QueryableCollection queryableCollection;
 	private CollectionPropertyMapping collectionPropertyMapping;
 	private JoinSequence joinSequence;
-
 	private String collectionSuffix;
 
 	public FromElementType(FromElement fromElement, EntityPersister persister, EntityType entityType) {

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/util/JoinProcessor.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/util/JoinProcessor.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/util/JoinProcessor.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -5,6 +5,7 @@
 import java.util.Iterator;
 import java.util.ListIterator;
 import java.util.Collections;
+import java.util.List;
 
 import org.hibernate.AssertionFailure;
 import org.hibernate.engine.JoinSequence;
@@ -13,6 +14,7 @@
 import org.hibernate.hql.ast.tree.FromClause;
 import org.hibernate.hql.ast.tree.FromElement;
 import org.hibernate.hql.ast.tree.QueryNode;
+import org.hibernate.hql.ast.tree.DotNode;
 import org.hibernate.sql.JoinFragment;
 import org.hibernate.util.StringHelper;
 
@@ -26,7 +28,7 @@
  * The join generating classes are complex, this encapsulates some of the JoinSequence-related
  * code.
  *
- * @author josh Jul 22, 2004 7:33:42 AM
+ * @author Joshua Davis
  */
 public class JoinProcessor implements SqlTokenTypes {
 
@@ -38,7 +40,7 @@
 	/**
 	 * Constructs a new JoinProcessor.
 	 *
-	 * @param astFactory The factory for AST node creation.
+	 * @param astFactory		  The factory for AST node creation.
 	 * @param queryTranslatorImpl The query translator.
 	 */
 	public JoinProcessor(ASTFactory astFactory, QueryTranslatorImpl queryTranslatorImpl) {
@@ -70,35 +72,51 @@
 	public void processJoins(QueryNode query, boolean inSubquery) {
 		final FromClause fromClause = query.getFromClause();
 
-		// TODO : found it easiest to simply reorder the FromElements here into ascending order
-		// in terms of injecting them into the resulting sql ast in orders relative to those
-		// expected by the old parser; this is definitely another of those "only needed
-		// for regression purposes".  The SyntheticAndFactory, then, simply injects them as it
-		// encounters them.
-		ArrayList orderedFromElements = new ArrayList();
-		ListIterator liter = fromClause.getFromElements().listIterator( fromClause.getFromElements().size() );
-		while ( liter.hasPrevious() ) {
-			orderedFromElements.add( liter.previous() );
+		final List fromElements;
+		if ( DotNode.useThetaStyleImplicitJoins ) {
+			// for regression testing against output from the old parser...
+			// found it easiest to simply reorder the FromElements here into ascending order
+			// in terms of injecting them into the resulting sql ast in orders relative to those
+			// expected by the old parser; this is definitely another of those "only needed
+			// for regression purposes".  The SyntheticAndFactory, then, simply injects them as it
+			// encounters them.
+			fromElements = new ArrayList();
+			ListIterator liter = fromClause.getFromElements().listIterator( fromClause.getFromElements().size() );
+			while ( liter.hasPrevious() ) {
+				fromElements.add( liter.previous() );
+			}
 		}
+		else {
+			fromElements = fromClause.getFromElements();
+		}
 
 		// Iterate through the alias,JoinSequence pairs and generate SQL token nodes.
-		Iterator iter = orderedFromElements.iterator();
+		Iterator iter = fromElements.iterator();
 		while ( iter.hasNext() ) {
 			final FromElement fromElement = ( FromElement ) iter.next();
 			JoinSequence join = fromElement.getJoinSequence();
 			join.setSelector(
-			        new JoinSequence.Selector() {
-				        public boolean includeSubclasses(String alias) {
-					        boolean shallowQuery = queryTranslatorImpl.isShallowQuery();
-					        boolean containsTableAlias = fromClause.containsTableAlias( alias );
-					        boolean includeSubclasses = fromElement.isIncludeSubclasses();
-					        boolean subQuery = fromClause.isSubQuery();
-					        return includeSubclasses && containsTableAlias && !subQuery && !shallowQuery;
-				        }
-			        }
-				);
+					new JoinSequence.Selector() {
+						public boolean includeSubclasses(String alias) {
+							// The uber-rule here is that we need to include  subclass joins if
+							// the FromElement is in any way dereferenced by a property from
+							// the subclass table; otherwise we end up with column references
+							// qualified by a non-existent table reference in the resulting SQL...
+							boolean containsTableAlias = fromClause.containsTableAlias( alias );
+							if ( fromElement.isDereferencedBySubclassProperty() ) {
+								// TODO : or should we return 'containsTableAlias'??
+								log.trace( "forcing inclusion of extra joins [alias=" + alias + ", containsTableAlias=" + containsTableAlias + "]" );
+								return true;
+							}
+							boolean shallowQuery = queryTranslatorImpl.isShallowQuery();
+							boolean includeSubclasses = fromElement.isIncludeSubclasses();
+							boolean subQuery = fromClause.isSubQuery();
+							return includeSubclasses && containsTableAlias && !subQuery && !shallowQuery;
+						}
+					}
+			);
 			addJoinNodes( query, join, fromElement, inSubquery );
-		} // while
+		}
 
 	}
 
@@ -106,10 +124,10 @@
 		// Generate FROM and WHERE fragments for the from element.
 		JoinFragment joinFragment = join.toJoinFragment(
 				inSubquery ? Collections.EMPTY_MAP : queryTranslatorImpl.getEnabledFilters(),
-				fromElement.useFromFragment(),
-		        fromElement.getWithClauseFragment(),
-		        fromElement.getWithClauseJoinAlias()
-			);
+				fromElement.useFromFragment() || fromElement.isDereferencedBySuperclassOrSubclassProperty(),
+				fromElement.getWithClauseFragment(),
+				fromElement.getWithClauseJoinAlias()
+		);
 
 		String frag = joinFragment.toFromFragmentString();
 		String whereFrag = joinFragment.toWhereFragmentString();
@@ -126,7 +144,9 @@
 		// If there is a FROM fragment and the FROM element is an explicit, then add the from part.
 		if ( fromElement.useFromFragment() /*&& StringHelper.isNotEmpty( frag )*/ ) {
 			String fromFragment = processFromFragment( frag, join );
-			if ( log.isDebugEnabled() ) log.debug( "Using FROM fragment [" + fromFragment + "]" );
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Using FROM fragment [" + fromFragment + "]" );
+			}
 			fromElement.setText( fromFragment.trim() ); // Set the text of the fromElement.
 		}
 		andFactory.addWhereFragment( joinFragment, whereFrag, query, fromElement );
@@ -138,22 +158,6 @@
 		if ( fromFragment.startsWith( ", " ) ) {
 			fromFragment = fromFragment.substring( 2 );
 		}
-		/*
-		// *** BEGIN FROM FRAGMENT VOODOO ***
-		// If there is more than one join, reverse the order of the tables in the FROM fragment.
-		if ( join.getJoinCount() > 1 && fromFragment.indexOf( ',' ) >= 0 ) {
-			String[] froms = StringHelper.split( ",", fromFragment );
-			StringBuffer buf = new StringBuffer();
-			for ( int i = froms.length - 1; i >= 0; i-- ) {
-				buf.append( froms[i] );
-				if ( i > 0 ) {
-					buf.append( ", " );
-				}
-			}
-			fromFragment = buf.toString();
-		}
-		// *** END OF FROM FRAGMENT VOODOO ***
-		*/
 		return fromFragment;
 	}
 

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/util/SessionFactoryHelper.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/util/SessionFactoryHelper.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/util/SessionFactoryHelper.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -379,12 +379,7 @@
 			}
 		}
 
-		Type rtnType = sqlFunction.getReturnType( argumentType, sfi );
-		if ( rtnType == null ) {
-			throw new QueryException( "unable to determine function return type [" + functionName + "]" );
-		}
-
-		return rtnType;
+		return sqlFunction.getReturnType( argumentType, sfi );
 	}
 
 	public String[][] generateColumnNames(Type[] sqlResultTypes) {

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -1352,6 +1352,19 @@
 		return index==-1 ? 0 : getSubclassPropertyTableNumber(index);
 	}
 
+	public Declarer getSubclassPropertyDeclarer(String propertyPath) {
+		int tableIndex = getSubclassPropertyTableNumber( propertyPath );
+		if ( tableIndex == 0 ) {
+			return Declarer.CLASS;
+		}
+		else if ( isClassOrSuperclassTable( tableIndex ) ) {
+			return Declarer.SUPERCLASS;
+		}
+		else {
+			return Declarer.SUBCLASS;
+		}
+	}
+
 	protected String generateTableAlias(String rootAlias, int tableNumber) {
 		if ( tableNumber == 0 ) {
 			return rootAlias;

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -575,4 +575,12 @@
 	public String getRootTableName() {
 		return naturalOrderTableNames[0];
 	}
+
+	public Declarer getSubclassPropertyDeclarer(String propertyPath) {
+		if ( "class".equals( propertyPath ) ) {
+			// special case where we need to force incloude all subclass joins
+			return Declarer.SUBCLASS;
+		}
+		return super.getSubclassPropertyDeclarer( propertyPath );
+	}
 }

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/Queryable.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/Queryable.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/Queryable.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -102,6 +102,18 @@
 	public int getSubclassPropertyTableNumber(String propertyPath);
 
 	/**
+	 * Determine whether the given property is declared by our
+	 * mapped class, our super class, or one of our subclasses...
+	 * <p/>
+	 * Note: the method is called 'subclass property...' simply
+	 * for consistency sake (e.g. {@link #getSubclassPropertyTableNumber}
+	 *
+	 * @param propertyPath The property name.
+	 * @return The property declarer
+	 */
+	public Declarer getSubclassPropertyDeclarer(String propertyPath);
+
+	/**
 	 * Get the name of the table with the given index from the internal
 	 * array.
 	 *
@@ -126,4 +138,17 @@
 	 * @return The alias used for "filter conditions" within the where clause.
 	 */
 	public String generateFilterConditionAlias(String rootAlias);
+
+	public static class Declarer {
+		public static final Declarer CLASS = new Declarer( "class" );
+		public static final Declarer SUBCLASS = new Declarer( "subclass" );
+		public static final Declarer SUPERCLASS = new Declarer( "superclass" );
+		private final String name;
+		public Declarer(String name) {
+			this.name = name;
+		}
+		public String toString() {
+			return name;
+		}
+	}
 }

Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -80,7 +80,9 @@
 				"cid/Order.hbm.xml",
 				"cid/LineItem.hbm.xml",
 				"cid/Product.hbm.xml",
-				"any/Properties.hbm.xml"
+				"any/Properties.hbm.xml",
+				"legacy/Commento.hbm.xml",
+				"legacy/Marelo.hbm.xml"
 		};
 	}
 
@@ -90,6 +92,52 @@
 		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
 	}
 
+	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...
+		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 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" );
@@ -1581,4 +1629,65 @@
 		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;
+		}
+	}
 }

Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/HQLTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/HQLTest.java	2006-11-16 19:32:48 UTC (rev 10824)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/HQLTest.java	2006-11-16 19:33:19 UTC (rev 10825)
@@ -3,39 +3,37 @@
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.*;
+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 junit.framework.TestSuite;
 
-import org.hibernate.classic.Session;
-import org.hibernate.criterion.Projections;
+import org.hibernate.Hibernate;
 import org.hibernate.dialect.DB2Dialect;
 import org.hibernate.dialect.HSQLDialect;
 import org.hibernate.dialect.MySQLDialect;
 import org.hibernate.dialect.Oracle9Dialect;
 import org.hibernate.dialect.PostgreSQLDialect;
 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.ASTQueryTranslatorFactory;
 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.IndexNode;
 import org.hibernate.hql.ast.tree.SelectClause;
-import org.hibernate.hql.QueryTranslatorFactory;
-import org.hibernate.hql.QueryTranslator;
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.engine.query.HQLQueryPlan;
-import org.hibernate.engine.query.ReturnMetadata;
-import org.hibernate.Criteria;
-import org.hibernate.Hibernate;
 
-import antlr.RecognitionException;
-
 /**
  * Tests cases where the AST based query translator and the 'classic' query translator generate identical SQL.
  *
@@ -939,9 +937,19 @@
 	}
 
 	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" );
+//		assertTranslation( "from DomesticAnimal an where an.class = Dog" );
+//		assertTranslation( "from Animal an where an.class = Dog" );
 	}
 
 	public void testSelectDialectFunction() throws Exception {
@@ -1008,11 +1016,6 @@
 		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" );




More information about the hibernate-commits mailing list