/* * Hibernate, Relational Persistence for Idiomatic Java * * License: Apache License, Version 2.0 * See the LICENSE file in the root directory or visit http://www.apache.org/licenses/LICENSE-2.0 */ package org.hibernate.sqm.test.hql; import java.util.List; import javax.persistence.Id; import javax.persistence.ManyToOne; import org.hibernate.orm.persister.entity.spi.EntityReference; import org.hibernate.query.sqm.produce.spi.SemanticQueryProducer; import org.hibernate.query.sqm.AliasCollisionException; import org.hibernate.query.sqm.produce.spi.ImplicitAliasGenerator; import org.hibernate.query.sqm.tree.SqmQuerySpec; import org.hibernate.query.sqm.tree.SqmSelectStatement; import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SubQuerySqmExpression; import org.hibernate.query.sqm.tree.expression.domain.SqmSingularAttributeReference; import org.hibernate.query.sqm.tree.from.SqmFromElementSpace; import org.hibernate.query.sqm.tree.from.SqmFromClause; import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.predicate.AndSqmPredicate; import org.hibernate.query.sqm.tree.predicate.InSubQuerySqmPredicate; import org.hibernate.query.sqm.tree.predicate.RelationalSqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.select.SqmSelection; import org.hibernate.sqm.test.ConsumerContextImpl; import org.hibernate.sqm.test.domain.OrmHelper; import org.junit.Test; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** * @author Andrea Boriero */ public class AliasTest { final ConsumerContextImpl consumerContext = new ConsumerContextImpl( OrmHelper.buildDomainMetamodel( Entity.class, Anything.class, Something.class, SomethingElse.class ) ); @Test(expected = AliasCollisionException.class) public void testRedefiningAResultVariableInSelectionsHavingDifferentSelectionExpressions() { final String query = "select a.address as b, a.name as b from Anything a"; interpretQuery( query ); } @Test(expected = AliasCollisionException.class) public void testRedefiningAResultVariableInSelectionsHavingTheSameSelectionExpression() { final String query = "select a.address as b, a.address as b from Anything a"; interpretQuery( query ); } @Test public void testMixedResultVariableAndAttributeSelection() { final String query = "select o, o.basic1 as o1 from Entity o"; final SqmQuerySpec querySpec = interpretQuery( query ).getQuerySpec(); checkElementSelection( querySpec, 0, Entity.class.getName(), null ); checkAttributeReferenceExpression( querySpec, 1, Entity.class.getName(), "basic1", "o1" ); checkFromClause( querySpec, 0, Entity.class.getName(), "o" ); } @Test public void testDefiningDifferentResultVAriables() { final String query = "select a.basic as b, a.basic2 as c from Anything a"; final SqmQuerySpec querySpec = interpretQuery( query ).getQuerySpec(); checkAttributeReferenceExpression( querySpec, 0, Anything.class.getName(), "basic", "b" ); checkAttributeReferenceExpression( querySpec, 1, Anything.class.getName(), "basic2", "c" ); checkFromClause( querySpec, 0, Anything.class.getName(), "a" ); } @Test public void testDefiningAResultVariableEqualsToAnIdentificationVariable() { final String query = "select a as a from Anything as a"; final SqmQuerySpec querySpec = interpretQuery( query ).getQuerySpec(); checkElementSelection( querySpec, 0, Anything.class.getName(), "a" ); checkFromClause( querySpec, 0, Anything.class.getName(), "a" ); } @Test public void testReusingAnIdentificationVariableInSelectClause() { final String query = "select a.basic from Anything as a"; final SqmQuerySpec querySpec = interpretQuery( query ).getQuerySpec(); checkAttributeReferenceExpression( querySpec, 0, Anything.class.getName(), "basic", null ); checkFromClause( querySpec, 0, Anything.class.getName(), "a" ); } @Test(expected = AliasCollisionException.class) public void testDefiningAResultVariableEqualsToAnIdentificationVariableConflict() { final String query = "select a.basic as a from Anything as a"; interpretQuery( query ); } @Test public void testMultipleFromClauseSpaces() { final String query = "select a as a, b.basic2 from Anything as a, SomethingElse as b where b.basic = 2 "; final SqmQuerySpec querySpec = interpretQuery( query ).getQuerySpec(); checkElementSelection( querySpec, 0, Anything.class.getName(), "a" ); checkAttributeReferenceExpression( querySpec, 1, SomethingElse.class.getName(), "basic2", null ); checkFromClause( querySpec, 0, Anything.class.getName(), "a" ); checkFromClause( querySpec, 1, SomethingElse.class.getName(), "b" ); checkRelationalPredicateLeftHandWhereExpression( querySpec, SomethingElse.class.getName(), "basic", "b" ); } @Test(expected = AliasCollisionException.class) public void testDefiningAResultVariableEqualsToAnIdentificationVariableConflictWithMultipleFromClauseSpaces() { final String query = "select a as a from Anything as a, SomethingElse as a "; interpretQuery( query ); } @Test public void testDifferentIdentificationVariablesInSubquery() { final String query = "select a from Anything a where a.b in ( select b from SomethingElse b where b.basic = 5)"; final SqmSelectStatement selectStatement = interpretQuery( query ); checkElementSelection( selectStatement.getQuerySpec(), 0, Anything.class.getName(), null ); checkFromClause( selectStatement.getQuerySpec(), 0, Anything.class.getName(), "a" ); final SqmQuerySpec subQuerySpec = getInSubQueryExpression( selectStatement ).getQuerySpec(); checkElementSelection( subQuerySpec, 0, SomethingElse.class.getName(), null ); checkFromClause( subQuerySpec, 0, SomethingElse.class.getName(), "b" ); checkRelationalPredicateLeftHandWhereExpression( subQuerySpec, SomethingElse.class.getName(), "basic", "b" ); } @Test public void testSameIdentificationVariablesInSubquery() { final String query = "select a from Anything a where a.basic1 in ( select a from SomethingElse a where a.basic = 5)"; final SqmSelectStatement selectStatement = interpretQuery( query ); SqmQuerySpec querySpec = selectStatement.getQuerySpec(); checkElementSelection( querySpec, 0, Anything.class.getName(), null ); checkFromClause( querySpec, 0, Anything.class.getName(), "a" ); checkInSubqueryTestExpression( querySpec, Anything.class.getName(), "basic1", "a" ); SqmQuerySpec subQuerySpec = getInSubQueryExpression( selectStatement ).getQuerySpec(); checkElementSelection( subQuerySpec, 0, SomethingElse.class.getName(), null ); checkFromClause( subQuerySpec, 0, SomethingElse.class.getName(), "a" ); checkRelationalPredicateLeftHandWhereExpression( subQuerySpec, SomethingElse.class.getName(), "basic", "a" ); } @Test public void testSubqueryUsingIdentificationVariableDefinedInRootQuery() { final String query = "select a from Anything a where a.basic in " + "( select b.basic from SomethingElse b where a.basic = b.basic2 )"; final SqmSelectStatement selectStatement = interpretQuery( query ); checkElementSelection( selectStatement.getQuerySpec(), 0, Anything.class.getName(), null ); checkFromClause( selectStatement.getQuerySpec(), 0, Anything.class.getName(), "a" ); checkInSubqueryTestExpression( selectStatement.getQuerySpec(), "com.acme.Anything", "basic", "a" ); SqmQuerySpec subQuerySpec = getInSubQueryExpression( selectStatement ).getQuerySpec(); checkAttributeReferenceExpression( subQuerySpec, 0, SomethingElse.class.getName(), "basic", null ); checkFromClause( subQuerySpec, 0, SomethingElse.class.getName(), "b" ); checkRelationalPredicateLeftHandWhereExpression( subQuerySpec, Anything.class.getName(), "basic", "a" ); checkRelationalPredicateRightHandWhereExpression( subQuerySpec, SomethingElse.class.getName(), "basic2", "b" ); } @Test public void testSubqueriesRedefiningIdentificationVariableDefinedInparentQuery() { final String query = "select a.basic from Anything a where a.basic in" + " ( select b.basic2 from SomethingElse b where b.basic2 = a.basic1 ) and a.basic in" + " ( select b.basic1 from Something b where b.basic1 = a.basic )"; final SqmSelectStatement selectStatement = interpretQuery( query ); SqmQuerySpec subQuerySpec = getLeftAndPredicateSubQueryExpression( selectStatement.getQuerySpec() ).getQuerySpec(); checkAttributeReferenceExpression( subQuerySpec, 0, SomethingElse.class.getName(), "basic2", null ); checkFromClause( subQuerySpec, 0, SomethingElse.class.getName(), "b" ); checkRelationalPredicateLeftHandWhereExpression( subQuerySpec, SomethingElse.class.getName(), "basic2", "b" ); checkRelationalPredicateRightHandWhereExpression( subQuerySpec, Anything.class.getName(), "basic1", "a" ); subQuerySpec = getRightAndPredicateSubQueryExpression( selectStatement.getQuerySpec() ).getQuerySpec(); checkAttributeReferenceExpression( subQuerySpec, 0, Something.class.getName(), "basic1", null ); checkFromClause( subQuerySpec, 0, Something.class.getName(), "b" ); checkRelationalPredicateLeftHandWhereExpression( subQuerySpec, Something.class.getName(), "basic1", "b" ); checkRelationalPredicateRightHandWhereExpression( subQuerySpec, Anything.class.getName(), "basic", "a" ); } @Test public void testNestedSubqueriesUsingIdentificationVariableDefinedInRootQuery() { final String query = "select a from Anything a where a.basic in " + "( select b.basic1 from SomethingElse b where b.basic = " + "( select c.basic3 as d from Something c where c.basic3 = a.basic))"; final SqmSelectStatement selectStatement = interpretQuery( query ); final SqmQuerySpec querySpec = selectStatement.getQuerySpec(); checkElementSelection( querySpec, 0, Anything.class.getName(), null ); checkFromClause( querySpec, 0, Anything.class.getName(), "a" ); checkInSubqueryTestExpression( querySpec, Anything.class.getName(), "basic", "a" ); SqmQuerySpec subQuerySpec = getInSubQueryExpression( selectStatement ).getQuerySpec(); checkAttributeReferenceExpression( subQuerySpec, 0, SomethingElse.class.getName(), "basic1", null ); checkFromClause( subQuerySpec, 0, SomethingElse.class.getName(), "b" ); subQuerySpec = getRelationaSubQueryExpression( subQuerySpec ).getQuerySpec(); checkAttributeReferenceExpression( subQuerySpec, 0, Something.class.getName(), "basic3", "d" ); checkFromClause( subQuerySpec, 0, Something.class.getName(), "c" ); checkRelationalPredicateLeftHandWhereExpression( subQuerySpec, Something.class.getName(), "basic3", "c" ); checkRelationalPredicateRightHandWhereExpression( subQuerySpec, Anything.class.getName(), "basic", "a" ); } @Test public void testNestedSubqueriesRedefiningIdentificationVariableDefinedInRootQuery() { final String query = "select a from Anything a where a.basic in " + "( select b.basic1 from SomethingElse b where b.basic = " + "( select a.basic3 as d from Something a where a.basic3 = a.basic ))"; final SqmSelectStatement selectStatement = interpretQuery( query ); final SqmQuerySpec querySpec = selectStatement.getQuerySpec(); checkElementSelection( querySpec, 0, Anything.class.getName(), null ); checkFromClause( querySpec, 0, Anything.class.getName(), "a" ); checkInSubqueryTestExpression( querySpec, Anything.class.getName(), "basic", "a" ); SqmQuerySpec subQuerySpec = getInSubQueryExpression( selectStatement ).getQuerySpec(); checkAttributeReferenceExpression( subQuerySpec, 0, SomethingElse.class.getName(), "basic1", null ); checkFromClause( subQuerySpec, 0, SomethingElse.class.getName(), "b" ); subQuerySpec = getRelationaSubQueryExpression( subQuerySpec ).getQuerySpec(); checkAttributeReferenceExpression( subQuerySpec, 0, Something.class.getName(), "basic3", "d" ); checkFromClause( subQuerySpec, 0, Something.class.getName(), "a" ); checkRelationalPredicateLeftHandWhereExpression( subQuerySpec, Something.class.getName(), "basic3", "a" ); checkRelationalPredicateRightHandWhereExpression( subQuerySpec, Something.class.getName(), "basic", "a" ); } @Test(expected = AliasCollisionException.class) public void testResultVariableCollisionSubQuery() { final String query = "select a.address as b, a.basic as c from Anything a where a.basic2 in " + "(select b.basic3 as b from SomethingElse as b where b.basic3 = 2)"; interpretQuery( query ); } @Test(expected = AliasCollisionException.class) public void testIdentificationVariableCollisionSubQuery() { final String query = "select a.address as b, a.basic as c from Anything a where a.basic2 in " + "(select b.basic3 as e from SomethingElse as b, Something as b)"; interpretQuery( query ); } @Test(expected = AliasCollisionException.class) public void testReDefineSameIdentificationVariableInJoin() { final String query = "select a from Something a left outer join a.entity a on a.basic1 > 5"; interpretQuery( query ); } private void checkFromClause(SqmQuerySpec querySpec, int fromClauseIndex, String typeName, String alias) { SqmFromClause fromClause = querySpec.getFromClause(); SqmFromElementSpace fromElementSpace = fromClause.getFromElementSpaces().get( fromClauseIndex ); SqmRoot root = fromElementSpace.getRoot(); assertThat( root.getEntityName(), is( typeName ) ); if ( alias == null ) { assertThat( root.getIdentificationVariable(), is( nullValue() ) ); } else { assertThat( root.getIdentificationVariable(), is( alias ) ); } } private void checkAttributeReferenceExpression( SqmQuerySpec querySpect, int attributeIndex, String typeName, String attributeName, String alias) { List<SqmSelection> selections = querySpect.getSelectClause().getSelections(); SqmSelection selection = selections.get( attributeIndex ); SqmSingularAttributeReference expression = (SqmSingularAttributeReference) selection.getExpression(); assertThat( expression.getReferencedNavigable().getAttributeName(), is( attributeName ) ); if ( alias == null ) { assertTrue( ImplicitAliasGenerator.isImplicitAlias( selection.getAlias() ) ); } else { assertThat( selection.getAlias(), is( alias ) ); } } private void checkElementSelection(SqmQuerySpec querySpec, int selectionIndex, String typeName, String alias) { List<SqmSelection> selections = querySpec.getSelectClause().getSelections(); SqmSelection selection = selections.get( selectionIndex ); SqmExpression expression = selection.getExpression(); EntityReference entityType = (EntityReference) expression.getExpressionType(); assertThat( entityType.getTypeName(), is( typeName ) ); if ( alias == null ) { assertTrue( ImplicitAliasGenerator.isImplicitAlias( selection.getAlias() ) ); } else { assertThat( selection.getAlias(), is( alias ) ); } } private void checkInSubqueryTestExpression( SqmQuerySpec querySpec, String typeName, String attributeName, String alias ) { SqmWhereClause whereClause = querySpec.getWhereClause(); InSubQuerySqmPredicate predicate = (InSubQuerySqmPredicate) whereClause.getPredicate(); SqmSingularAttributeReference testExpression = (SqmSingularAttributeReference) predicate.getTestExpression(); assertThat( testExpression.getReferencedNavigable().getAttributeName(), is( attributeName ) ); assertThat( testExpression.getSourceReference(), notNullValue() ); assertThat( testExpression.getSourceReference().getExportedFromElement().getIdentificationVariable(), is( alias ) ); } private void checkRelationalPredicateLeftHandWhereExpression( SqmQuerySpec querySpec, String typeName, String attributeName, String alias) { SqmWhereClause whereClause = querySpec.getWhereClause(); RelationalSqmPredicate predicate = (RelationalSqmPredicate) whereClause.getPredicate(); SqmSingularAttributeReference leftHandExpression = (SqmSingularAttributeReference) predicate.getLeftHandExpression(); assertThat( leftHandExpression.getReferencedNavigable().getAttributeName(), is( attributeName ) ); assertThat( leftHandExpression.getSourceReference().getExportedFromElement().getIdentificationVariable(), is( alias ) ); } private void checkRelationalPredicateRightHandWhereExpression( SqmQuerySpec querySpec, String typeName, String attributeName, String alias) { SqmWhereClause whereClause = querySpec.getWhereClause(); RelationalSqmPredicate predicate = (RelationalSqmPredicate) whereClause.getPredicate(); SqmSingularAttributeReference leftHandExpression = (SqmSingularAttributeReference) predicate.getRightHandExpression(); assertThat( leftHandExpression.getReferencedNavigable().getAttributeName(), is( attributeName ) ); assertThat( leftHandExpression.getSourceReference().getExportedFromElement().getIdentificationVariable(), is( alias ) ); // assertThat( leftHandExpression.getPluralAttributeReference().getExpressionType().getTypeName(), is( typeName ) ); } private SubQuerySqmExpression getInSubQueryExpression(SqmSelectStatement selectStatement) { return getInSubQueryExpression( selectStatement.getQuerySpec() ); } private SubQuerySqmExpression getInSubQueryExpression(SqmQuerySpec querySpec) { SqmWhereClause whereClause = querySpec.getWhereClause(); InSubQuerySqmPredicate predicate = (InSubQuerySqmPredicate) whereClause.getPredicate(); return predicate.getSubQueryExpression(); } private SubQuerySqmExpression getLeftAndPredicateSubQueryExpression(SqmQuerySpec querySpec) { SqmWhereClause whereClause = querySpec.getWhereClause(); AndSqmPredicate predicate = (AndSqmPredicate) whereClause.getPredicate(); return ((InSubQuerySqmPredicate) predicate.getLeftHandPredicate()).getSubQueryExpression(); } private SubQuerySqmExpression getRightAndPredicateSubQueryExpression(SqmQuerySpec querySpec) { SqmWhereClause whereClause = querySpec.getWhereClause(); AndSqmPredicate predicate = (AndSqmPredicate) whereClause.getPredicate(); return ((InSubQuerySqmPredicate) predicate.getRightHandPredicate()).getSubQueryExpression(); } private SubQuerySqmExpression getRelationaSubQueryExpression(SqmQuerySpec querySpec) { SqmWhereClause whereClause = querySpec.getWhereClause(); RelationalSqmPredicate predicate = (RelationalSqmPredicate) whereClause.getPredicate(); return (SubQuerySqmExpression) predicate.getRightHandExpression(); } private SqmSelectStatement interpretQuery(String query) { return (SqmSelectStatement) SemanticQueryProducer.interpret( query, consumerContext ); } @javax.persistence.Entity( name = "Entity" ) public static class Entity { @Id public Integer id; String basic; String basic1; } @javax.persistence.Entity( name = "Anything" ) public static class Anything { @Id public Integer id; String address; String name; Long basic; Long basic1; Long basic2; Long basic3; Long b; } @javax.persistence.Entity( name = "Something" ) public static class Something { @Id public Integer id; Long basic; Long basic1; Long basic2; Long basic3; Long basic4; @ManyToOne Entity entity; } @javax.persistence.Entity( name = "SomethingElse" ) public static class SomethingElse { @Id public Integer id; Long basic; Long basic1; Long basic2; Long basic3; @ManyToOne Entity entity; } }