From 41e81cbc67088f7fd9636fdb59cc3e912495fe24 Mon Sep 17 00:00:00 2001 From: Strong Liu Date: Wed, 25 May 2011 16:35:58 +0800 Subject: [PATCH] HHH-2225 NPE when eager fetching joined component with native SQL query --- .../sql/NativeSQLQueryNonScalarReturn.java | 6 +-- .../spi/sql/NativeSQLQueryRootReturn.java | 2 +- .../org/hibernate/internal/SQLQueryImpl.java | 31 ++++++++----- .../test/annotations/query/AllTables.java | 45 +++++++++++++++++++ .../annotations/query/QueryAndSQLTest.java | 29 +++++++++++- 5 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/query/AllTables.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/sql/NativeSQLQueryNonScalarReturn.java b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/sql/NativeSQLQueryNonScalarReturn.java index 3d0378c482..fc06c2e448 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/sql/NativeSQLQueryNonScalarReturn.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/sql/NativeSQLQueryNonScalarReturn.java @@ -39,7 +39,7 @@ import org.hibernate.LockMode; public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryReturn, Serializable { private final String alias; private final LockMode lockMode; - private final Map propertyResults = new HashMap(); + private final Map propertyResults = new HashMap(); private final int hashCode; /** @@ -49,7 +49,7 @@ public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryRet * @param propertyResults Any user-supplied column->property mappings * @param lockMode The lock mode to apply to the return. */ - protected NativeSQLQueryNonScalarReturn(String alias, Map propertyResults, LockMode lockMode) { + protected NativeSQLQueryNonScalarReturn(String alias, Map propertyResults, LockMode lockMode) { this.alias = alias; if ( alias == null ) { throw new HibernateException("alias must be specified"); @@ -84,7 +84,7 @@ public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryRet * * @return The property mappings. */ - public Map getPropertyResultsMap() { + public Map getPropertyResultsMap() { return Collections.unmodifiableMap( propertyResults ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/sql/NativeSQLQueryRootReturn.java b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/sql/NativeSQLQueryRootReturn.java index 6703514716..f230646ead 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/sql/NativeSQLQueryRootReturn.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/sql/NativeSQLQueryRootReturn.java @@ -56,7 +56,7 @@ public class NativeSQLQueryRootReturn extends NativeSQLQueryNonScalarReturn { * @param propertyResults Any user-supplied column->property mappings * @param lockMode The lock mode to apply */ - public NativeSQLQueryRootReturn(String alias, String entityName, Map propertyResults, LockMode lockMode) { + public NativeSQLQueryRootReturn(String alias, String entityName, Map propertyResults, LockMode lockMode) { super( alias, propertyResults, lockMode ); this.returnEntityName = entityName; this.hashCode = determineHashCode(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SQLQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SQLQueryImpl.java index 7d64ce1f6d..3a017fe52e 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SQLQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SQLQueryImpl.java @@ -51,6 +51,7 @@ import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn; import org.hibernate.engine.query.spi.sql.NativeSQLQueryScalarReturn; import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification; import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.type.Type; /** @@ -410,7 +411,7 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery { private final String alias; private final String entityName; private LockMode lockMode = LockMode.READ; - private Map> propertyMappings; + private Map propertyMappings; private RootReturnBuilder(String alias, String entityName) { this.alias = alias; @@ -434,15 +435,20 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery { public ReturnProperty addProperty(final String propertyName) { if ( propertyMappings == null ) { - propertyMappings = new HashMap>(); + propertyMappings = new HashMap(); } return new ReturnProperty() { public ReturnProperty addColumnAlias(String columnAlias) { - List columnAliases = propertyMappings.get( propertyName ); + String[] columnAliases = propertyMappings.get( propertyName ); if ( columnAliases == null ) { - columnAliases = new ArrayList(); + columnAliases = new String[]{columnAlias}; + }else{ + String[] newColumnAliases = new String[columnAliases.length + 1]; + System.arraycopy( columnAliases, 0, newColumnAliases, 0, columnAliases.length ); + newColumnAliases[columnAliases.length] = columnAlias; + columnAliases = newColumnAliases; } - columnAliases.add( columnAlias ); + propertyMappings.put( propertyName,columnAliases ); return this; } }; @@ -457,7 +463,7 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery { private String ownerTableAlias; private final String joinedPropertyName; private LockMode lockMode = LockMode.READ; - private Map> propertyMappings; + private Map propertyMappings; private FetchReturnBuilder(String alias, String ownerTableAlias, String joinedPropertyName) { this.alias = alias; @@ -477,15 +483,20 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery { public ReturnProperty addProperty(final String propertyName) { if ( propertyMappings == null ) { - propertyMappings = new HashMap>(); + propertyMappings = new HashMap(); } return new ReturnProperty() { public ReturnProperty addColumnAlias(String columnAlias) { - List columnAliases = propertyMappings.get( propertyName ); + String[] columnAliases = propertyMappings.get( propertyName ); if ( columnAliases == null ) { - columnAliases = new ArrayList(); + columnAliases = new String[]{columnAlias}; + }else{ + String[] newColumnAliases = new String[columnAliases.length + 1]; + System.arraycopy( columnAliases, 0, newColumnAliases, 0, columnAliases.length ); + newColumnAliases[columnAliases.length] = columnAlias; + columnAliases = newColumnAliases; } - columnAliases.add( columnAlias ); + propertyMappings.put( propertyName,columnAliases ); return this; } }; diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/AllTables.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/AllTables.java new file mode 100644 index 0000000000..5baa020ee4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/AllTables.java @@ -0,0 +1,45 @@ +package org.hibernate.test.annotations.query; +import javax.persistence.Column; +import javax.persistence.ColumnResult; +import javax.persistence.Entity; +import javax.persistence.EntityResult; +import javax.persistence.FieldResult; +import javax.persistence.Id; +import javax.persistence.SqlResultSetMapping; +import javax.persistence.Table; + +import org.hibernate.annotations.Formula; + +@Entity +@Table(name = "ALL_TABLES") +@SqlResultSetMapping(name = "all", + entities = @EntityResult(entityClass = AllTables.class, + fields = { + @FieldResult(name = "tableName", column = "t_name"), + @FieldResult(name = "daysOld", column = "t_time") + })) + public class AllTables { + + @Id + @Column(name = "TABLE_NAME", nullable = false) + private String tableName; + + @Formula(value = "(SYSDATE())") + private String daysOld; + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public String getDaysOld() { + return daysOld; + } + + public void setDaysOld(String daysOld) { + this.daysOld = daysOld; + } + } \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java index ac74d8008a..0c718cbdb9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java @@ -31,6 +31,7 @@ import java.util.List; import org.hibernate.MappingException; import org.hibernate.Query; +import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; @@ -39,6 +40,7 @@ import org.hibernate.stat.Statistics; import org.junit.Test; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.test.annotations.A320; @@ -57,6 +59,30 @@ import static org.junit.Assert.fail; * @author Emmanuel Bernard */ public class QueryAndSQLTest extends BaseCoreFunctionalTestCase { + @Test + public void testNativeQueryWithFormulaAttribute() { + String sql = "select t.table_name as {t.tableName}, sysdate() as {t.daysOld} from all_tables t where t.table_name = 'AUDIT_ACTIONS' "; + String sql2 = "select table_name as t_name, sysdate() as t_time from all_tables where table_name = 'AUDIT_ACTIONS' "; + Session s = openSession(); + s.beginTransaction(); + s.createSQLQuery( sql ).addEntity( "t", AllTables.class ).list(); + s.createSQLQuery( sql2 ).setResultSetMapping( "all" ).list(); + SQLQuery q = s.createSQLQuery( sql2 ); + q.addRoot( "t", AllTables.class ).addProperty( "tableName", "t_name" ).addProperty( "daysOld", "t_time" ); + q.list(); + s.getTransaction().commit(); + s.close(); + } + @Test + @FailureExpected( jiraKey = "HHH-2225") + public void testNativeQueryWithFormulaAttributeWithoutAlias() { + String sql = "select table_name , sysdate() from all_tables where table_name = 'AUDIT_ACTIONS' "; + Session s = openSession(); + s.beginTransaction(); + s.createSQLQuery( sql ).addEntity( "t", AllTables.class ).list(); + s.getTransaction().commit(); + s.close(); + } @Test public void testPackageQueries() throws Exception { Session s = openSession(); @@ -415,7 +441,8 @@ public class QueryAndSQLTest extends BaseCoreFunctionalTestCase { SynonymousDictionary.class, Captain.class, Chaos.class, - CasimirParticle.class + CasimirParticle.class, + AllTables.class }; }