diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectClause.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectClause.java index 6e6522d278..3786fb25da 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectClause.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectClause.java @@ -31,6 +31,7 @@ public class SelectClause extends SelectExpressionList { private boolean scalarSelect; private List fromElementsForLoad = new ArrayList(); + private List alreadyRenderedIdentifiers = new ArrayList(); //private Type[] sqlResultTypes; private Type[] queryReturnTypes; private String[][] columnNames; @@ -224,6 +225,7 @@ public class SelectClause extends SelectExpressionList { //sqlResultTypeList.add( type ); // Generate the select expression. String text = fromElement.renderIdentifierSelect( size, k ); + alreadyRenderedIdentifiers.add( text ); SelectExpressionImpl generatedExpr = (SelectExpressionImpl) appender.append( SqlTokenTypes.SELECT_EXPR, text, @@ -355,6 +357,7 @@ public class SelectClause extends SelectExpressionList { } } + @Override protected AST getFirstSelectExpression() { AST n = getFirstChild(); // Skip 'DISTINCT' and 'ALL', so we return the first expression node. @@ -450,7 +453,10 @@ public class SelectClause extends SelectExpressionList { expr.setText( text ); } else { - appender.append( SqlTokenTypes.SQL_TOKEN, text, false ); + if (! alreadyRenderedIdentifiers.contains(text)) { + appender.append( SqlTokenTypes.SQL_TOKEN, text, false ); + alreadyRenderedIdentifiers.add(text); + } } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/pagination/DataMetaPoint.java b/hibernate-core/src/test/java/org/hibernate/test/pagination/DataMetaPoint.java new file mode 100644 index 0000000000..0852abb705 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/pagination/DataMetaPoint.java @@ -0,0 +1,78 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.pagination; + +/** + * @author Piotr Findeisen + */ +public class DataMetaPoint { + private long id; + private DataPoint dataPoint; + private String meta; + + /** + * @return Returns the id. + */ + public long getId() { + return id; + } + + /** + * @param id + * The id to set. + */ + public void setId(long id) { + this.id = id; + } + + public DataPoint getDataPoint() { + return dataPoint; + } + + public void setDataPoint(DataPoint dataPoint) { + this.dataPoint = dataPoint; + } + + public String getMeta() { + return meta; + } + + public void setMeta(String meta) { + this.meta = meta; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((dataPoint == null) ? 0 : dataPoint.hashCode()); + result = prime * result + (int) (id ^ (id >>> 32)); + result = prime * result + ((meta == null) ? 0 : meta.hashCode()); + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DataMetaPoint dataPoint = (DataMetaPoint) o; + + if (meta != null ? !meta.equals(dataPoint.meta) : dataPoint.meta != null) { + return false; + } + if (dataPoint != null ? !dataPoint.equals(dataPoint.dataPoint) : dataPoint.dataPoint != null) { + return false; + } + + return true; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml index 40fc544d7c..1b1452a591 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml @@ -28,4 +28,13 @@ + + + + + + + + diff --git a/hibernate-core/src/test/java/org/hibernate/test/pagination/PaginationTest.java b/hibernate-core/src/test/java/org/hibernate/test/pagination/PaginationTest.java index a3c28ec58c..adf6a0b39d 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/pagination/PaginationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/pagination/PaginationTest.java @@ -7,21 +7,27 @@ package org.hibernate.test.pagination; import java.math.BigDecimal; +import java.util.Collections; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.hibernate.Criteria; import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.criterion.Order; - +import org.hibernate.engine.query.spi.HQLQueryPlan; import org.hibernate.testing.DialectChecks; import org.hibernate.testing.RequiresDialectFeature; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.Test; +import static java.lang.String.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * @author Gavin King @@ -101,6 +107,41 @@ public class PaginationTest extends BaseNonConfigCoreFunctionalTestCase { cleanupTestData(); } + /** + * @author Piotr Findeisen + */ + @Test + @TestForIssue( jiraKey = "HHH-951" ) + @RequiresDialectFeature( + value = DialectChecks.SupportLimitCheck.class, + comment = "Dialect does not support limit" + ) + public void testLimitWithExpreesionAndFetchJoin() { + Session session = openSession(); + session.beginTransaction(); + + String hql = "SELECT b, 1 FROM DataMetaPoint b inner join fetch b.dataPoint dp"; + session.createQuery(hql) + .setMaxResults(3) + // This should not fail + .list(); + + HQLQueryPlan queryPlan = new HQLQueryPlan(hql, false, Collections.EMPTY_MAP, sessionFactory()); + String sqlQuery = queryPlan.getTranslators()[0] + .collectSqlStrings().get(0); + + session.getTransaction().commit(); + session.close(); + + Matcher matcher = Pattern.compile( + "(?is)\\b(?\\w+\\.\\w+)\\s+as\\s+(?\\w+)\\b.*\\k\\s+as\\s+\\k") + .matcher(sqlQuery); + if (matcher.find()) { + fail(format("Column %s mapped to alias %s twice in generated SQL: %s", matcher.group("column"), + matcher.group("alias"), sqlQuery)); + } + } + @Test @RequiresDialectFeature( value = DialectChecks.SupportLimitAndOffsetCheck.class,