HHH-2225 NPE when eager fetching joined component with native SQL query
This commit is contained in:
parent
6d5ed5fc5e
commit
41e81cbc67
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue