HHH-2225 NPE when eager fetching joined component with native SQL query

This commit is contained in:
Strong Liu 2011-05-25 16:35:58 +08:00
parent 6d5ed5fc5e
commit 41e81cbc67
5 changed files with 98 additions and 15 deletions

View File

@ -39,7 +39,7 @@ import org.hibernate.LockMode;
public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryReturn, Serializable { public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryReturn, Serializable {
private final String alias; private final String alias;
private final LockMode lockMode; private final LockMode lockMode;
private final Map propertyResults = new HashMap(); private final Map<String,String[]> propertyResults = new HashMap<String,String[]>();
private final int hashCode; private final int hashCode;
/** /**
@ -49,7 +49,7 @@ public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryRet
* @param propertyResults Any user-supplied column->property mappings * @param propertyResults Any user-supplied column->property mappings
* @param lockMode The lock mode to apply to the return. * @param lockMode The lock mode to apply to the return.
*/ */
protected NativeSQLQueryNonScalarReturn(String alias, Map propertyResults, LockMode lockMode) { protected NativeSQLQueryNonScalarReturn(String alias, Map<String,String[]> propertyResults, LockMode lockMode) {
this.alias = alias; this.alias = alias;
if ( alias == null ) { if ( alias == null ) {
throw new HibernateException("alias must be specified"); throw new HibernateException("alias must be specified");
@ -84,7 +84,7 @@ public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryRet
* *
* @return The property mappings. * @return The property mappings.
*/ */
public Map getPropertyResultsMap() { public Map<String,String[]> getPropertyResultsMap() {
return Collections.unmodifiableMap( propertyResults ); return Collections.unmodifiableMap( propertyResults );
} }

View File

@ -56,7 +56,7 @@ public class NativeSQLQueryRootReturn extends NativeSQLQueryNonScalarReturn {
* @param propertyResults Any user-supplied column->property mappings * @param propertyResults Any user-supplied column->property mappings
* @param lockMode The lock mode to apply * @param lockMode The lock mode to apply
*/ */
public NativeSQLQueryRootReturn(String alias, String entityName, Map propertyResults, LockMode lockMode) { public NativeSQLQueryRootReturn(String alias, String entityName, Map<String,String[]> propertyResults, LockMode lockMode) {
super( alias, propertyResults, lockMode ); super( alias, propertyResults, lockMode );
this.returnEntityName = entityName; this.returnEntityName = entityName;
this.hashCode = determineHashCode(); this.hashCode = determineHashCode();

View File

@ -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.NativeSQLQueryScalarReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification; import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.Type; import org.hibernate.type.Type;
/** /**
@ -410,7 +411,7 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
private final String alias; private final String alias;
private final String entityName; private final String entityName;
private LockMode lockMode = LockMode.READ; private LockMode lockMode = LockMode.READ;
private Map<String,List<String>> propertyMappings; private Map<String,String[]> propertyMappings;
private RootReturnBuilder(String alias, String entityName) { private RootReturnBuilder(String alias, String entityName) {
this.alias = alias; this.alias = alias;
@ -434,15 +435,20 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
public ReturnProperty addProperty(final String propertyName) { public ReturnProperty addProperty(final String propertyName) {
if ( propertyMappings == null ) { if ( propertyMappings == null ) {
propertyMappings = new HashMap<String,List<String>>(); propertyMappings = new HashMap<String,String[]>();
} }
return new ReturnProperty() { return new ReturnProperty() {
public ReturnProperty addColumnAlias(String columnAlias) { public ReturnProperty addColumnAlias(String columnAlias) {
List<String> columnAliases = propertyMappings.get( propertyName ); String[] columnAliases = propertyMappings.get( propertyName );
if ( columnAliases == null ) { if ( columnAliases == null ) {
columnAliases = new ArrayList<String>(); 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; return this;
} }
}; };
@ -457,7 +463,7 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
private String ownerTableAlias; private String ownerTableAlias;
private final String joinedPropertyName; private final String joinedPropertyName;
private LockMode lockMode = LockMode.READ; private LockMode lockMode = LockMode.READ;
private Map<String,List<String>> propertyMappings; private Map<String,String[]> propertyMappings;
private FetchReturnBuilder(String alias, String ownerTableAlias, String joinedPropertyName) { private FetchReturnBuilder(String alias, String ownerTableAlias, String joinedPropertyName) {
this.alias = alias; this.alias = alias;
@ -477,15 +483,20 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
public ReturnProperty addProperty(final String propertyName) { public ReturnProperty addProperty(final String propertyName) {
if ( propertyMappings == null ) { if ( propertyMappings == null ) {
propertyMappings = new HashMap<String,List<String>>(); propertyMappings = new HashMap<String,String[]>();
} }
return new ReturnProperty() { return new ReturnProperty() {
public ReturnProperty addColumnAlias(String columnAlias) { public ReturnProperty addColumnAlias(String columnAlias) {
List<String> columnAliases = propertyMappings.get( propertyName ); String[] columnAliases = propertyMappings.get( propertyName );
if ( columnAliases == null ) { if ( columnAliases == null ) {
columnAliases = new ArrayList<String>(); 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; return this;
} }
}; };

View File

@ -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;
}
}

View File

@ -31,6 +31,7 @@ import java.util.List;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.Query; import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
@ -39,6 +40,7 @@ import org.hibernate.stat.Statistics;
import org.junit.Test; import org.junit.Test;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.test.annotations.A320; import org.hibernate.test.annotations.A320;
@ -57,6 +59,30 @@ import static org.junit.Assert.fail;
* @author Emmanuel Bernard * @author Emmanuel Bernard
*/ */
public class QueryAndSQLTest extends BaseCoreFunctionalTestCase { 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 @Test
public void testPackageQueries() throws Exception { public void testPackageQueries() throws Exception {
Session s = openSession(); Session s = openSession();
@ -415,7 +441,8 @@ public class QueryAndSQLTest extends BaseCoreFunctionalTestCase {
SynonymousDictionary.class, SynonymousDictionary.class,
Captain.class, Captain.class,
Chaos.class, Chaos.class,
CasimirParticle.class CasimirParticle.class,
AllTables.class
}; };
} }