Author: steve.ebersole(a)jboss.com
Date: 2006-11-16 14:32:48 -0500 (Thu, 16 Nov 2006)
New Revision: 10824
Modified:
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java
trunk/Hibernate3/src/org/hibernate/hql/ast/util/JoinProcessor.java
trunk/Hibernate3/src/org/hibernate/hql/ast/util/SessionFactoryHelper.java
trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
trunk/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
trunk/Hibernate3/src/org/hibernate/persister/entity/Queryable.java
trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
trunk/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: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java 2006-11-16 17:33:12 UTC
(rev 10823)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java 2006-11-16 19:32:48 UTC
(rev 10824)
@@ -138,8 +138,10 @@
// 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 {
if ( isResolved() ) {
return;
@@ -163,7 +165,7 @@
dereferenceCollection( ( CollectionType ) propertyType, true, true, null, parent );
}
- public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST
parent)
+ public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST
parent)
throws SemanticException {
// If this dot has already been resolved, stop now.
if ( isResolved() ) {
@@ -177,7 +179,7 @@
if ( parent == null ) {
getWalker().getLiteralProcessor().lookupConstant( this );
}
- // If the propertyType is null and there isn't a parent, just
+ // If the propertyType is null and there isn't a parent, just
// stop now... there was a problem resolving the node anyway.
return;
}
@@ -205,7 +207,7 @@
}
setResolved();
}
-
+
private void initText() {
String[] cols = getColumns();
String text = StringHelper.join( ", ", cols );
@@ -222,14 +224,14 @@
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;
String role = collectionType.getRole();
-
+
//foo.bars.size (also handles deprecated stuff like foo.bars.maxelement for
backwardness)
- boolean isSizeProperty = getNextSibling()!=null &&
+ boolean isSizeProperty = getNextSibling()!=null &&
CollectionProperties.isAnyCollectionProperty( getNextSibling().getText() );
if ( isSizeProperty ) indexed = true; //yuck!
@@ -260,19 +262,19 @@
implicitJoin
);
FromElement elem = factory.createCollection( queryableCollection, role, joinType,
fetch, indexed );
-
+
if ( log.isDebugEnabled() ) {
log.debug( "dereferenceCollection() : Created new FROM element for " +
propName + " : " + elem );
}
-
+
setImpliedJoin( elem );
setFromElement( elem ); // This 'dot' expression now refers to the resulting
from element.
-
+
if ( isSizeProperty ) {
elem.setText("");
elem.setUseWhereFragment(false);
}
-
+
if ( !implicitJoin ) {
EntityPersister entityPersister = elem.getEntityPersister();
if ( entityPersister != null ) {
@@ -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,24 +318,11 @@
}
- 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;
}
- private void dereferenceEntityJoin(String classAlias, EntityType propertyType, boolean
impliedJoin, AST parent)
+ private void dereferenceEntityJoin(String classAlias, EntityType propertyType, boolean
impliedJoin, AST parent)
throws SemanticException {
dereferenceType = DEREF_ENTITY;
if ( log.isDebugEnabled() ) {
@@ -403,17 +384,17 @@
FromElementFactory factory = new FromElementFactory(
currentFromClause,
getLhs().getFromElement(),
- joinPath,
- classAlias,
- joinColumns,
+ joinPath,
+ classAlias,
+ joinColumns,
impliedJoin
);
- elem = factory.createEntityJoin(
- associatedEntityName,
- tableAlias,
- joinSequence,
- fetch,
- getWalker().isInFrom(),
+ elem = factory.createEntityJoin(
+ associatedEntityName,
+ tableAlias,
+ joinSequence,
+ fetch,
+ getWalker().isInFrom(),
propertyType
);
}
@@ -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() ) {
@@ -494,8 +460,8 @@
// special shortcut for id properties, skip the join!
// this must only occur at the _end_ of a path expression
if ( log.isDebugEnabled() ) {
- log.debug( "dereferenceShortcut() : property " +
- propertyName + " in " + getFromElement().getClassName() +
+ log.debug( "dereferenceShortcut() : property " +
+ propertyName + " in " + getFromElement().getClassName() +
" does not require a join." );
}
@@ -614,8 +580,14 @@
}
}
}
+
+ FromReferenceNode lhs = getLhs();
+ while ( lhs != null ) {
+ checkSubclassOrSuperclassPropertyReference( lhs, lhs.getNextSibling().getText() );
+ lhs = ( FromReferenceNode ) lhs.getFirstChild();
+ }
}
-
+
/**
* Used ONLY for regression testing!
*/
@@ -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: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java 2006-11-16 17:33:12
UTC (rev 10823)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java 2006-11-16 19:32:48
UTC (rev 10824)
@@ -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();
@@ -470,11 +482,11 @@
public boolean isFromOrJoinFragment() {
return getType() == SqlTokenTypes.FROM_FRAGMENT || getType() ==
SqlTokenTypes.JOIN_FRAGMENT;
}
-
+
public boolean isAllPropertyFetch() {
return isAllPropertyFetch;
}
-
+
public void setAllPropertyFetch(boolean fetch) {
isAllPropertyFetch = fetch;
}
@@ -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: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java 2006-11-16
17:33:12 UTC (rev 10823)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java 2006-11-16
19:32:48 UTC (rev 10824)
@@ -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: trunk/Hibernate3/src/org/hibernate/hql/ast/util/JoinProcessor.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/util/JoinProcessor.java 2006-11-16 17:33:12
UTC (rev 10823)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/util/JoinProcessor.java 2006-11-16 19:32:48
UTC (rev 10824)
@@ -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: trunk/Hibernate3/src/org/hibernate/hql/ast/util/SessionFactoryHelper.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/util/SessionFactoryHelper.java 2006-11-16
17:33:12 UTC (rev 10823)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/util/SessionFactoryHelper.java 2006-11-16
19:32:48 UTC (rev 10824)
@@ -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:
trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
---
trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-11-16
17:33:12 UTC (rev 10823)
+++
trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-11-16
19:32:48 UTC (rev 10824)
@@ -847,14 +847,12 @@
final SessionImplementor session,
final Object[] snapshot,
final int j,
- final Object propValue
- ) {
+ final Object propValue) {
setPropertyValue( entity, lazyPropertyNumbers[j], propValue, session.getEntityMode()
);
-
- if (snapshot != null) { // object have been loaded with setReadOnly(true); HHH-2236
+ if (snapshot != null) {
+ // object have been loaded with setReadOnly(true); HHH-2236
snapshot[ lazyPropertyNumbers[j] ] = lazyPropertyTypes[j].deepCopy( propValue,
session.getEntityMode(), factory );
}
-
return fieldName.equals( lazyPropertyNames[j] );
}
@@ -1352,6 +1350,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;
@@ -3674,11 +3685,11 @@
public Type getIdentifierType() {
return entityMetamodel.getIdentifierProperty().getType();
}
-
+
public boolean hasSubselectLoadableCollections() {
return hasSubselectLoadableCollections;
}
-
+
public int[] getNaturalIdentifierProperties() {
return entityMetamodel.getNaturalIdentifierProperties();
}
@@ -3769,7 +3780,7 @@
public boolean hasNaturalIdentifier() {
return entityMetamodel.hasNaturalIdentifier();
}
-
+
public void setPropertyValue(Object object, String propertyName, Object value,
EntityMode entityMode)
throws HibernateException {
getTuplizer( entityMode ).setPropertyValue( object, propertyName, value );
Modified:
trunk/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
===================================================================
---
trunk/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java 2006-11-16
17:33:12 UTC (rev 10823)
+++
trunk/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java 2006-11-16
19:32:48 UTC (rev 10824)
@@ -44,7 +44,7 @@
private final String[][] tableKeyColumns;
private final String[][] naturalOrderTableKeyColumns;
private final boolean[] naturalOrderCascadeDeleteEnabled;
-
+
private final String[] spaces;
private final String[] subclassClosure;
@@ -82,7 +82,7 @@
//INITIALIZATION:
public JoinedSubclassEntityPersister(
- final PersistentClass persistentClass,
+ final PersistentClass persistentClass,
final CacheConcurrencyStrategy cache,
final SessionFactoryImplementor factory,
final Mapping mapping)
@@ -109,8 +109,8 @@
if ( optimisticLockMode()!=Versioning.OPTIMISTIC_LOCK_VERSION ) {
throw new MappingException(
- "optimistic-lock attribute not supported for joined-subclass mappings: " +
- getEntityName()
+ "optimistic-lock attribute not supported for joined-subclass mappings: "
+
+ getEntityName()
);
}
@@ -126,10 +126,10 @@
while ( titer.hasNext() ) {
Table tab = (Table) titer.next();
KeyValue key = (KeyValue) kiter.next();
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
);
tables.add(tabname);
String[] keyCols = new String[idColumnSpan];
@@ -151,10 +151,10 @@
while ( titer.hasNext() ) {
Table tab = (Table) titer.next();
isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
);
subtables.add(tabname);
String[] key = new String[idColumnSpan];
@@ -182,8 +182,8 @@
reverse(subclassTableNameClosure, tableSpan);
reverse(subclassTableKeyColumnClosure, tableSpan);
- spaces = ArrayHelper.join(
- tableNames,
+ spaces = ArrayHelper.join(
+ tableNames,
ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
);
@@ -233,8 +233,8 @@
while( iter.hasNext() ) {
Property prop = (Property) iter.next();
String tabname = prop.getValue().getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
propertyTableNumbers[i] = getTableId(tabname, tableNames);
@@ -245,19 +245,19 @@
// subclass closure properties
//TODO: code duplication with SingleTableEntityPersister
-
+
ArrayList columnTableNumbers = new ArrayList();
ArrayList formulaTableNumbers = new ArrayList();
ArrayList propTableNumbers = new ArrayList();
-
+
iter = persistentClass.getSubclassPropertyClosureIterator();
while ( iter.hasNext() ) {
Property prop = (Property) iter.next();
Table tab = prop.getValue().getTable();
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
);
Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
propTableNumbers.add(tabnum);
@@ -290,10 +290,10 @@
discriminatorValues[subclassSpan-1] = discriminatorSQLString;
notNullColumnTableNumbers = new int[subclassSpan];
final int id = getTableId(
- persistentClass.getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
+ persistentClass.getTable().getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
),
subclassTableNameClosure
);
@@ -315,16 +315,16 @@
try {
if ( persistentClass.isPolymorphic() ) {
// we now use subclass ids that are consistent across all
- // persisters for a class hierarchy, so that the use of
+ // persisters for a class hierarchy, so that the use of
// "foo.class = Bar" works in HQL
Integer subclassId = new Integer( sc.getSubclassId() );//new Integer(k+1);
subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
discriminatorValues[k] = subclassId.toString();
int id = getTableId(
- sc.getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
+ sc.getTable().getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
),
subclassTableNameClosure
);
@@ -341,7 +341,7 @@
initLockers();
initSubclassPropertyAliasesMap(persistentClass);
-
+
postConstruct(mapping);
}
@@ -351,7 +351,7 @@
//TODO: other lock modes?
loader = createEntityLoader(LockMode.NONE, CollectionHelper.EMPTY_MAP);
}*/
-
+
public String getSubclassPropertyTableName(int i) {
return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
}
@@ -381,11 +381,11 @@
protected String[] getKeyColumns(int j) {
return naturalOrderTableKeyColumns[j];
}
-
+
protected boolean isTableCascadeDeleteEnabled(int j) {
return naturalOrderCascadeDeleteEnabled[j];
}
-
+
protected boolean isPropertyOfTable(int property, int j) {
return naturalOrderPropertyTableNumbers[property]==j;
}
@@ -403,7 +403,7 @@
getQueryLoader() :
this.loader;
try {
-
+
final Object result = loader.load(id, optionalObject, session);
if (result!=null) lock(id, getVersion(result), result, lockMode, session);
@@ -451,7 +451,7 @@
public String getTableName() {
return tableNames[0];
}
-
+
private static int getTableId(String tableName, String[] tables) {
for ( int j=0; j<tables.length; j++ ) {
if ( tableName.equals( tables[j] ) ) {
@@ -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: trunk/Hibernate3/src/org/hibernate/persister/entity/Queryable.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/entity/Queryable.java 2006-11-16 17:33:12
UTC (rev 10823)
+++ trunk/Hibernate3/src/org/hibernate/persister/entity/Queryable.java 2006-11-16 19:32:48
UTC (rev 10824)
@@ -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.
*
@@ -109,7 +121,7 @@
* @return
*/
public String getSubclassTableName(int number);
-
+
/**
* Is the version property included in insert statements?
*/
@@ -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: trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-11-16
17:33:12 UTC (rev 10823)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-11-16
19:32:48 UTC (rev 10824)
@@ -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,92 +92,65 @@
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
}
- 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 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 testSelectAndResultColumnReferences() {
- Session s = openSession();
- s.beginTransaction();
- s.createQuery( "select m.name from Model as m" ).list();
- s.createQuery( "select h.name.first from Human h" ).list();
- s.createQuery( "select h.name from Human h" ).list();
- s.getTransaction().commit();
- s.close();
+ 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 testSelectAndResultColumnReferencesWithGrouping() {
- if ( ! allowsPhysicalColumnNameInHaving( "scalar HQL queries" ) ) {
- return;
- }
+ 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)
- Session s = openSession();
- s.beginTransaction();
+ new SyntaxChecker( "from Zoo z join z.mammals as m where m.name.first =
'John'" ).checkIterate();
- s.createQuery( "select m.name, count(*) from Model as m group by m.name"
).list();
- s.createQuery( "select m.name, count(*) from Model as m group by m.name order by
m.name" ).list();
- s.createQuery( "select m.name, max( m.id ) from Model as m group by m.name having
max( id ) > 1" ).list();
- s.createQuery( "select m.name, count(*) from Model as m group by m.name having
count(*) > 1" ).list();
- s.createQuery( "select m.name, count(*) from Model as m group by m.name having
m.name like 'abc%'" ).list();
+ 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();
- s.createQuery( "select h.name.first, count(*) from Human h group by
h.name.first" ).list();
- s.createQuery( "select h.name.first, count(*) from Human h group by h.name.first
having count(*) > 1" ).list();
+ 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();
- s.createQuery( "select h.name, count(*) from Human h group by h.name"
).list();
- s.createQuery( "select h.name, count(*) from Human h group by h.name having
count(*) > 1" ).list();
+ 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();
- s.getTransaction().commit();
- s.close();
- }
+ 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();
- public void testSelectAndResultColumnReferencesWithCollation() {
- if ( ! allowsPhysicalColumnNameInOrderby( "scalar HQL queries" ) ) {
- return;
- }
-
- Session s = openSession();
- s.beginTransaction();
-
- s.createQuery( "select m.name from Model as m order by m.name" ).list();
-
- s.createQuery( "select h.name.first from Human h order by h.name.first"
).list();
-
- s.createQuery( "select h.name from Human h order by h.name" ).list();
-
- s.getTransaction().commit();
- s.close();
+ 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 testSelectAndResultColumnReferencesWithCollationAndOrdering() {
- if ( ! allowsPhysicalColumnNameInHaving( "scalar HQL queries" ) ) {
+ public void testSimpleSelectWithLimitAndOffset() throws Exception {
+ if ( ! ( getDialect().supportsLimit() && getDialect().supportsLimitOffset() ) )
{
+ reportSkip( "dialect does not support offset and limit combo", "limit
and offset combination" );
return;
}
- if ( ! allowsPhysicalColumnNameInOrderby( "scalar HQL queries" ) ) {
- return;
- }
- Session s = openSession();
- s.beginTransaction();
-
- s.createQuery( "select m.name, count(*) from Model as m group by m.name having
m.name like 'abc%' order by m.name" ).list();
-
- s.createQuery( "select h.name.first, count(*) from Human h group by h.name.first
having count(*) > 1 order by h.name.first" ).list();
-
- s.createQuery( "select h.name, count(*) from Human h group by h.name having
count(*) > 1 order by h.name" ).list();
-
- s.getTransaction().commit();
- s.close();
+ // just checking correctness of param binding code...
+ Session session = openSession();
+ session.createQuery( "from Animal" )
+ .setFirstResult( 2 )
+ .setMaxResults( 1 )
+ .list();
+ session.close();
}
public void testJPAPositionalParameterList() {
@@ -403,7 +378,7 @@
s.close();
}
- public void testFetchInSubqueryFails() {
+ public void testFetchInSubqueryFailureExpected() {
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();
@@ -614,7 +589,7 @@
t.commit();
s.close();
}
-
+
public void testSelectClauseSubselect() {
Session s = openSession();
Transaction t = s.beginTransaction();
@@ -631,7 +606,7 @@
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();
@@ -774,7 +749,7 @@
bw.toString();
s.delete(a);
t.commit();
- s.close();
+ s.close();
}
public void testAliases() {
@@ -792,7 +767,7 @@
assertEquals(aliases2[1], "avg");
s.delete(a);
t.commit();
- s.close();
+ s.close();
}
public void testParameterMixing() {
@@ -849,9 +824,9 @@
.setParameter("country", "Australia")
.list();*/
t.commit();
- s.close();
+ s.close();
}
-
+
public void testAggregation() {
Session s = openSession();
Transaction t = s.beginTransaction();
@@ -871,7 +846,7 @@
t.commit();
s.close();
}
-
+
public void testSelectClauseCase() {
Session s = openSession();
Transaction t = s.beginTransaction();
@@ -904,28 +879,28 @@
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();
+ session.close();
}
-
+
public void testStr() {
Session session = openSession();
Transaction txn = session.beginTransaction();
@@ -936,14 +911,14 @@
if ( getDialect() instanceof DB2Dialect ) {
assertTrue( str.startsWith("1.234") );
}
- else if ( getDialect() instanceof SQLServerDialect) {
+ 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) ) {
+ 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();
@@ -964,7 +939,7 @@
txn.commit();
session.close();
}
-
+
public void testCast() {
if ( ( getDialect() instanceof MySQLDialect ) || ( getDialect() instanceof DB2Dialect )
) {
return;
@@ -975,9 +950,9 @@
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();
+ session.close();
}
-
+
public void testExtract() {
Session session = openSession();
Transaction txn = session.beginTransaction();
@@ -988,7 +963,7 @@
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();
+ session.close();
}
public void testOneToManyFilter() throws Throwable {
@@ -1020,7 +995,7 @@
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);
@@ -1058,14 +1033,14 @@
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();
@@ -1135,7 +1110,7 @@
txn.commit();
session.close();
}
-
+
public void testImplicitJoin() throws Exception {
Session session = openSession();
Transaction t = session.beginTransaction();
@@ -1298,7 +1273,7 @@
destroyTestBaseData();
}
-
+
public void testStandardFunctions() throws Exception {
Session session = openSession();
Transaction t = session.beginTransaction();
@@ -1319,7 +1294,7 @@
session.delete(p);
t.commit();
session.close();
-
+
}
public void testDynamicInstantiationQueries() throws Exception {
@@ -1331,11 +1306,11 @@
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 );
-
+ 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 );
@@ -1351,13 +1326,13 @@
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 );
@@ -1377,19 +1352,19 @@
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" )
@@ -1412,28 +1387,28 @@
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();
}
@@ -1447,10 +1422,10 @@
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 );
+ 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);
@@ -1458,41 +1433,41 @@
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 );
+ 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());
+ 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();
}
@@ -1503,10 +1478,10 @@
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 );
+ 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());
@@ -1518,9 +1493,9 @@
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() );
@@ -1528,20 +1503,20 @@
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();
}
@@ -1574,7 +1549,7 @@
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();
@@ -1584,7 +1559,7 @@
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();
@@ -1632,20 +1607,20 @@
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();
@@ -1654,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: trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java 2006-11-16 17:33:12 UTC (rev
10823)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java 2006-11-16 19:32:48 UTC (rev
10824)
@@ -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.
*
@@ -165,7 +163,7 @@
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");
}
@@ -176,7 +174,7 @@
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");
@@ -188,7 +186,7 @@
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"
);
@@ -317,7 +315,7 @@
"select o.mother.bodyWeight, count(distinct o) " +
"from Animal an " +
" join an.offspring as o " +
- "group by o.mother.bodyWeight"
+ "group by o.mother.bodyWeight"
);
}
@@ -335,14 +333,14 @@
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");
@@ -424,7 +422,7 @@
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" );
}
@@ -447,7 +445,7 @@
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");
@@ -507,7 +505,7 @@
// 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'");
}
@@ -515,7 +513,7 @@
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" );
}
@@ -628,7 +626,7 @@
assertTranslation( "select count(*) from Human h group by year(sysdate)" );
}
-
+
public void testPolymorphism() throws Exception {
HashMap replacements = new HashMap();
replacements.put( "false", "0" );
@@ -723,7 +721,7 @@
/**
* Test for HHH-559
- */
+ */
public void testMultibyteCharacterConstant() throws Exception {
assertTranslation( "from Zoo zoo join zoo.animals an where an.description
like '%\u4e2d%'" );
}
@@ -813,8 +811,8 @@
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" );
}
@@ -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" );
@@ -1131,7 +1134,7 @@
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.
@@ -1162,13 +1165,13 @@
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");
@@ -1189,8 +1192,8 @@
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)" );
}
@@ -1279,5 +1282,5 @@
public static Test suite() {
return new TestSuite( HQLTest.class );
}
-
+
}