NativeQuery support
- initial working support - simple scalar queries
This commit is contained in:
parent
25fc3e2dce
commit
5dded5de7c
|
@ -6,9 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.engine.query.internal;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.query.spi.NativeQueryInterpreter;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.sql.internal.NativeSelectQueryPlanImpl;
|
||||
import org.hibernate.query.sql.internal.ParameterParser;
|
||||
import org.hibernate.query.sql.spi.NativeSelectQueryDefinition;
|
||||
import org.hibernate.query.sql.spi.NativeSelectQueryPlan;
|
||||
|
@ -32,15 +32,12 @@ public class NativeQueryInterpreterStandardImpl implements NativeQueryInterprete
|
|||
public <R> NativeSelectQueryPlan<R> createQueryPlan(
|
||||
NativeSelectQueryDefinition<R> queryDefinition,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
|
||||
// CustomQuery customQuery = new SQLCustomQuery(
|
||||
// specification.getQueryString(),
|
||||
// specification.getQueryReturns(),
|
||||
// specification.getQuerySpaces(),
|
||||
// sessionFactory
|
||||
// );
|
||||
//
|
||||
// return new NativeSQLQueryPlan( specification.getQueryString(), customQuery );
|
||||
return new NativeSelectQueryPlanImpl<>(
|
||||
queryDefinition.getSqlString(),
|
||||
queryDefinition.getAffectedTableNames(),
|
||||
queryDefinition.getQueryParameterList(),
|
||||
queryDefinition.getJdbcValuesMappingProducer(),
|
||||
queryDefinition.getRowTransformer()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
|
@ -468,4 +469,15 @@ public final class ArrayHelper {
|
|||
public static boolean isEmpty(Object[] array) {
|
||||
return array == null || array.length == 0;
|
||||
}
|
||||
|
||||
public static <T> void forEach(T[] array, Consumer<T> consumer) {
|
||||
if ( array == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for ( int i = 0; i < array.length; i++ ) {
|
||||
consumer.accept( array[ i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,11 +49,12 @@ import org.hibernate.query.Query;
|
|||
import org.hibernate.query.QueryParameter;
|
||||
import org.hibernate.query.internal.QueryOptionsImpl;
|
||||
import org.hibernate.query.procedure.ProcedureParameter;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
import org.hibernate.query.results.ResultSetMappingImpl;
|
||||
import org.hibernate.query.spi.AbstractQuery;
|
||||
import org.hibernate.query.spi.MutableQueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.result.NoMoreReturnsException;
|
||||
import org.hibernate.result.Output;
|
||||
import org.hibernate.result.ResultSetOutput;
|
||||
|
@ -83,7 +84,7 @@ public class ProcedureCallImpl<R>
|
|||
private final ProcedureParameterMetadataImpl parameterMetadata;
|
||||
private final ProcedureParamBindings paramBindings;
|
||||
|
||||
private final List<DomainResultProducer<?>> domainResultProducers;
|
||||
private final ResultSetMapping resultSetMapping = new ResultSetMappingImpl();
|
||||
|
||||
private Set<String> synchronizedQuerySpaces;
|
||||
|
||||
|
@ -106,7 +107,6 @@ public class ProcedureCallImpl<R>
|
|||
this.paramBindings = new ProcedureParamBindings( parameterMetadata, getSessionFactory() );
|
||||
|
||||
this.synchronizedQuerySpaces = null;
|
||||
this.domainResultProducers = null;
|
||||
}
|
||||
/**
|
||||
* The result Class(es) return form
|
||||
|
@ -125,12 +125,11 @@ public class ProcedureCallImpl<R>
|
|||
this.parameterMetadata = new ProcedureParameterMetadataImpl();
|
||||
this.paramBindings = new ProcedureParamBindings( parameterMetadata, getSessionFactory() );
|
||||
|
||||
this.domainResultProducers = CollectionHelper.arrayList( resultClasses.length );
|
||||
this.synchronizedQuerySpaces = new HashSet<>();
|
||||
|
||||
Util.resolveResultSetMappingClasses(
|
||||
resultClasses,
|
||||
domainResultProducers::add,
|
||||
resultSetMapping,
|
||||
synchronizedQuerySpaces::add,
|
||||
getSession().getFactory()
|
||||
);
|
||||
|
@ -156,12 +155,11 @@ public class ProcedureCallImpl<R>
|
|||
this.parameterMetadata = new ProcedureParameterMetadataImpl();
|
||||
this.paramBindings = new ProcedureParamBindings( parameterMetadata, getSessionFactory() );
|
||||
|
||||
this.domainResultProducers = CollectionHelper.arrayList( resultSetMappingNames.length );
|
||||
this.synchronizedQuerySpaces = new HashSet<>();
|
||||
|
||||
Util.resolveResultSetMappingNames(
|
||||
resultSetMappingNames,
|
||||
domainResultProducers::add,
|
||||
resultSetMapping,
|
||||
synchronizedQuerySpaces::add,
|
||||
getSession().getFactory()
|
||||
);
|
||||
|
@ -180,13 +178,12 @@ public class ProcedureCallImpl<R>
|
|||
this.parameterMetadata = new ProcedureParameterMetadataImpl( memento, session );
|
||||
this.paramBindings = new ProcedureParamBindings( parameterMetadata, getSessionFactory() );
|
||||
|
||||
this.domainResultProducers = new ArrayList<>();
|
||||
this.synchronizedQuerySpaces = CollectionHelper.makeCopy( memento.getQuerySpaces() );
|
||||
|
||||
Util.resolveResultSetMappings(
|
||||
memento.getResultSetMappingNames(),
|
||||
memento.getResultSetMappingClasses(),
|
||||
domainResultProducers::add,
|
||||
resultSetMapping,
|
||||
synchronizedQuerySpaces::add,
|
||||
getSession().getFactory()
|
||||
);
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.query.named.NamedQueryRepository;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.query.spi.ResultSetMapping;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -32,7 +32,7 @@ public class Util {
|
|||
public static void resolveResultSetMappings(
|
||||
String[] resultSetMappingNames,
|
||||
Class[] resultSetMappingClasses,
|
||||
Consumer<DomainResultProducer> resultProducerConsumer,
|
||||
ResultSetMapping resultSetMapping,
|
||||
Consumer<String> querySpaceConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
if ( ! ArrayHelper.isEmpty( resultSetMappingNames ) ) {
|
||||
|
@ -40,10 +40,10 @@ public class Util {
|
|||
if ( ! ArrayHelper.isEmpty( resultSetMappingClasses ) ) {
|
||||
throw new IllegalArgumentException( "Cannot specify both result-set mapping names and classes" );
|
||||
}
|
||||
resolveResultSetMappingNames( resultSetMappingNames, resultProducerConsumer, querySpaceConsumer, sessionFactory );
|
||||
resolveResultSetMappingNames( resultSetMappingNames, resultSetMapping, querySpaceConsumer, sessionFactory );
|
||||
}
|
||||
else if ( ! ArrayHelper.isEmpty( resultSetMappingClasses ) ) {
|
||||
resolveResultSetMappingClasses( resultSetMappingClasses, resultProducerConsumer, querySpaceConsumer, sessionFactory );
|
||||
resolveResultSetMappingClasses( resultSetMappingClasses, resultSetMapping, querySpaceConsumer, sessionFactory );
|
||||
}
|
||||
|
||||
// otherwise, nothing to resolve
|
||||
|
@ -51,22 +51,24 @@ public class Util {
|
|||
|
||||
public static void resolveResultSetMappingNames(
|
||||
String[] resultSetMappingNames,
|
||||
Consumer<DomainResultProducer> resultProducerConsumer,
|
||||
ResultSetMapping resultSetMapping,
|
||||
Consumer<String> querySpaceConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final NamedQueryRepository namedQueryRepository = sessionFactory.getQueryEngine().getNamedQueryRepository();
|
||||
|
||||
for ( String resultSetMappingName : resultSetMappingNames ) {
|
||||
final NamedResultSetMappingMemento memento = namedQueryRepository.getResultSetMappingMemento( resultSetMappingName );
|
||||
final ResultSetMapping resultSetMapping = memento.toResultSetMapping();
|
||||
resultProducerConsumer.accept( resultSetMapping );
|
||||
// todo (6.0) : determine query spaces - maybe passing the consumer to `NamedResultSetMappingMemento#toResultSetMapping`?
|
||||
memento.resolve(
|
||||
resultSetMapping,
|
||||
querySpaceConsumer,
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void resolveResultSetMappingClasses(
|
||||
Class[] resultSetMappingClasses,
|
||||
Consumer<DomainResultProducer> resultProducerConsumer,
|
||||
ResultSetMapping resultSetMapping,
|
||||
Consumer<String> querySpaceConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
throw new NotYetImplementedFor6Exception( Util.class );
|
||||
|
|
|
@ -25,7 +25,7 @@ public abstract class AbstractQueryParameter<T> implements QueryParameterImpleme
|
|||
|
||||
@Override
|
||||
public void disallowMultiValuedBinding() {
|
||||
QueryLogger.QUERY_LOGGER.debugf( "QueryParameter#disallowMultiValuedBinding() called : %s", this );
|
||||
QueryLogger.QUERY_MESSAGE_LOGGER.debugf( "QueryParameter#disallowMultiValuedBinding() called : %s", this );
|
||||
this.allowMultiValuedBinding = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ import static org.jboss.logging.Logger.Level.ERROR;
|
|||
public interface QueryLogger extends BasicLogger {
|
||||
String LOGGER_NAME = "org.hibernate.orm.query";
|
||||
|
||||
QueryLogger QUERY_LOGGER = Logger.getMessageLogger( QueryLogger.class, LOGGER_NAME );
|
||||
Logger QUERY_LOGGER = Logger.getLogger( LOGGER_NAME );
|
||||
QueryLogger QUERY_MESSAGE_LOGGER = Logger.getMessageLogger( QueryLogger.class, LOGGER_NAME );
|
||||
|
||||
boolean TRACE_ENABLED = QUERY_LOGGER.isTraceEnabled();
|
||||
boolean DEBUG_ENABLED = QUERY_LOGGER.isDebugEnabled();
|
||||
|
|
|
@ -123,6 +123,10 @@ public class NamedQueryRepositoryImpl implements NamedQueryRepository {
|
|||
resultSetMappingMementoMap.put( name, memento );
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Prepare repository for use
|
||||
|
||||
@Override
|
||||
public void prepare(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.query.internal;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.query.spi.ResultSetMapping;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -27,7 +29,10 @@ public class NamedResultSetMappingMementoImpl implements NamedResultSetMappingMe
|
|||
}
|
||||
|
||||
@Override
|
||||
public ResultSetMapping toResultSetMapping() {
|
||||
public void resolve(
|
||||
ResultSetMapping resultSetMapping,
|
||||
Consumer<String> querySpaceConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.query.internal;
|
||||
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface NativeQueryReturnBuilder {
|
||||
NativeSQLQueryReturn buildReturn();
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.query.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryJoinReturn;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
||||
import org.hibernate.query.NativeQuery;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NativeQueryReturnBuilderFetchImpl implements NativeQuery.FetchReturn, NativeQueryReturnBuilder {
|
||||
private final String alias;
|
||||
private String ownerTableAlias;
|
||||
private final String joinedPropertyName;
|
||||
private LockMode lockMode = LockMode.READ;
|
||||
private Map<String, String[]> propertyMappings;
|
||||
|
||||
public NativeQueryReturnBuilderFetchImpl(String alias, String ownerTableAlias, String joinedPropertyName) {
|
||||
this.alias = alias;
|
||||
this.ownerTableAlias = ownerTableAlias;
|
||||
this.joinedPropertyName = joinedPropertyName;
|
||||
}
|
||||
|
||||
public NativeQuery.FetchReturn setLockMode(LockMode lockMode) {
|
||||
this.lockMode = lockMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeQuery.FetchReturn addProperty(String propertyName, String columnAlias) {
|
||||
addProperty( propertyName ).addColumnAlias( columnAlias );
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeQuery.ReturnProperty addProperty(final String propertyName) {
|
||||
if ( propertyMappings == null ) {
|
||||
propertyMappings = new HashMap<>();
|
||||
}
|
||||
return new NativeQuery.ReturnProperty() {
|
||||
public NativeQuery.ReturnProperty addColumnAlias(String columnAlias) {
|
||||
String[] columnAliases = propertyMappings.get( propertyName );
|
||||
if ( columnAliases == null ) {
|
||||
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;
|
||||
}
|
||||
propertyMappings.put( propertyName, columnAliases );
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public NativeSQLQueryReturn buildReturn() {
|
||||
return new NativeSQLQueryJoinReturn(
|
||||
alias,
|
||||
ownerTableAlias,
|
||||
joinedPropertyName,
|
||||
propertyMappings,
|
||||
lockMode
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.query.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
|
||||
import org.hibernate.query.NativeQuery;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NativeQueryReturnBuilderRootImpl implements NativeQuery.RootReturn, NativeQueryReturnBuilder {
|
||||
private final String alias;
|
||||
private final String entityName;
|
||||
private LockMode lockMode = LockMode.READ;
|
||||
private Map<String, String[]> propertyMappings;
|
||||
|
||||
public NativeQueryReturnBuilderRootImpl(String alias, String entityName) {
|
||||
this.alias = alias;
|
||||
this.entityName = entityName;
|
||||
}
|
||||
|
||||
public NativeQuery.RootReturn setLockMode(LockMode lockMode) {
|
||||
this.lockMode = lockMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeQuery.RootReturn setDiscriminatorAlias(String alias) {
|
||||
addProperty( "class", alias );
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeQuery.RootReturn addProperty(String propertyName, String columnAlias) {
|
||||
addProperty( propertyName ).addColumnAlias( columnAlias );
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeQuery.ReturnProperty addProperty(final String propertyName) {
|
||||
if ( propertyMappings == null ) {
|
||||
propertyMappings = new HashMap<>();
|
||||
}
|
||||
return new NativeQuery.ReturnProperty() {
|
||||
public NativeQuery.ReturnProperty addColumnAlias(String columnAlias) {
|
||||
String[] columnAliases = propertyMappings.get( propertyName );
|
||||
if ( columnAliases == null ) {
|
||||
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;
|
||||
}
|
||||
propertyMappings.put( propertyName, columnAliases );
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public NativeSQLQueryReturn buildReturn() {
|
||||
return new NativeSQLQueryRootReturn( alias, entityName, propertyMappings, lockMode );
|
||||
}
|
||||
}
|
|
@ -6,8 +6,11 @@
|
|||
*/
|
||||
package org.hibernate.query.named;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.query.spi.ResultSetMapping;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
|
||||
/**
|
||||
* Used to keep information about named result mappings defined by the
|
||||
|
@ -27,8 +30,5 @@ import org.hibernate.query.spi.ResultSetMapping;
|
|||
public interface NamedResultSetMappingMemento {
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* todo (6.0) : determine the proper arguments. depends on how we port JdbcValues, etc from the original 6.0 work
|
||||
*/
|
||||
ResultSetMapping toResultSetMapping();
|
||||
void resolve(ResultSetMapping resultSetMapping, Consumer<String> querySpaceConsumer, SessionFactoryImplementor sessionFactory);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractPropertyContainer<T extends AbstractPropertyContainer<T>> implements PropertyContainer {
|
||||
private Map<String,FetchBuilder> fetchBuilderMap;
|
||||
|
||||
protected abstract String getPropertyBase();
|
||||
|
||||
@Override
|
||||
public T addProperty(String propertyName, String columnAlias) {
|
||||
final FetchBuilder fetchBuilder = addProperty( propertyName );
|
||||
fetchBuilder.addColumnAlias( columnAlias );
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T addProperty(String propertyName, String... columnAliases) {
|
||||
final FetchBuilder fetchBuilder = addProperty( propertyName );
|
||||
ArrayHelper.forEach( columnAliases, fetchBuilder::addColumnAlias );
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchBuilder addProperty(String propertyName) {
|
||||
if ( fetchBuilderMap == null ) {
|
||||
fetchBuilderMap = new HashMap<>();
|
||||
}
|
||||
else {
|
||||
final FetchBuilder existing = fetchBuilderMap.get( propertyName );
|
||||
if ( existing != null ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Fetch was already defined for %s.%s : %s",
|
||||
getPropertyBase(),
|
||||
propertyName,
|
||||
existing
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final FetchBuilder fetchBuilder = new StandardFetchBuilderImpl();
|
||||
fetchBuilderMap.put( propertyName, fetchBuilder );
|
||||
|
||||
return fetchBuilder;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface BuilderGraphNode {
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class Builders {
|
||||
public static ScalarResultBuilder scalar(
|
||||
String columnAlias,
|
||||
BasicType<?> type) {
|
||||
return new ScalarResultBuilder( columnAlias, type );
|
||||
}
|
||||
|
||||
public static ScalarResultBuilder scalar(
|
||||
String columnAlias,
|
||||
Class<?> javaType,
|
||||
SessionFactoryImplementor factory) {
|
||||
return new ScalarResultBuilder(
|
||||
columnAlias,
|
||||
factory.getTypeConfiguration().getBasicTypeForJavaType( javaType )
|
||||
);
|
||||
}
|
||||
|
||||
public static DomainResult<?> implicitScalarDomainResult(
|
||||
int colIndex,
|
||||
String columnName,
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( colIndex );
|
||||
final BasicJavaDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
||||
final BasicType<?> jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, sqlTypeDescriptor );
|
||||
sqlSelectionConsumer.accept( new SqlSelectionImpl( colIndex, jdbcMapping ) );
|
||||
return new BasicResult<>( colIndex, columnName, javaTypeDescriptor );
|
||||
}
|
||||
|
||||
public static EntityResultBuilder entity(String tableAlias, String entityName) {
|
||||
throw new NotYetImplementedFor6Exception( );
|
||||
}
|
||||
|
||||
public static LegacyFetchBuilder fetch(String tableAlias, String ownerTableAlias, String joinPropertyName) {
|
||||
throw new NotYetImplementedFor6Exception( );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.NativeQuery;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityResultBuilder
|
||||
extends AbstractPropertyContainer<EntityResultBuilder>
|
||||
implements ResultBuilder, NativeQuery.RootReturn {
|
||||
private final String entityName;
|
||||
private final String tableAlias;
|
||||
|
||||
private LockMode lockMode;
|
||||
|
||||
private String discriminatorColumnAlias;
|
||||
|
||||
public EntityResultBuilder(String entityName, String tableAlias) {
|
||||
this.entityName = entityName;
|
||||
this.tableAlias = tableAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPropertyBase() {
|
||||
return entityName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<?> buildReturn(
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
|
||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityResultBuilder setLockMode(LockMode lockMode) {
|
||||
this.lockMode = lockMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityResultBuilder setDiscriminatorAlias(String columnAlias) {
|
||||
this.discriminatorColumnAlias = columnAlias;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.NativeQuery;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
/**
|
||||
* Responsible for building a single {@link DomainResult} instance as part of
|
||||
* the overall mapping of native / procedure query results.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface FetchBuilder extends NativeQuery.ReturnProperty {
|
||||
Fetch buildFetch(
|
||||
FetchParent parent,
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||
SessionFactoryImplementor sessionFactory);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping;
|
||||
|
||||
/**
|
||||
* Implementation of JdbcValuesMapping for native / procedure queries
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcValuesMappingImpl implements JdbcValuesMapping {
|
||||
private final List<SqlSelection> sqlSelections;
|
||||
private final List<DomainResult<?>> domainResults;
|
||||
|
||||
public JdbcValuesMappingImpl(
|
||||
List<SqlSelection> sqlSelections,
|
||||
List<DomainResult<?>> domainResults) {
|
||||
this.sqlSelections = sqlSelections;
|
||||
this.domainResults = domainResults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SqlSelection> getSqlSelections() {
|
||||
return sqlSelections;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public List<DomainResult> getDomainResults() {
|
||||
return (List) domainResults;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public List<DomainResultAssembler> resolveAssemblers(AssemblerCreationState creationState) {
|
||||
final List<DomainResultAssembler> assemblers = new ArrayList<>( domainResults.size() );
|
||||
domainResults.forEach(
|
||||
domainResult -> assemblers.add( domainResult.createResultAssembler( creationState ) )
|
||||
);
|
||||
return assemblers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import org.hibernate.query.NativeQuery;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface LegacyFetchBuilder extends FetchBuilder, NativeQuery.FetchReturn {
|
||||
String getOwnerAlias();
|
||||
String getFetchAlias();
|
||||
String getFetchedAttributeName();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface PropertyContainer {
|
||||
/**
|
||||
* Add a simple property-to-one-column mapping.
|
||||
*/
|
||||
PropertyContainer addProperty(String propertyName, String columnAlias);
|
||||
|
||||
/**
|
||||
* Add a property mapped to multiple columns
|
||||
*/
|
||||
PropertyContainer addProperty(String propertyName, String... columnAliases);
|
||||
|
||||
/**
|
||||
* Add a property whose columns can later be defined using {@link FetchBuilder#addColumnAlias}
|
||||
*/
|
||||
FetchBuilder addProperty(String propertyName);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
/**
|
||||
* Responsible for building a single {@link DomainResult} instance as part of
|
||||
* the overall mapping of native / procedure query results.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface ResultBuilder {
|
||||
DomainResult<?> buildReturn(
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
BiFunction<String,String,LegacyFetchBuilder> legacyFetchResolver,
|
||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||
SessionFactoryImplementor sessionFactory);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
|
||||
|
||||
/**
|
||||
* Acts as the {@link JdbcValuesMappingProducer} for {@link org.hibernate.query.NativeQuery}
|
||||
* or {@link org.hibernate.procedure.ProcedureCall} / {@link javax.persistence.StoredProcedureQuery}
|
||||
* instances.
|
||||
*
|
||||
* Collects builders for results and fetches and manages resolving them via JdbcValuesMappingProducer
|
||||
*
|
||||
* @see org.hibernate.query.NativeQuery#addScalar
|
||||
* @see org.hibernate.query.NativeQuery#addEntity
|
||||
* @see org.hibernate.query.NativeQuery#addJoin
|
||||
* @see org.hibernate.query.NativeQuery#addFetch
|
||||
* @see org.hibernate.query.NativeQuery#addRoot
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface ResultSetMapping extends JdbcValuesMappingProducer {
|
||||
int getNumberOfResultBuilders();
|
||||
|
||||
void visitResultBuilders(BiConsumer<Integer, ResultBuilder> resultBuilderConsumer);
|
||||
|
||||
void addResultBuilder(ResultBuilder resultBuilder);
|
||||
void addLegacyFetchBuilder(LegacyFetchBuilder fetchBuilder);
|
||||
|
||||
NamedResultSetMappingMemento toMemento(String name);
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
@Internal
|
||||
public class ResultSetMappingImpl implements ResultSetMapping {
|
||||
private List<ResultBuilder> resultBuilders;
|
||||
private Map<String, Map<String,LegacyFetchBuilder>> legacyFetchBuilders;
|
||||
|
||||
@Override
|
||||
public int getNumberOfResultBuilders() {
|
||||
return resultBuilders == null ? 0 : resultBuilders.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitResultBuilders(BiConsumer<Integer, ResultBuilder> resultBuilderConsumer) {
|
||||
if ( resultBuilders == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < resultBuilders.size(); i++ ) {
|
||||
resultBuilderConsumer.accept( i, resultBuilders.get( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResultBuilder(ResultBuilder resultBuilder) {
|
||||
if ( resultBuilders == null ) {
|
||||
resultBuilders = new ArrayList<>();
|
||||
}
|
||||
resultBuilders.add( resultBuilder );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLegacyFetchBuilder(LegacyFetchBuilder fetchBuilder) {
|
||||
final Map<String, LegacyFetchBuilder> existingFetchBuildersByOwner;
|
||||
|
||||
if ( legacyFetchBuilders == null ) {
|
||||
legacyFetchBuilders = new HashMap<>();
|
||||
existingFetchBuildersByOwner = null;
|
||||
}
|
||||
else {
|
||||
existingFetchBuildersByOwner = legacyFetchBuilders.get( fetchBuilder.getOwnerAlias() );
|
||||
}
|
||||
|
||||
final Map<String, LegacyFetchBuilder> fetchBuildersByOwner;
|
||||
if ( existingFetchBuildersByOwner == null ) {
|
||||
fetchBuildersByOwner = new HashMap<>();
|
||||
legacyFetchBuilders.put( fetchBuilder.getOwnerAlias(), fetchBuildersByOwner );
|
||||
}
|
||||
else {
|
||||
fetchBuildersByOwner = existingFetchBuildersByOwner;
|
||||
}
|
||||
|
||||
final LegacyFetchBuilder previousBuilder = fetchBuildersByOwner.put( fetchBuilder.getFetchedAttributeName(), fetchBuilder );
|
||||
if ( previousBuilder != null ) {
|
||||
// todo (6.0) : error? log? nothing?
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcValuesMapping resolve(
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final List<SqlSelection> sqlSelections = new ArrayList<>( jdbcResultsMetadata.getColumnCount() );
|
||||
|
||||
final int numberOfResults;
|
||||
|
||||
if ( resultBuilders == null ) {
|
||||
numberOfResults = jdbcResultsMetadata.getColumnCount();
|
||||
}
|
||||
else {
|
||||
numberOfResults = resultBuilders.size();
|
||||
}
|
||||
|
||||
final List<DomainResult<?>> domainResults = new ArrayList<>( numberOfResults );
|
||||
|
||||
for ( int i = 0; i < numberOfResults; i++ ) {
|
||||
final ResultBuilder resultBuilder = resultBuilders != null
|
||||
? resultBuilders.get( i )
|
||||
: null;
|
||||
|
||||
final DomainResult<?> domainResult;
|
||||
if ( resultBuilder == null ) {
|
||||
domainResult = makeImplicitDomainResult(
|
||||
i,
|
||||
sqlSelections::add,
|
||||
jdbcResultsMetadata,
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
else {
|
||||
domainResult = resultBuilder.buildReturn(
|
||||
jdbcResultsMetadata,
|
||||
(ownerAlias, fetchName) -> {
|
||||
if ( legacyFetchBuilders == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Map<String, LegacyFetchBuilder> fetchBuildersForOwner = legacyFetchBuilders.get(
|
||||
ownerAlias );
|
||||
if ( fetchBuildersForOwner == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fetchBuildersForOwner.get( fetchName );
|
||||
},
|
||||
sqlSelections::add,
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
domainResults.add( domainResult );
|
||||
}
|
||||
|
||||
return new JdbcValuesMappingImpl( sqlSelections, domainResults );
|
||||
}
|
||||
|
||||
private DomainResult<?> makeImplicitDomainResult(
|
||||
int valuesArrayPosition,
|
||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final int jdbcPosition = valuesArrayPosition + 1;
|
||||
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
|
||||
|
||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||
|
||||
final JavaTypeDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
||||
|
||||
final BasicType<?> jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve(
|
||||
javaTypeDescriptor,
|
||||
sqlTypeDescriptor
|
||||
);
|
||||
|
||||
final String name = jdbcResultsMetadata.resolveColumnName( jdbcPosition );
|
||||
|
||||
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, jdbcMapping );
|
||||
sqlSelectionConsumer.accept( sqlSelection );
|
||||
|
||||
return new BasicResult( valuesArrayPosition, name, jdbcMapping.getJavaTypeDescriptor() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedResultSetMappingMemento toMemento(String name) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @see javax.persistence.ColumnResult
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ScalarResultBuilder implements ResultBuilder {
|
||||
private final String explicitName;
|
||||
private final BasicType<?> explicitType;
|
||||
|
||||
ScalarResultBuilder(String explicitName, BasicType<?> explicitType) {
|
||||
assert explicitName != null;
|
||||
this.explicitName = explicitName;
|
||||
this.explicitType = explicitType;
|
||||
}
|
||||
|
||||
public String getExplicitName() {
|
||||
return explicitName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<?> buildReturn(
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
|
||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( explicitName );
|
||||
final int valuesArrayPosition = jdbcPosition - 1;
|
||||
|
||||
final BasicType<?> jdbcMapping;
|
||||
|
||||
if ( explicitType != null ) {
|
||||
jdbcMapping = explicitType;
|
||||
}
|
||||
else {
|
||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||
|
||||
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
|
||||
final JavaTypeDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
|
||||
|
||||
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, sqlTypeDescriptor );
|
||||
}
|
||||
|
||||
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, jdbcMapping );
|
||||
sqlSelectionConsumer.accept( sqlSelection );
|
||||
|
||||
return new BasicResult( valuesArrayPosition, explicitName, jdbcMapping.getJavaTypeDescriptor() );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
|
||||
/**
|
||||
* SqlSelection for NativeQuery
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqlSelectionImpl implements SqlSelection {
|
||||
private final int valuesArrayPosition;
|
||||
private final BasicValuedMapping valueMapping;
|
||||
|
||||
public SqlSelectionImpl(int valuesArrayPosition, BasicValuedMapping valueMapping) {
|
||||
this.valuesArrayPosition = valuesArrayPosition;
|
||||
this.valueMapping = valueMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueExtractor getJdbcValueExtractor() {
|
||||
return valueMapping.getJdbcMapping().getJdbcValueExtractor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getValuesArrayPosition() {
|
||||
return valuesArrayPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingModelExpressable getExpressionType() {
|
||||
return valueMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(SqlAstWalker sqlAstWalker) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.NativeQuery;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardFetchBuilderImpl implements FetchBuilder {
|
||||
@Override
|
||||
public Fetch buildFetch(
|
||||
FetchParent parent,
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NativeQuery.ReturnProperty addColumnAlias(String columnAlias) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for defining result-set mappings used in {@link org.hibernate.query.NativeQuery}
|
||||
* and {@link org.hibernate.procedure.ProcedureCall} / {@link javax.persistence.StoredProcedureQuery}.
|
||||
* These result-set mappings are used to map the values in the JDBC {@link java.sql.ResultSet}
|
||||
* into "domain results" (see {@link org.hibernate.sql.results.graph.DomainResult}).
|
||||
*
|
||||
* @see org.hibernate.query.results.ResultSetMapping
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
package org.hibernate.query.results;
|
|
@ -304,7 +304,7 @@ public class QueryEngine {
|
|||
StringBuilder failingQueries = new StringBuilder( "Errors in named queries: " );
|
||||
String sep = "";
|
||||
for ( Map.Entry<String, HibernateException> entry : errors.entrySet() ) {
|
||||
QueryLogger.QUERY_LOGGER.namedQueryError( entry.getKey(), entry.getValue() );
|
||||
QueryLogger.QUERY_MESSAGE_LOGGER.namedQueryError( entry.getKey(), entry.getValue() );
|
||||
failingQueries.append( sep ).append( entry.getKey() );
|
||||
sep = ", ";
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.spi;
|
||||
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* A builder for {@link DomainResult} instances related to native SQL query results.
|
||||
*
|
||||
* todo (6.0) : Perhaps this should be a builder for QueryResultProducer instances instead?
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface QueryResultBuilder {
|
||||
// todo (6.0) : need to add the notion of "builders" that nest inside other builders.
|
||||
// Nesting can happen as:
|
||||
//
|
||||
// For a scalar, it might represent:
|
||||
// 1) a top-level QueryResult
|
||||
// 2) a column within the attribute mapping for entity (or composite?)
|
||||
// 3) an argument to a dynamic-instantiation
|
||||
//
|
||||
// For an attribute, it always represents a non-QueryResult. At least I
|
||||
// think that is accurate - validate this, can an attribute be defined
|
||||
// as a top-level QueryResult? dynamic-instantiation argument? - JPA at least does not support that
|
||||
//
|
||||
// For dynamic-instantiation, it might represent:
|
||||
// 1) a top-level QueryResult
|
||||
// 2) dynamic-instantiation argument (non-JPA)
|
||||
|
||||
JavaTypeDescriptor getResultType();
|
||||
|
||||
DomainResult buildReturn(DomainResultCreationState creationState);
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.spi;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
|
||||
/**
|
||||
* Describes a ResultSet mapping applied to either a {@link org.hibernate.query.NativeQuery}
|
||||
* or a {@link org.hibernate.procedure.ProcedureCall} / {@link javax.persistence.StoredProcedureQuery}.
|
||||
*
|
||||
* It is either generated from a {@link NamedResultSetMappingMemento} or
|
||||
* on-the-fly via Hibernate's {@link org.hibernate.query.NativeQuery} contract. Acts
|
||||
* as the {@link DomainResultProducer} for these uses
|
||||
*
|
||||
* @see org.hibernate.query.NativeQuery#addScalar
|
||||
* @see org.hibernate.query.NativeQuery#addEntity
|
||||
* @see org.hibernate.query.NativeQuery#addJoin
|
||||
* @see org.hibernate.query.NativeQuery#addFetch
|
||||
* @see org.hibernate.query.NativeQuery#addRoot
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface ResultSetMapping extends DomainResultProducer {
|
||||
}
|
|
@ -11,7 +11,6 @@ import java.time.Instant;
|
|||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -38,9 +37,6 @@ import org.hibernate.NotYetImplementedFor6Exception;
|
|||
import org.hibernate.QueryException;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.engine.query.spi.NativeQueryInterpreter;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryConstructorReturn;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryScalarReturn;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.graph.GraphSemantic;
|
||||
|
@ -56,12 +52,13 @@ import org.hibernate.query.Query;
|
|||
import org.hibernate.query.QueryParameter;
|
||||
import org.hibernate.query.ResultListTransformer;
|
||||
import org.hibernate.query.TupleTransformer;
|
||||
import org.hibernate.query.internal.NativeQueryReturnBuilder;
|
||||
import org.hibernate.query.internal.NativeQueryReturnBuilderFetchImpl;
|
||||
import org.hibernate.query.internal.NativeQueryReturnBuilderRootImpl;
|
||||
import org.hibernate.query.internal.ParameterMetadataImpl;
|
||||
import org.hibernate.query.internal.QueryOptionsImpl;
|
||||
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
||||
import org.hibernate.query.results.Builders;
|
||||
import org.hibernate.query.results.EntityResultBuilder;
|
||||
import org.hibernate.query.results.LegacyFetchBuilder;
|
||||
import org.hibernate.query.results.ResultSetMappingImpl;
|
||||
import org.hibernate.query.spi.AbstractQuery;
|
||||
import org.hibernate.query.spi.MutableQueryOptions;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
|
@ -84,6 +81,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
|
|||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
|
||||
import org.hibernate.sql.results.spi.RowTransformer;
|
||||
import org.hibernate.transform.ResultTransformer;
|
||||
import org.hibernate.type.BasicType;
|
||||
|
||||
import static org.hibernate.jpa.QueryHints.HINT_NATIVE_LOCKMODE;
|
||||
|
||||
|
@ -104,11 +102,7 @@ public class NativeQueryImpl<R>
|
|||
|
||||
private Set<String> querySpaces;
|
||||
|
||||
|
||||
|
||||
private List<NativeSQLQueryReturn> queryReturns;
|
||||
private List<NativeQueryReturnBuilder> queryReturnBuilders;
|
||||
private boolean autoDiscoverTypes;
|
||||
private ResultSetMappingImpl resultSetMapping = new ResultSetMappingImpl();
|
||||
|
||||
private Object collectionKey;
|
||||
private NativeQueryInterpreter nativeQueryInterpreter;
|
||||
|
@ -141,7 +135,10 @@ public class NativeQueryImpl<R>
|
|||
SharedSessionContractImplementor session) {
|
||||
this( memento, session );
|
||||
|
||||
// todo (6.0) : validate `resultJavaType` against specified result-set mapping
|
||||
// todo (6.0) : need to add handling for `javax.persistence.NamedNativeQuery#resultSetMapping`
|
||||
// and `javax.persistence.NamedNativeQuery#resultClass`
|
||||
|
||||
// todo (6.0) : relatedly, does `resultJavaType` come from `NamedNativeQuery#resultClass`?
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,6 +149,11 @@ public class NativeQueryImpl<R>
|
|||
String resultSetMappingName,
|
||||
SharedSessionContractImplementor session) {
|
||||
this( memento, session );
|
||||
|
||||
// todo (6.0) : need to add handling for `javax.persistence.NamedNativeQuery#resultSetMapping`
|
||||
// and `javax.persistence.NamedNativeQuery#resultClass`
|
||||
|
||||
// todo (6.0) : relatedly, does `resultSetMappingName` come from `NamedNativeQuery#resultSetMapping`?
|
||||
}
|
||||
|
||||
private ParameterInterpretation resolveParameterInterpretation(SharedSessionContractImplementor session) {
|
||||
|
@ -199,7 +201,6 @@ public class NativeQueryImpl<R>
|
|||
|
||||
this.sqlString = sqlString;
|
||||
|
||||
this.queryReturns = new ArrayList<>();
|
||||
this.querySpaces = new HashSet<>();
|
||||
|
||||
final ParameterInterpretation parameterInterpretation = resolveParameterInterpretation( session );
|
||||
|
@ -332,44 +333,56 @@ public class NativeQueryImpl<R>
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private SelectQueryPlan<R> resolveSelectQueryPlan() {
|
||||
|
||||
SelectQueryPlan<R> queryPlan = null;
|
||||
|
||||
|
||||
final JdbcValuesMappingProducer resultSetMapping = getJdbcValuesMappingProducer();
|
||||
|
||||
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping );
|
||||
if ( cacheKey != null ) {
|
||||
return getSession().getFactory().getQueryEngine().getInterpretationCache().resolveSelectQueryPlan(
|
||||
cacheKey,
|
||||
this::createQueryPlan
|
||||
() -> createQueryPlan( resultSetMapping )
|
||||
);
|
||||
}
|
||||
else {
|
||||
return createQueryPlan();
|
||||
return createQueryPlan( resultSetMapping );
|
||||
}
|
||||
}
|
||||
|
||||
private NativeSelectQueryPlan<R> createQueryPlan() {
|
||||
final RowTransformer rowTransformer = resolveRowTransformer();
|
||||
private NativeSelectQueryPlan<R> createQueryPlan(JdbcValuesMappingProducer jdbcValuesMappingProducer) {
|
||||
final RowTransformer<?> rowTransformer = null;
|
||||
|
||||
return getSessionFactory().getQueryEngine().getNativeQueryInterpreter().createQueryPlan(
|
||||
generateSelectQueryDefinition(),
|
||||
getSessionFactory()
|
||||
);
|
||||
}
|
||||
final NativeSelectQueryDefinition queryDefinition = new NativeSelectQueryDefinition() {
|
||||
@Override
|
||||
public String getSqlString() {
|
||||
return NativeQueryImpl.this.getQueryString();
|
||||
}
|
||||
|
||||
private JdbcValuesMappingProducer getJdbcValuesMappingProducer() {
|
||||
// todo (6.0) - need to resolve SqlSelections as well as resolving ResultBuilders and FetchBuilders into QueryResult trees
|
||||
// also need to account for the edge case where the user passed just the
|
||||
// query string and no mappings (see ResultSetMappingUndefinedImpl)
|
||||
throw new NotYetImplementedFor6Exception( );
|
||||
}
|
||||
@Override
|
||||
public boolean isCallable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private RowTransformer resolveRowTransformer() {
|
||||
// todo (6.0) - need to resolve the RowTransformer to use, if one.
|
||||
// todo (6.0) - what about ResultListTransformer?
|
||||
throw new NotYetImplementedFor6Exception( );
|
||||
@Override
|
||||
public List<QueryParameterImplementor<?>> getQueryParameterList() {
|
||||
return NativeQueryImpl.this.occurrenceOrderedParamList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcValuesMappingProducer getJdbcValuesMappingProducer() {
|
||||
return jdbcValuesMappingProducer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowTransformer getRowTransformer() {
|
||||
return rowTransformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAffectedTableNames() {
|
||||
return querySpaces;
|
||||
}
|
||||
};
|
||||
|
||||
return getSessionFactory().getQueryEngine()
|
||||
.getNativeQueryInterpreter()
|
||||
.createQueryPlan( queryDefinition, getSessionFactory() );
|
||||
}
|
||||
|
||||
private SelectInterpretationsKey generateSelectInterpretationsKey(JdbcValuesMappingProducer resultSetMapping) {
|
||||
|
@ -398,57 +411,6 @@ public class NativeQueryImpl<R>
|
|||
return limit.getFirstRow() != null || limit.getMaxRows() != null;
|
||||
}
|
||||
|
||||
private NativeSelectQueryDefinition<R> generateSelectQueryDefinition() {
|
||||
return new NativeSelectQueryDefinition() {
|
||||
@Override
|
||||
public String getSqlString() {
|
||||
return NativeQueryImpl.this.getQueryString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCallable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<QueryParameterImplementor<?>> getQueryParameterList() {
|
||||
return NativeQueryImpl.this.occurrenceOrderedParamList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcValuesMappingProducer getJdbcValuesMappingProducer() {
|
||||
return NativeQueryImpl.this.getJdbcValuesMappingProducer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowTransformer getRowTransformer() {
|
||||
return NativeQueryImpl.this.resolveRowTransformer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAffectedTableNames() {
|
||||
return querySpaces;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void prepareQueryReturnsIfNecessary() {
|
||||
if ( queryReturnBuilders != null ) {
|
||||
if ( !queryReturnBuilders.isEmpty() ) {
|
||||
if ( queryReturns != null ) {
|
||||
queryReturns.clear();
|
||||
queryReturns = null;
|
||||
}
|
||||
queryReturns = new ArrayList<>();
|
||||
for ( NativeQueryReturnBuilder builder : queryReturnBuilders ) {
|
||||
queryReturns.add( builder.buildReturn() );
|
||||
}
|
||||
queryReturnBuilders.clear();
|
||||
}
|
||||
queryReturnBuilders = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScrollableResultsImplementor doScroll(ScrollMode scrollMode) {
|
||||
return resolveSelectQueryPlan().performScroll( scrollMode, this );
|
||||
|
@ -456,27 +418,6 @@ public class NativeQueryImpl<R>
|
|||
|
||||
@Override
|
||||
protected void beforeQuery(boolean txnRequired) {
|
||||
prepareQueryReturnsIfNecessary();
|
||||
boolean noReturns = queryReturns == null || queryReturns.isEmpty();
|
||||
if ( noReturns ) {
|
||||
this.autoDiscoverTypes = true;
|
||||
}
|
||||
else {
|
||||
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
|
||||
if ( queryReturn instanceof NativeSQLQueryScalarReturn ) {
|
||||
NativeSQLQueryScalarReturn scalar = (NativeSQLQueryScalarReturn) queryReturn;
|
||||
if ( scalar.getType() == null ) {
|
||||
autoDiscoverTypes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( NativeSQLQueryConstructorReturn.class.isInstance( queryReturn ) ) {
|
||||
autoDiscoverTypes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.beforeQuery( txnRequired );
|
||||
|
||||
if ( getSynchronizedQuerySpaces() != null && !getSynchronizedQuerySpaces().isEmpty() ) {
|
||||
|
@ -496,7 +437,7 @@ public class NativeQueryImpl<R>
|
|||
}
|
||||
|
||||
protected int doExecuteUpdate() {
|
||||
return resolveNonSelectQueryPlan().executeUpdate( this );
|
||||
return resolveNonSelectQueryPlan().executeUpdate( this );
|
||||
}
|
||||
|
||||
private NonSelectQueryPlan resolveNonSelectQueryPlan() {
|
||||
|
@ -537,36 +478,24 @@ public class NativeQueryImpl<R>
|
|||
return addScalar( columnAlias, null );
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public NativeQueryImplementor<R> addScalar(String columnAlias, BasicDomainType type) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public NativeQueryImplementor<R> addScalar(String columnAlias, BasicDomainType type) {
|
||||
addReturnBuilder(
|
||||
() -> new NativeSQLQueryScalarReturn( columnAlias, type )
|
||||
);
|
||||
resultSetMapping.addResultBuilder( Builders.scalar( columnAlias, (BasicType<?>) type ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void addReturnBuilder(NativeQueryReturnBuilder builder) {
|
||||
if ( queryReturnBuilders == null ) {
|
||||
queryReturnBuilders = new ArrayList<>();
|
||||
}
|
||||
|
||||
queryReturnBuilders.add( builder );
|
||||
@Override
|
||||
public EntityResultBuilder addRoot(String tableAlias, String entityName) {
|
||||
final EntityResultBuilder resultBuilder = Builders.entity(
|
||||
tableAlias,
|
||||
entityName
|
||||
);
|
||||
resultSetMapping.addResultBuilder( resultBuilder );
|
||||
return resultBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RootReturn addRoot(String tableAlias, String entityName) {
|
||||
NativeQueryReturnBuilderRootImpl builder = new NativeQueryReturnBuilderRootImpl( tableAlias, entityName );
|
||||
addReturnBuilder( builder );
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RootReturn addRoot(String tableAlias, Class entityType) {
|
||||
public EntityResultBuilder addRoot(String tableAlias, Class entityType) {
|
||||
return addRoot( tableAlias, entityType.getName() );
|
||||
}
|
||||
|
||||
|
@ -604,9 +533,9 @@ public class NativeQueryImpl<R>
|
|||
|
||||
@Override
|
||||
public FetchReturn addFetch(String tableAlias, String ownerTableAlias, String joinPropertyName) {
|
||||
NativeQueryReturnBuilderFetchImpl builder = new NativeQueryReturnBuilderFetchImpl( tableAlias, ownerTableAlias, joinPropertyName );
|
||||
addReturnBuilder( builder );
|
||||
return builder;
|
||||
final LegacyFetchBuilder fetchBuilder = Builders.fetch( tableAlias, ownerTableAlias, joinPropertyName );
|
||||
resultSetMapping.addLegacyFetchBuilder( fetchBuilder );
|
||||
return fetchBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query.sql.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -14,7 +15,13 @@ import org.hibernate.ScrollMode;
|
|||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
import org.hibernate.query.sql.spi.NativeSelectQueryPlan;
|
||||
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
|
||||
import org.hibernate.sql.results.spi.RowTransformer;
|
||||
|
||||
|
@ -40,28 +47,53 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
this.affectedTableNames = affectedTableNames;
|
||||
this.parameterList = parameterList;
|
||||
this.resultSetMapping = resultSetMapping;
|
||||
this.rowTransformer = rowTransformer;
|
||||
this.rowTransformer = rowTransformer != null
|
||||
? rowTransformer
|
||||
: RowTransformerPassThruImpl.instance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<R> performList(ExecutionContext executionContext) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
final List<JdbcParameterBinder> jdbcParameterBinders = resolveJdbcParamBinders( executionContext );
|
||||
final JdbcParameterBindings jdbcParameterBindings = resolveJdbcParamBindings( executionContext, jdbcParameterBinders );
|
||||
|
||||
// final List<JdbcParameterBinder> jdbcParameterBinders = resolveJdbcParameterBinders( executionContext );
|
||||
//
|
||||
// final JdbcSelect jdbcSelect = new JdbcSelectImpl(
|
||||
// sql,
|
||||
// jdbcParameterBinders,
|
||||
// resultSetMapping,
|
||||
// affectedTableNames
|
||||
// );
|
||||
//
|
||||
// // todo (6.0) : need to make this swappable (see note in executor class)
|
||||
// final JdbcSelectExecutor executor = JdbcSelectExecutorStandardImpl.INSTANCE;
|
||||
//
|
||||
// return executor.list( jdbcSelect, JdbcParameterBindings.NO_BINDINGS, executionContext, rowTransformer );
|
||||
final JdbcSelect jdbcSelect = new JdbcSelect(
|
||||
sql,
|
||||
jdbcParameterBinders,
|
||||
resultSetMapping,
|
||||
affectedTableNames,
|
||||
Collections.emptySet()
|
||||
);
|
||||
|
||||
final JdbcSelectExecutor executor = JdbcSelectExecutorStandardImpl.INSTANCE;
|
||||
|
||||
return executor.list(
|
||||
jdbcSelect,
|
||||
jdbcParameterBindings,
|
||||
executionContext,
|
||||
rowTransformer,
|
||||
false
|
||||
);
|
||||
}
|
||||
//
|
||||
|
||||
private List<JdbcParameterBinder> resolveJdbcParamBinders(ExecutionContext executionContext) {
|
||||
if ( parameterList == null || parameterList.isEmpty() ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
private JdbcParameterBindings resolveJdbcParamBindings(
|
||||
ExecutionContext executionContext,
|
||||
List<JdbcParameterBinder> jdbcParameterBinders) {
|
||||
if ( jdbcParameterBinders.isEmpty() ) {
|
||||
return JdbcParameterBindings.NO_BINDINGS;
|
||||
}
|
||||
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
// private List<JdbcParameterBinder> resolveJdbcParameterBinders(ExecutionContext executionContext) {
|
||||
// final List<JdbcParameterBinder> jdbcParameterBinders = CollectionHelper.arrayList( parameterList.size() );
|
||||
//
|
||||
|
@ -98,27 +130,25 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
|
||||
@Override
|
||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, ExecutionContext executionContext) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
//
|
||||
// // todo (6.0) : see notes above in `#performList`
|
||||
//
|
||||
// final List<JdbcParameterBinder> jdbcParameterBinders = resolveJdbcParameterBinders( executionContext );
|
||||
//
|
||||
// final JdbcSelect jdbcSelect = new JdbcSelectImpl(
|
||||
// sql,
|
||||
// jdbcParameterBinders,
|
||||
// resultSetMapping,
|
||||
// affectedTableNames
|
||||
// );
|
||||
// final JdbcSelectExecutor executor = JdbcSelectExecutorStandardImpl.INSTANCE;
|
||||
//
|
||||
// return executor.scroll(
|
||||
// jdbcSelect,
|
||||
// scrollMode,
|
||||
// // the binders created here encapsulate their bind value
|
||||
// JdbcParameterBindings.NO_BINDINGS,
|
||||
// executionContext,
|
||||
// rowTransformer
|
||||
// );
|
||||
final List<JdbcParameterBinder> jdbcParameterBinders = resolveJdbcParamBinders( executionContext );
|
||||
final JdbcParameterBindings jdbcParameterBindings = resolveJdbcParamBindings( executionContext, jdbcParameterBinders );
|
||||
|
||||
final JdbcSelect jdbcSelect = new JdbcSelect(
|
||||
sql,
|
||||
jdbcParameterBinders,
|
||||
resultSetMapping,
|
||||
affectedTableNames,
|
||||
Collections.emptySet()
|
||||
);
|
||||
|
||||
final JdbcSelectExecutor executor = JdbcSelectExecutorStandardImpl.INSTANCE;
|
||||
|
||||
return executor.scroll(
|
||||
jdbcSelect,
|
||||
scrollMode,
|
||||
jdbcParameterBindings,
|
||||
executionContext,
|
||||
rowTransformer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.hibernate.query.QueryParameter;
|
|||
import org.hibernate.query.ResultListTransformer;
|
||||
import org.hibernate.query.TupleTransformer;
|
||||
import org.hibernate.query.named.NameableQuery;
|
||||
import org.hibernate.query.results.EntityResultBuilder;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
|
||||
/**
|
||||
|
@ -55,7 +56,7 @@ public interface NativeQueryImplementor<R> extends QueryImplementor<R>, NativeQu
|
|||
NativeQueryImplementor<R> addScalar(String columnAlias, BasicDomainType type);
|
||||
|
||||
@Override
|
||||
RootReturn addRoot(String tableAlias, String entityName);
|
||||
EntityResultBuilder addRoot(String tableAlias, String entityName);
|
||||
|
||||
@Override
|
||||
NativeQueryImplementor<R> addEntity(String entityName);
|
||||
|
|
|
@ -707,7 +707,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
// add any additional join restrictions
|
||||
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||
if ( sqmJoin.isFetched() ) {
|
||||
QueryLogger.QUERY_LOGGER.debugf( "Join fetch [" + sqmJoin.getNavigablePath() + "] is restricted" );
|
||||
QueryLogger.QUERY_MESSAGE_LOGGER.debugf( "Join fetch [" + sqmJoin.getNavigablePath() + "] is restricted" );
|
||||
}
|
||||
|
||||
if ( joinedTableGroupJoin == null ) {
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.sql.results.jdbc.spi;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.ResultSetMapping;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
|
||||
/**
|
||||
* Producer for JdbcValuesMapping references.
|
||||
|
@ -20,13 +21,12 @@ import org.hibernate.query.spi.ResultSetMapping;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface JdbcValuesMappingProducer {
|
||||
|
||||
/**
|
||||
* Resolve the selections (both at the JDBC and object level) for this
|
||||
* mapping. Acts as delayed access to this resolution process to support
|
||||
* "auto discovery" as needed for "undefined scalar" results as defined by
|
||||
* native-sql and procedure call queries.
|
||||
* Resolve the JdbcValuesMapping. This involves resolving the
|
||||
* {@link org.hibernate.sql.results.graph.DomainResult} and
|
||||
* {@link org.hibernate.sql.results.graph.Fetch}
|
||||
*/
|
||||
JdbcValuesMapping resolve(JdbcValuesMetadata jdbcResultsMetadata, SessionFactoryImplementor sessionFactory);
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@ import javax.persistence.Id;
|
|||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.graph.GraphParser;
|
||||
import org.hibernate.graph.GraphSemantic;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -81,6 +83,7 @@ public class EntityGraphNativeQueryTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( reason = "Uses an implicit entity/root return, which is not yet implemented" )
|
||||
void testNativeQueryLoadGraph(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -98,14 +101,21 @@ public class EntityGraphNativeQueryTest {
|
|||
.setHint( GraphSemantic.LOAD.getJpaHintName(), fooGraph )
|
||||
.getSingleResult();
|
||||
fail("Should throw exception");
|
||||
} catch (Exception e) {
|
||||
assertThat( e.getMessage(), is( "A native SQL query cannot use EntityGraphs" ) );
|
||||
}
|
||||
catch (Exception e) {
|
||||
if ( e.getMessage().equals( "A native SQL query cannot use EntityGraphs" ) ) {
|
||||
// success
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException( "Unexpected exception", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( reason = "Uses an implicit entity/root return, which is not yet implemented" )
|
||||
void testNativeQueryFetchGraph(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -123,8 +133,14 @@ public class EntityGraphNativeQueryTest {
|
|||
.setHint( GraphSemantic.FETCH.getJpaHintName(), fooGraph )
|
||||
.getSingleResult();
|
||||
fail( "Should throw exception" );
|
||||
} catch (Exception e) {
|
||||
assertThat( e.getMessage(), is( "A native SQL query cannot use EntityGraphs" ) );
|
||||
}
|
||||
catch (Exception e) {
|
||||
if ( e.getMessage().equals( "A native SQL query cannot use EntityGraphs" ) ) {
|
||||
// success
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException( "Unexpected exception", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -8,6 +8,8 @@ package org.hibernate.orm.test.query.named.resultmapping;
|
|||
|
||||
import org.hibernate.query.named.NamedQueryRepository;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
import org.hibernate.query.results.ResultSetMappingImpl;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
@ -16,7 +18,7 @@ import org.hibernate.testing.orm.junit.SessionFactory;
|
|||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
|
@ -31,8 +33,10 @@ public class SimpleNamedMappingTests {
|
|||
final QueryEngine queryEngine = sessionFactoryScope.getSessionFactory().getQueryEngine();
|
||||
final NamedQueryRepository namedQueryRepository = queryEngine.getNamedQueryRepository();
|
||||
final NamedResultSetMappingMemento mappingMemento = namedQueryRepository.getResultSetMappingMemento( "name" );
|
||||
assertThat( mappingMemento.toResultSetMapping(), notNullValue() );
|
||||
}
|
||||
|
||||
// todo (6.0) : atm that ^^ is as far as we can test until we implement native-query support to test applying a mapping
|
||||
final ResultSetMapping mapping = new ResultSetMappingImpl();
|
||||
mappingMemento.resolve( mapping, querySpace -> {}, sessionFactoryScope.getSessionFactory() );
|
||||
|
||||
assertThat( mapping.getNumberOfResultBuilders(), is( 1 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.query.sql;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
import org.hibernate.query.sql.spi.NativeQueryImplementor;
|
||||
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.contacts.Contact;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(
|
||||
standardModels = StandardDomainModel.CONTACTS
|
||||
)
|
||||
@SessionFactory
|
||||
public class NativeQueryScalarTests {
|
||||
@Test
|
||||
public void fullyImplicitTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final String sql = "select gender, first, last, id from contacts";
|
||||
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||
|
||||
final List<?> results = query.list();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
final Object result = results.get( 0 );
|
||||
assertThat( result, instanceOf( Object[].class ) );
|
||||
|
||||
final Object[] values = (Object[]) result;
|
||||
assertThat( values.length, is(4 ) );
|
||||
|
||||
assertThat( ( (Number) values[0] ).intValue(), is( Contact.Gender.OTHER.ordinal() ) );
|
||||
assertThat( values[1], is( "My First" ) );
|
||||
assertThat( values[2], is( "Contact" ) );
|
||||
assertThat( values[3], is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
@Test
|
||||
public void explicitOrderTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final String sql = "select gender, first, last, id from contacts";
|
||||
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||
// notice the reverse order from the select clause
|
||||
query.addScalar( "id" );
|
||||
query.addScalar( "last" );
|
||||
query.addScalar( "first" );
|
||||
query.addScalar( "gender" );
|
||||
|
||||
final List<?> results = query.list();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
final Object result = results.get( 0 );
|
||||
assertThat( result, instanceOf( Object[].class ) );
|
||||
|
||||
final Object[] values = (Object[]) result;
|
||||
assertThat( values.length, is(4 ) );
|
||||
|
||||
assertThat( values[0], is( 1 ) );
|
||||
assertThat( values[1], is( "Contact" ) );
|
||||
assertThat( values[2], is( "My First" ) );
|
||||
assertThat( ( (Number) values[3] ).intValue(), is( Contact.Gender.OTHER.ordinal() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( reason = "Explicit type support not working atm" )
|
||||
public void explicitEnumTypeTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final String sql = "select gender, first, last, id from contacts";
|
||||
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||
// notice the reverse order from the select clause
|
||||
query.addScalar( "id" );
|
||||
query.addScalar( "last" );
|
||||
query.addScalar( "first" );
|
||||
query.addScalar( "gender", scope.getSessionFactory().getTypeConfiguration().getBasicTypeForJavaType( Contact.Gender.class ) );
|
||||
|
||||
final List<?> results = query.list();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
final Object result = results.get( 0 );
|
||||
assertThat( result, instanceOf( Object[].class ) );
|
||||
|
||||
final Object[] values = (Object[]) result;
|
||||
assertThat( values.length, is(4 ) );
|
||||
|
||||
assertThat( values[0], is( 1 ) );
|
||||
assertThat( values[1], is( "Contact" ) );
|
||||
assertThat( values[2], is( "My First" ) );
|
||||
assertThat( values[3], is( Contact.Gender.OTHER ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.persist(
|
||||
new Contact(
|
||||
1,
|
||||
new Contact.Name( "My First", "Contact"),
|
||||
Contact.Gender.OTHER,
|
||||
LocalDate.EPOCH
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanUpData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> session.createQuery( "delete Contact" ).executeUpdate()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests for {@link org.hibernate.query.NativeQuery}
|
||||
*/
|
||||
package org.hibernate.orm.test.query.sql;
|
|
@ -10,13 +10,17 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.ColumnResult;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.SqlResultSetMapping;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.query.NativeQuery;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
@ -117,8 +121,43 @@ public class SetElementNullBasicTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// @SqlResultSetMapping(
|
||||
// columns = {
|
||||
// @ColumnResult( name = "a_id", type = long.class ),
|
||||
// @ColumnResult( name = "a_name" )
|
||||
// }
|
||||
// )
|
||||
private List<?> getCollectionElementRows(int id) {
|
||||
doInHibernate(
|
||||
this::sessionFactory,
|
||||
session -> {
|
||||
final String qry = "SELECT a.id as a_id, a.name as a_name FROM AnEntity a where a.id = " + id;
|
||||
final NativeQuery nativeQuery = session.createNativeQuery( qry );
|
||||
nativeQuery.list();
|
||||
|
||||
|
||||
|
||||
nativeQuery.addRoot( "a", AnEntity.class )
|
||||
.addIdColumnAliases( "a_id" )
|
||||
.addProperty( "name", "a_name" );
|
||||
nativeQuery.addFetch( "c", "a", "aCollection" );
|
||||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory,
|
||||
session -> {
|
||||
final String qry = "SELECT a.id as a_id, a.name as a_name, c.aCollection FROM AnEntity a join AnEntity_aCollection c on a.id = c.id and a.id = " + id;
|
||||
final NativeQuery nativeQuery = session.createNativeQuery( qry );
|
||||
nativeQuery.addRoot( "a", AnEntity.class )
|
||||
.addIdColumnAliases( "a_id" )
|
||||
.addProperty( "name", "a_name" );
|
||||
nativeQuery.addFetch( "c", "a", "aCollection" );
|
||||
nativeQuery.list();
|
||||
}
|
||||
);
|
||||
|
||||
return doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
return session.createNativeQuery(
|
||||
|
|
|
@ -16,6 +16,7 @@ import javax.persistence.Entity;
|
|||
import javax.persistence.Id;
|
||||
import javax.persistence.OrderColumn;
|
||||
import javax.persistence.SecondaryTable;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
|
@ -23,6 +24,7 @@ import javax.persistence.TemporalType;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity
|
||||
@Table( name = "contacts" )
|
||||
@SecondaryTable( name="contact_supp" )
|
||||
public class Contact {
|
||||
private Integer id;
|
||||
|
|
|
@ -41,6 +41,15 @@ public class SimpleEntity {
|
|||
this.someString = someString;
|
||||
}
|
||||
|
||||
public SimpleEntity(
|
||||
Integer id,
|
||||
String someString,
|
||||
Long someLong) {
|
||||
this.id = id;
|
||||
this.someString = someString;
|
||||
this.someLong = someLong;
|
||||
}
|
||||
|
||||
public SimpleEntity(
|
||||
Integer id,
|
||||
Date someDate,
|
||||
|
|
Loading…
Reference in New Issue