Permalink
Browse files

HHH-5396 - JPQL KEY(), ENTRY() and VALUE() does not recognize alias refs

  • Loading branch information...
1 parent 2b213da commit 44fcd0a156c61710f4f2494e996ea5ed230e9da8 @sebersole sebersole committed May 30, 2012
View
49 ...nate-core/src/main/java/org/hibernate/hql/internal/ast/tree/AbstractMapComponentNode.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -34,7 +36,7 @@
import org.hibernate.type.Type;
/**
- * TODO : javadoc
+ * Basic support for KEY, VALUE and ENTRY based "qualified identification variables".
*
* @author Steve Ebersole
*/
@@ -49,10 +51,12 @@ public FromReferenceNode getMapReference() {
return columns;
}
+ @Override
public void setScalarColumnText(int i) throws SemanticException {
ColumnHelper.generateScalarColumns( this, getColumns(), i );
}
+ @Override
public void resolve(
boolean generateJoin,
boolean implicitJoin,
@@ -64,20 +68,36 @@ public void resolve(
FromReferenceNode mapReference = getMapReference();
mapReference.resolve( true, true );
- if ( mapReference.getDataType().isCollectionType() ) {
- CollectionType collectionType = (CollectionType) mapReference.getDataType();
- if ( Map.class.isAssignableFrom( collectionType.getReturnedClass() ) ) {
- FromElement sourceFromElement = mapReference.getFromElement();
- setFromElement( sourceFromElement );
- setDataType( resolveType( sourceFromElement.getQueryableCollection() ) );
- this.columns = resolveColumns( sourceFromElement.getQueryableCollection() );
- initText( this.columns );
- setFirstChild( null );
- return;
+
+ FromElement sourceFromElement = null;
+ if ( isAliasRef( mapReference ) ) {
+ QueryableCollection collectionPersister = mapReference.getFromElement().getQueryableCollection();
+ if ( Map.class.isAssignableFrom( collectionPersister.getCollectionType().getReturnedClass() ) ) {
+ sourceFromElement = mapReference.getFromElement();
+ }
+ }
+ else {
+ if ( mapReference.getDataType().isCollectionType() ) {
+ CollectionType collectionType = (CollectionType) mapReference.getDataType();
+ if ( Map.class.isAssignableFrom( collectionType.getReturnedClass() ) ) {
+ sourceFromElement = mapReference.getFromElement();
+ }
}
}
- throw nonMap();
+ if ( sourceFromElement == null ) {
+ throw nonMap();
+ }
+
+ setFromElement( sourceFromElement );
+ setDataType( resolveType( sourceFromElement.getQueryableCollection() ) );
+ this.columns = resolveColumns( sourceFromElement.getQueryableCollection() );
+ initText( this.columns );
+ setFirstChild( null );
+ }
+
+ private boolean isAliasRef(FromReferenceNode mapReference) {
+ return ALIAS_REF == mapReference.getType();
}
private void initText(String[] columns) {
@@ -100,6 +120,7 @@ protected SemanticException nonMap() {
return new SemanticException( expressionDescription() + " expression did not reference map property" );
}
+ @Override
public void resolveIndex(AST parent) throws SemanticException {
throw new UnsupportedOperationException( expressionDescription() + " expression cannot be the source for an index operation" );
}
View
33 hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/MapEntryNode.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.hql.internal.ast.tree;
+
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -41,7 +44,7 @@
import org.hibernate.type.Type;
/**
- * TODO : javadoc
+ * Tree node representing reference to the entry ({@link Map.Entry}) of a Map association.
*
* @author Steve Ebersole
*/
@@ -61,6 +64,7 @@ public String generateAlias(String sqlExpression) {
private int scalarColumnIndex = -1;
+ @Override
protected String expressionDescription() {
return "entry(*)";
}
@@ -70,6 +74,8 @@ public Class getAggregationResultType() {
return Map.Entry.class;
}
+ @Override
+ @SuppressWarnings("unchecked")
protected Type resolveType(QueryableCollection collectionPersister) {
Type keyType = collectionPersister.getIndexType();
Type valueType = collectionPersister.getElementType();
@@ -81,6 +87,7 @@ protected Type resolveType(QueryableCollection collectionPersister) {
return null;
}
+ @Override
protected String[] resolveColumns(QueryableCollection collectionPersister) {
List selections = new ArrayList();
determineKeySelectExpressions( collectionPersister, selections );
@@ -118,8 +125,9 @@ private void determineKeySelectExpressions(QueryableCollection collectionPersist
}
}
+ @SuppressWarnings({"unchecked", "ForLoopReplaceableByForEach"})
private void appendSelectExpressions(String[] columnNames, List selections, AliasGenerator aliasGenerator) {
- for ( int i = 0; i < columnNames.length; i++ ) {
+ for ( int i = 0; i < columnNames.length; i++ ) {
selections.add(
new BasicSelectExpression(
collectionTableAlias() + '.' + columnNames[i],
@@ -129,6 +137,7 @@ private void appendSelectExpressions(String[] columnNames, List selections, Alia
}
}
+ @SuppressWarnings({"unchecked", "WhileLoopReplaceableByForEach"})
private void appendSelectExpressions(SelectFragment fragment, List selections, AliasGenerator aliasGenerator) {
Iterator itr = fragment.getColumns().iterator();
while ( itr.hasNext() ) {
@@ -176,10 +185,12 @@ private BasicSelectExpression(String expression, String alias) {
this.alias = alias;
}
+ @Override
public String getExpression() {
return expression;
}
+ @Override
public String getAlias() {
return alias;
}
@@ -189,48 +200,57 @@ public SessionFactoryImplementor sfi() {
return getSessionFactoryHelper().getFactory();
}
+ @Override
public void setText(String s) {
if ( isResolved() ) {
return;
}
super.setText( s );
}
+ @Override
public void setScalarColumn(int i) throws SemanticException {
this.scalarColumnIndex = i;
}
+ @Override
public int getScalarColumnIndex() {
return scalarColumnIndex;
}
+ @Override
public void setScalarColumnText(int i) throws SemanticException {
}
+ @Override
public boolean isScalar() {
// Constructors are always considered scalar results.
return true;
}
private List types = new ArrayList(4); // size=4 to prevent resizing
+ @Override
public List getAggregatedSelectionTypeList() {
return types;
}
private static final String[] ALIASES = { null, null };
+ @Override
public String[] getAggregatedAliases() {
return ALIASES;
}
private MapEntryBuilder mapEntryBuilder;
+ @Override
public ResultTransformer getResultTransformer() {
return mapEntryBuilder;
}
private static class MapEntryBuilder extends BasicTransformerAdapter {
+ @Override
public Object transformTuple(Object[] tuple, String[] aliases) {
if ( tuple.length != 2 ) {
throw new HibernateException( "Expecting exactly 2 tuples to transform into Map.Entry" );
@@ -248,20 +268,24 @@ private EntryAdapter(Object key, Object value) {
this.value = value;
}
+ @Override
public Object getValue() {
return value;
}
+ @Override
public Object getKey() {
return key;
}
+ @Override
public Object setValue(Object value) {
Object old = this.value;
this.value = value;
return old;
}
+ @Override
public boolean equals(Object o) {
// IMPL NOTE : nulls are considered equal for keys and values according to Map.Entry contract
if ( this == o ) {
@@ -278,6 +302,7 @@ public boolean equals(Object o) {
}
+ @Override
public int hashCode() {
int keyHash = key == null ? 0 : key.hashCode();
int valueHash = value == null ? 0 : value.hashCode();
View
12 hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/MapKeyNode.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,23 +22,27 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.hql.internal.ast.tree;
+
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type;
/**
- * TODO : javadoc
+ * Tree node representing reference to the key of a Map association.
*
* @author Steve Ebersole
*/
public class MapKeyNode extends AbstractMapComponentNode {
+ @Override
protected String expressionDescription() {
return "key(*)";
}
+ @Override
protected String[] resolveColumns(QueryableCollection collectionPersister) {
return collectionPersister.getIndexColumnNames();
}
+ @Override
protected Type resolveType(QueryableCollection collectionPersister) {
return collectionPersister.getIndexType();
}
View
12 hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/MapValueNode.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,23 +22,27 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.hql.internal.ast.tree;
+
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type;
/**
- * TODO : javadoc
+ * Tree node representing reference to the value of a Map association.
*
* @author Steve Ebersole
*/
public class MapValueNode extends AbstractMapComponentNode {
+ @Override
protected String expressionDescription() {
return "value(*)";
}
+ @Override
protected String[] resolveColumns(QueryableCollection collectionPersister) {
return collectionPersister.getElementColumnNames();
}
+ @Override
protected Type resolveType(QueryableCollection collectionPersister) {
return collectionPersister.getElementType();
}
View
21 hibernate-core/src/matrix/java/org/hibernate/test/hql/ASTParserLoadingTest.java
@@ -278,6 +278,18 @@ public void testJPAQLQualifiedIdentificationVariables() {
s = openSession();
s.beginTransaction();
+ results = s.createQuery( "select entry(f) from Human h from h.family f" ).list();
+ assertEquals( 1, results.size() );
+ result = results.get(0);
+ assertTrue( Map.Entry.class.isAssignableFrom( result.getClass() ) );
+ entry = (Map.Entry) result;
+ assertTrue( String.class.isAssignableFrom( entry.getKey().getClass() ) );
+ assertTrue( Human.class.isAssignableFrom( entry.getValue().getClass() ) );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
results = s.createQuery( "select distinct key(h.family) from Human h" ).list();
assertEquals( 1, results.size() );
Object key = results.get(0);
@@ -287,6 +299,15 @@ public void testJPAQLQualifiedIdentificationVariables() {
s = openSession();
s.beginTransaction();
+ results = s.createQuery( "select distinct key(f) from Human h join h.family f" ).list();
+ assertEquals( 1, results.size() );
+ key = results.get(0);
+ assertTrue( String.class.isAssignableFrom( key.getClass() ) );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
s.delete( me );
s.delete( joe );
s.getTransaction().commit();

0 comments on commit 44fcd0a

Please sign in to comment.